Hacker News new | past | comments | ask | show | jobs | submit login
MVVM is Exceptionally OK (ashfurrow.com)
47 points by marvel_boy on Dec 21, 2015 | hide | past | favorite | 49 comments

Something bothers me about all this MV* pattern stuff. It's the notion that there is this canonical great pattern applications should follow. There's also a lot of "we" involved in this, and social posturing of "best practices". Look if MVWhatever works for your particular problem, knock yourself out, but I've seen so many badly designed applications because they tried to hammer something into an MVC framework without considering if any of that actually made sense for what their application does. And if you suggest that all this scaffolding is just hiding a more elegant design, you're going against "best practices" (despite the fact that most of these "best practices" arise from opinionated bloggers.)

I feel like MVVM is generally solving the wrong problem though. Ok, so MVC tends to get nasty because people shove all the logic into the controller, the model ends up being a crappy interface to the database, and views do too much. But maybe that just means that MVC is a bad fit for what you're doing. It doesn't mean "we" need the "next" MVC, it means you have to do the hard work of actually designing what your application does without training wheels.

It's all about managing state and dependencies. Doesn't matter much for small apps but does when you have tons of people trying to work on the same thing.

Also helps in large organizations that develop lots of apps because it reduces the learning curve for new team members.

Besides, it's not like MVVM is a huge thing. It can be explained in a paragraph.

> It's all about managing state and dependencies. Doesn't matter much for small apps but does when you have tons of people trying to work on the same thing.

That literally applies to any program though. A compiler has to manage a lot of state too, but I've yet to hear compiler makers trying to figure out why they have so much logic in their controllers, and why their views are too big (because nobody would write an MVC compiler).

> Besides, it's not like MVVM is a huge thing. It can be explained in a paragraph

And yet there's like 500 blog posts about why you're doing it wrong, and how to do it better, etc. Of course, in truth it's not complicated, what makes it complicated is when it's applied in contexts that make little sense.

> A compiler has to manage a lot of state too, but I've yet to hear compiler makers trying to figure out why they have so much logic in their controllers, and why their views are too big (because nobody would write an MVC compiler).

No, but they do write entire books about how their parser uses recursive descent or LL(1) or about how they do code generation.

>because nobody would write an MVC compiler

Model - Input -> output format transformation

View - input/output

Controller - Drives the model

And not much coupling between them except to pass data back and forth.

Sounds like a regular compiler to me.

You can make pretty much anything seem equivalent if you abstract it enough. You've basically just equated MVC with any program that does IO. I can't see how that's a useful thing to do.

Just looking at what you said though: why would you represent a transformation (something inherently a verb/action) as a model? "Model - Input -> output format transformation". It operates on models, it's not A model.

Also, claiming the view as input/output is pretty reductive. How do I represent a lexer as a view? More importantly, why would I want to?

Fun experiment, find the views and controllers in here: https://github.com/llvm-mirror/clang

>You can make pretty much anything seem equivalent if you abstract it enough. You've basically just equated MVC with any program that does IO. I can't see how that's a useful thing to do.

shrug MVC / MVVM is that simple.

>why would you represent a transformation (something inherently a verb/action) as a model? "Model - Input -> output format transformation". It operates on models, it's not A model.

Models are not limited to being data stores. Models are responsible for doing work, so-called business logic. Controllers / ViewModels work with Views to take in user input and apply it to the models, then take the updated model and give it back to the user.

>How do I represent a lexer as a view?

The lexer is part of the model.

The view would be what the compiler uses for input/output: for a CLI compiler it would be the function that reads stdin or the filesystem + the function that writes to stdout and the filesystem, for a compiler hosted in an IDE or webpage would be the compiler library interface (ie: a programmatic way to give it files or strings and receive output + errors), and so on. Separate views that only know how to take in user input and display user output, interfacing with a common controller/viewmodel + model.

Edit: Minor clarifications.

To clarify, an example of a non-MVC compiler would be something that expects to read a list of files from argv and expects to write to stdout.

An example of a MVC compiler would be something that abstracts the act of compiling bytes into bytes from how it obtains those bytes or puts them out.

I think gcc works like the former and clang like the latter? I'm not familiar with either.

An example I am familiar with is the TypeScript transpiler - a "Compiler" class with a pluggable "Host" interface. There is one implementation of that host for each environment it can run in (in-memory, node.js, cscript.exe) that knows how to read files and write output. The compiler class would call host.writeFile(filename, contents) and it's up to the host whether to write that to a file, or a textarea in a web page, or pipe the string to another transpiler, or whatever. It's up to the view to decide whether to colorize output or not, whether to show an underline that the user can click to jump to the error or not, etc.

Basically the view is independent of the model, and provides functionality local only to its interaction context that the model shouldn't need to care about. As a bonus it's pluggable and thus easy to write new views.

If your model fits everything, it fits nothing. If you've stretched until compilers are "MVC", you haven't got MVC anymore. Something has to be meaningfully a good design that is not MVC for MVC to exist as a distinct solution.

MVC is not simply "things should be abstracted from each other". That just, well, abstraction. (Or, better, indirected: http://zedshaw.com/archive/indirection-is-not-abstraction/ )

I've been anti-MVC (unless you are in the rare situations where it really works) for a while, and this is precisely why. It clouds people's thought. It convinces people they're doing "design" when they are often just complexifying things by rote application of badly misunderstood ideas.

Separation of concerns is neither complexity or misunderstood. It's just good design.

MVC !=== separation of concerns. Separation of concerns is something else. If "MVC is just exactly the same as separation of concerns", then, again, we don't need "MVC" as a concept. We already have "separation of concerns".

Again, this is why I find the term loathsome as it is actually used. Not only do people not think about it, they, like, actively won't think about it. Anyone who actually tries to nail down "what exactly is MVC" will find themselves coming up empty. It is an undefined term, and should be discarded for pretty much everybody who isn't writing a CAD/CAM app, not used as some sort of vague template for "all good design".

You've progressively shrunk the goalposts in every post in this series until you can't help but hit MVC. That's not useful.

>If "MVC is just exactly the same as separation of concerns", then, again, we don't need "MVC" as a concept. We already have "separation of concerns".

MVC is an example of separation of concerns, specifically applied to separating the computation of data from the input and output of that data. I don't see how this is such a difficult thing to understand.

(Edit: Heck, even Wikipedia calls it "a software architectural pattern mostly for implementing user interfaces (but not only for user interfaces). It divides a given software application into three interconnected parts, so as to separate internal representations of information from the ways that information is presented to or accepted from the user." Emphasis mine.)

>Again, this is why I find the term loathsome as it is actually used.

From this and sibling post I seem to detect some hostility against the term due to there being articles about "you're doing MVC wrong." You can find those a dime a dozen on any topic. Don't misdirect your anger.

>Anyone who actually tries to nail down "what exactly is MVC" will find themselves coming up empty.

See above, as well as my previous posts in this thread.

>You've progressively shrunk the goalposts in every post in this series until you can't help but hit MVC. That's not useful.

On the contrary, I've been consistent from the very first post what MVC is and how it applies to software. You're the one here insisting that it's something magic that needs to be different from what I've been saying it is.

To your example, I work on a CAD app that runs on web and even we don't use MVC. :-) (Similar concepts, sure, but no buzzwords or worry about being MVVM or whatever)

MVC itself isn't a tool of craft; it's an ontology for talking about code. That is, there's no system that is or is not MVC; MVC is a guide for mentally modelling a system. It's a way to distinguish parts of a continuous whole by drawing imaginary lines, like between having a "brain" vs. a "mind", or between having a "state" vs. a "government", or between various species of plant or animal. They're tools to use to cluster the various actions of messy systems into well-known, recognizable clumps, and assign labels to those clumps, so that when you talk about your system's "controller" and your friend talks about their system's "controller", you both can understand each-other.

Ontological modelling is the pure kind of abstraction—not the kind you reify by implementing it. There's no "MVC design pattern"; all systems can be broken down into MVC. You're never not implementing the "MVC design pattern."

The reason people get confused is that there are design patterns that people implement which make an explicit distinction that looks like MVC. This has nothing to do with MVC; you haven't "implemented MVC" by creating a system where all your model classes are Model classes, and all your views are Views. You've maybe made it easier to reason about your system in MVC terms, but that doesn't get you anything unless "reasoning about your system in MVC terms" is something you need to do a lot, because e.g. you and your coworkers split your responsibilities that way.

Now, what you may have done instead, when you think you've "implemented MVC", is implemented something like Hexagonal Architecture[1]: an actual design pattern—an idea that some-but-not-all codebases are an instance of—involving effectively inverting your "app" into an "engine" of business logic that relies on dependency-injection of engine-specified "pluggable" interfaces for its IO (both the out-to-the-world kind, and the in-to-its-databases and third-party-services kind.)

If your MVC app's "core" business-logic part is a library with direct unit tests on it and so forth, and this part is useless on its own; and if you've got another part that treats the core as a dependency, and turns it into a web service or whatever else—then you've got Hexagonal Architecture. You've also, coincidentally, got some quite-elegantly-delineated MVC boundaries: your model and your view can't share logic, since there's a component boundary between them and neither one can assume anything about the other. But that's just an analytic property of the code; you didn't "do MVC" or even "do MVC right." You just did Hexagonal Architecture, which happens to make it easy to reason about your codebase in MVC terms.

[1] http://fideloper.com/hexagonal-architecture

I think MVVM mainly makes two things easier: refactoring models and testing the user interface. It's not going to be a good fit in places where MVC wasn't already a good fit.

I find MVVM very confused.

In MVVM you have the Model and View layers, which I get, and also the View Model layer, which I don't. The View Model is supposed to be UI independent, and that I don't get. The Model layer is already UI independent. There is no need for a second UI independent layer. In practice the View Model layer is written specifically to support the UI, so there is no point in making it UI independent. Some argue this is for testability. But you can already test the Model layer without the UI. Additional testing should include the UI, and should be through the UI.

The motivation behind MVVM appears to be to update the UI automatically when data changes. Modern frameworks are moving away from two-way data binding (React, Angular 2.0, Ember, etc.)

Also, data binding is best done in code (the jQuery way) as opposed to declaratively (the WPF way).

From a XAML perspective:

The ViewModel just adapts various Models/Services for a particular View. It converts types provided by the Model as needed, formats strings, computes progress, etc.

"UI independent" just means that it should be a logical model of the View, rather than a visual model (e.g., don't expose Color or Brush properties, instead expose properties like IsSelected). So think of the View model like logical code-behind.

> Modern frameworks are moving away from two-way data binding (React, Angular 2.0, Ember, etc.)

On the web, maybe. But Windows apps (UWP) are still based on data binding.

> But Windows apps (UWP) are still based on data binding.

Yes, I understand that Windows APIs still use two-way data binding. But by and large the developer community is realizing that two-way data binding is gimmicky and that in large applications two-way data binding is a liability. On the Web most JavaScript frameworks are moving away from two-way data binding (React, Angular 2, Ember, etc.) The reason for that has nothing to do with the Web or with JavaScript. The underlying reason is applicable to application development in general, regardless of platform.

Here's Tom Dale and Yehuda Katz, developers of Ember, explaining their decision to move away from two-way data binding: https://changelog.com/131/ (skip to 0:42)


"Why do people still prefer to write server-rendered apps? The programming model is just so easy. If you think about how people build sever-rendered apps.. the request comes in, you get your model data out of the database, you hand it to your view layer to render, you return that output and that's it. Every time you handle a new request, because HTTP is stateless, you start from scratch.

"Conversely, things like Angular and Ember have two-way data bindings, right? And it really easy to end up in -- especially in a large or sophisticated application which is stateful. As the user is looking at it, it's not like the state is getting reset, you are constantly having to keep everything in sync yourself. It is easy to end up in a state where you can't yourself explain how data flows through it.

"The brilliance in react is bringing back a programming model that is as simple as server-rendered apps.

"Even though both Angular and Ember have the notion of events and data bindings, data bindings feels so cool that people started tunneling events through data bindings.

"Honestly when I look at the critiques React people have about Ember and trying to understand, OK, you were an ember developer, you were reasonably productive, but you find yourself way more productive in React. What is happening? What we are finding -- and this played into the Ember 2.0 plan -- is that people are abusing two way data bindings to express something that is fundamentally an event. A big focus of Ember 2.0 is moving away from two way data bindings as the primary method of communication to events. We added too much sugar around two-way data bindings and that led people to use two-way data bindings as an event bus.

> don't expose Color or Brush properties

Why not? The ViewModel is written specifically for the View, and it does not serve any purpose to make it UI independent. By avoiding Color etc. in this layer you end with two UI independent layers (Model and ViewModel) and that makes no sense. One UI-independent layer is enough.

In MVVM the View knows about the ViewModel but supposedly the ViewModel does not know about the View. But in reality the ViewModel is written specifically for the View, so it might as well know the View.

UI frameworks usually have DSL's that are much better at dealing with visual state (e.g., XAML, CSS) and provide mechanisms for sharing styles and resources between multiple views. And do things like swap colors out automatically based on system accessibility settings. Or adjust font sizes for localization.

I've only ever done MVVM development with WPF/XAML and it makes a whole lot of sense for me. Viewing it as a logical code-behind is exactly the right way to see view models in my experience. I've not done iOS development, and the term View Controller in the article was very confusing.

Other than XAML being somewhat confusing and having relatively poor IDE support, I've found the WPF MVVM model to be the most intuitive and nice UI design pattern that I've used.

I wrote a (very) large SPA in Knockout, which is nominally a MVVM framework, and I definitely see your points.

In Knockout, you have HTML templates, which are the view, but the distinction between the Models, the View Models, and every other bit of code in your application is pretty much lost. Not sure if it was my lack of knowledge of MVVM best practices (likely), Knockout (possible), or something inherent to MVVM, but if ever there was an architecture that lent itself to turning into Big Balls Of Mud...

Edit: Digging into the links, it seems the article is talking specifically about native mobile applications, so maybe there's context I'm missing.

>>Modern frameworks are moving away from two-way data binding (React, Angular 2.0, Ember, etc.)

Do you have any reference about this? I thought the opposite was true. My main interest being Ember, I'd like to know more about what you said.

Here it is: Creators of Ember talking about moving away from two-way data binding: https://changelog.com/131/ (skip to 0:43)

Take this as a grain of salt, but my experience with React so far as been one where it's easiest to set up your UI as one-way "data pipelines".

> The motivation behind MVVM appears to be to update the UI automatically when data changes. Modern frameworks are moving away from two-way data binding (React, Angular 2.0, Ember, etc.)

Angular still has ngModel according to its docs. Whether you have two-way binding or not, View Models are still useful. Cycle.js doesn't have two-way binding but uses Event Streams and has a pattern that is similar to MVVM (they call it Model-View-Intent but the Model is a View Model by normal definition).

React not having something like MVVM makes it difficult to create reusable components. Most React apps are divided into the view layer (which are "components" but really just dumb views) and application logic which lives in the flux layer. This division means you can't / shouldn't write components that fetch their own data.

Shouldn't, not can't. You still can have components keep their own state, and that may be the right decision for small/localized/ephemeral state, such as what's selected in a dropbox, or the coordinates of a widget that's being dragged around. But it's more common to have views trigger events/send actions, which then update the top-level state and trigger a re-render.

I get the impression that MVVM only really works well when you have robust data-binding support baked into the framework (e.g. WPF/XAML). Otherwise you end up with a bit of an impedance mismatch and a lot of overhead in keeping the views synced with the view model.

For example under iOS this probably means going all-in with ReactiveCocoa. But I'm not convinced that completely switching paradigms like that is the right way to go.

> Since view controllers do everything in MVC apps

Not even close. The model does everything in MVC apps. Views display the model and react to model changes. Controllers pick up the slack, which shouldn't be very much.

Now in Model Widget Controller[1] the "view controllers" (something that doesn't even exist in actual MVC) have to do more work because the widgets are generic. Still, if you find your "view controller" doing "everything", you've pretty much missed the point of MVC. Completely.

[1] http://blog.metaobject.com/2015/04/model-widget-controller-m...

Couldn't agree more, if you regularly have 400 line classes you're doing it wrong.

Some of the specialised iOS/OS X view controllers - e.g. UIImagePickerController - probably have a lot more than 400 lines.

Other classes, like NSLayoutManager, look a lot like most of a view controller. But they're not officially a subclass of UIViewController, because they don't link directly to a view - even though they could have been designed to.

Apple makes a big deal of MVC, but I sometimes wonder if anyone knows what MVC really is - except possibly a design pattern for generating disagreements about MVC.

The authors point, is that most people in the native app world are doing it wrong. And in my experience, he's right.

I have written several large WPF applications that use the MVVM pattern and it has worked very nicely. So I have always been a little confused as to why web developers have struggled to write web apps using the same approach. The desktop apps I have worked on are easily bigger than any SPA I have ever seen. So I have not seen any issue with it working when scaling MVVM to large code bases.

Maybe there is something fundamentally different about web development and/or JavaScript that causes it to not work well?

For example, lets say you have a User model object. You want to display information about the user in three different places in the user interface. With MVVM this is simple. You have a single User model and three different VM instances that each point at the source model. Each VM has a matching View. Any change in the User model propagates down to the VM and then the View. If you edit the users name in the View it updates the VM and then the User model. Changes then cascade back down so the other two views update if needed. Very simple.

But how is this done in Flux/Redux? Does the store contain the user information just once? But then what about the intermediate information that is the equivalent of the three views? I presume you need to store this state information in some store as well. But then how do you handle updating the user and having the three other stores updated at the same time as needed? I am not a web developer so this might be trivially simple to those that know how it fits together.

In Redux, if you edit the user's name, that would dispatch/trigger an action {type: 'SET_USER_NAME', payload: 'New Name'}. The store would take the current state and the action and generate the new state. Then it would send it to React to cause a re-render of everything to the virtual DOM (not just everywhere the username was, but actually the entire view). And then it diffs the vDOM with the real DOM and updates the real DOM anywhere it's different.

Slightly pedantic point, but I was under the impression the diff didn't touch real DOM unless there was a change required, and just dirty checked the virtual DOM - ie. doing everything in memory without a bunch of DOM access was where the performance came from?

It's actually fairly similar in an idiomatic Redux app.

"Lets say you have a User. You want to display information about the user in three different places in the user interface. With Redux this is simple. You have a single User store and three different containers that each receive the source model as inputs, transform it using connect/reselect, and then passes it on, along with action creators to change the data, to the underlying components. Any change in the User model propagates down to through the containers to the components. If you edit the user from one component it updates the store and then the components. Changes then cascade back down so that all three containers update if needed. Very simple."

Sounds familiar, no? The big difference is that instead of editing the data you're passed directly, and having it magically update everywhere, you're passed an immutable User object and an updateUser() function, which you call to edit the object.

But the same distinction between your data, the view, and the intermediate layer that transforms the data for the view is very much present.

In WPF, you call OnPropertyChanged on the setter of a property, giving you two-way data binding. Great, now you can modify the model directly from the view. The problem is that modifying the models directly from the views makes it really difficult to reason about your dataflows. It's not unusual to have the same model bound to five or ten different views. Run your WPF application for a while, and- hang on- this view isn't showing the correct data. This kind of scenario is hellish to debug, because there's so many places that could have mutated the model.

In a large application using two-way binding, the application state is implicit in its execution. There's thousands of places that mutate the state, so many that if you tried to make a graph of the dataflows, you'd get spaghetti. Sure, the code is neat and simple, but you know you've got a problem when the dependency graph is so complex that you can write a cyclic binding and not even realise it.

Redux borrows a lot from functional techniques to tackle these kinds of problems. The big one is that you can't mutate the state, because it's immutable. Instead, you write reducing functions that take an application state and an action, and return a completely new application state based on that action (which might sound wasteful until you learn about functional data structures).

This buys you a lot of things. You can hang on to your old application states instead of throwing them away, and then, very easily, set up a slider that lets you "time travel" in your application. You can grab a list of actions, and feed them to a hundred instances of your application, all with different initial states, and inspect how the state changed at each action- really useful for testing or debugging. You can completely change your code, and have the application update in real time with all the state intact, but now running your new code- this really speeds up development. You can catch errors, and then automatically send a complete snapshot of the application state (complete with where the focus was, the text the user was typing, the clicks they used to get to that particular screen, etc.) and then play it back, allowing you to perfectly reproduce the error.

These things are all extremely difficult when the state of your application (and how it changes over time) is implicit and scattered over hundreds of views. It's trivial when the state of your application is completely described by an initial state, a series of actions, and a single reducing function.

Regarding the "intermediate information" you alluded to: this is generally solved by using something like reselect, which allows you to define transformations on the state that can be fed to views. For example, you could write a function that returns a list of items in the state that match a search query in the state, but not have the resulting list itself live in the state. This means you still have one source of truth, and the immutability of the state ensures you don't lose any of the benefits I listed above.

All these acronyms don't matter. What matters is how the architecture deals with shared mutable state and whether or not it allows for UI functionality to be easily composed without turning app state into an incomprehensible, incoherent mess.

MMVM sounds like a mutable inheritance based architecture.

Would love to dig deeper, but here is "how I feel"


UI apps have all sorts of unavoidable copied state. For example, your data base might have separate fields for first name and last name, but your UI might concatenate these strings into a single one. Whether that's stored in a ViewModel or DOM is not a practical difference.

There's nothing about MVVM that says you have to copy Model state in your ViewModel either.

That's why UI architecture (at least on the web) has been moving toward an architecture where you have a single app state store and a unidirectional flow of app state mutations (e.g. in Flux terms: from Action to Store and Store back to View but not the other way around) If you make the app state store immutable then you land in the sane model of having app state transitions (e.g. Redux) where you can have time travel thru app state, which is awesome and aids in debugging. The REST layer decouples server and client states, so we're just concerned with UI state here. Local state isn't avoidable I agree but should be reserved for things like animations that are outside the app state model (unless we're talking about interruptible, resumable, rewindable animations) ... Again, roughly speaking, but love to dig deeper.

That's generally what you try to do in MVVM apps too... you have some "service" that stores all the state. User input goes:

View -> ViewModel -> Service

and the data goes

Service -> ViewModel -> View

However, the same app state may be presented in different ways in different parts of the UI. Those different ways could each have their own ViewModel for transforming that state as needed for its presentation.

Poorly architected MVVM apps have lots of inter-ViewModel dependencies... that's where you wind up with state spaghetti.

Yup, don't do shared mutable state. It is the enemy. Avoid it like the plague.

I really love value semantics with structs in swift, it's almost always the right thing, and generally very clear when it isn't.

If anyone ever programmed so that

  int a = 15 
  int b = a
  b = 17
  assert(a == 17)
meant that a was now 17 they'd call it insane, I have no idea why anyone would want that as the default behavior.

If you had a language where that were the default behavior, it would not be insane at all (e.g., see all of mathematics,) and you probably wouldn't be able to even compile it the way you've written. You've set b equal to two different values.

My point exactly.

I think I like the components, command, dispatcher (I call it CCD) way that React and Redux deals with UI! MVVM, MVC, and MVP just don't scale like CCD. MVVM, MVC, and MVP also make it very hard to reason with your code unless it is a very simple single model maps to a view and a controller. MVVM, MVC, and MVP also are very bad at being composable unlike CCD.

Meh. MVVM just moves the problem, so what if your view controllers are testable but now your ViewModel isn't. You need to be testing those 400 lines of code.

Since it's UI code that usually breaks when exposed to weird patterns just write something that sends random touches to the screen in a rapid manner, it surfaces the bugs really quickly and generally disallows bandaid patches.

I find regular UI unit tests on the verge of useless, it's generally just coding the pattern the developer moves through the UI anyway, eg. fill first form, second, press submit, not random stuff in 3rd form, press submit while simultaneously pressing the back button, then move forward back into the same controller.

eg. If you press a text field and the back button at the same time does it leave the keyboard up when navigating back? That's where the real bugs are.

The solution is extensions and inheritance that cut down on boiler plate in the VC, as well as child view controllers.

Chuck your models into your views and call it a day. For example take your ViewCell, add a method called setData: / setModel: / configureCell: whatever you want to call it, and put your UI manipulation code in there. The puritans will tell you you're doing it wrong but it declutters the code into a bunch of 25-100 line views.

If you really need a lot of logic in there make a ViewController for that view and add it as a childViewController.

I must have missed the MVVM hate; what happened? I've been using the MVVM pattern fine for a while now without any major problems.

It's from the same people who do MVC wrong leading to 450 line view controllers, thus hailing MVVM which lets them shove 400 lines into another class.

MVVM and MVC work well if you're doing it right, which most people aren't. We've all seen the code where they started with MVC and made a bigger mess moving to MVVM because they didn't do MVC right in the first place.

My rule of thumb is to grep for .tag, if you see more than one or two references to view.tag the code is totally fucked. If you see switch(view.tag) just run.

MVVM is useful when I develop a big project with complex logic. But I do not use any MV* framework when I develop a mobile web app. I want to make it simple, so, there is only some basic class like AjaxList and SessionManager, no view or controller at all.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact