MVC, MOVE - Or Simply A State Machine?
ingoschramm.tumblr.com
ingoschramm.tumblr.com
Regarding this article I think it would be much better if the author provided some code for his "state machine" idea. Currently it's just a blurb of text and it's hard to imagine how his ideas would work in practice.
One framework I enjoy and use is Lamson - - Zed Shaw's mail server framework. It uses a state machine abstraction and it works quite well. This said, I think mail server processing is very suited for the state machine abstraction - - I am unsure how suited UI is, since it's a lot more complex than processing email.
Event handlers are great as long as they remain independent little globs of code: this button turns that thing off, this click makes that color different, etc. But once they start affecting each other at a distance (e.g., the button starts some action that temporarily changes the meaning of the click), you need a method of controlling the effects systematically or you end up with spaghetti. Pretty much every complex UI I've ever seen is that spaghetti.
MVC is too simplistic to give this. M means "state" and V means "what the user sees" and C means "just make it all work, mkay?", which lets you down right where you need an organizing principle.
I struggled with UI spaghetti for years before finally realizing that state machines are a nice systematic way to manage this complexity. Now it seems kind of obvious that UIs are state machines. They're machines and they have state!
You just have functions (not "controllers", or "operations") that respond to a particular url/method combination. Those functions job is to interpret the request and respond accordingly.
This style adds no new abstractions or opinions that aren't already in http. It formalizes what http already gives you, with some utility methods for the common things needed (content negotiation, etc).
* Or at least, what web developers refer to as MVC.
When MVC was shoehorned into http the controller was meant to control the resource, which is how people know of it. But it also controls the collection of resources.
The route function is much simpler than a controller, it only handles one particular method of a resource.
How is this different than what a route function does?
There was a generation where these things were formally taught...but that ship has sailed. The people who get worked up about MVC in web frameworks these days are in the same boat for whom Microsoft once built the FrontPage wysiwyg html editor, because they were too busy to grok the bold and italic tag. Ofcourse a REST api can be modelled using an FSM. But then, so can addition. Division. Subtraction. Arithmetic. Do you honestly see people approaching general purpose CRUD programming by saying "hey lets build a state machine" , because that what's 99% of computation is, anyways ? Nope. Then why pretend ?
State machines, to me, are a completely natural way to solve problems. They are, of course, just one tool in the box, but in the digital logic world, FSMs are a tool used quite frequently.
I do some coding as well, mostly as a hobby/intellectual interest. I really struggle with a lot of CS ideas. Higher order functions require a lot of concentration on my part to keep straight, and recursion isn't a concept I run into much in hardware design.
I suppose it could just be a lack of familiarity, but I find state machines (Moore or Mealy) to be a very straight forward and concrete concept. I feel that much of CS requires the greater intellectual ability.
I struggle with MVC. It sounds great and eminently reasonable when I read about it, but it seems like the lines are smeared whenever I try to implement it or see others implementations.
* http://www.cs.dartmouth.edu/~sergey/langsec/
You can basically make security proofs in your protocol.
http://www.youtube.com/watch?v=3kEfedtQVOY
I was thinking about extending this to bottle.py and replacing the routing elements with an fsm library. Then I wanted the views to be a bunch of regexps or simple includes.
So, yes, I would agree - most things we want to do with most web interactions are little more than state machine changes. I would be interested in how the routing/FSM work might pan out.
We decided to model the whole UI transition flow into DFA's, using events from the touchscreen (pre-processed) as inputs. The state machine is modelled with boost::statechart, which has proven to live to it's thread-safe reputation.
The jump in development speed and the absence of flow bug is nothing short of remarkable from this experiment.
Although I pushed for it, I was a bit fearful that the formality would make developers resist the architecture, but I'm pleasantly surprised the opposite has happened!
...but, we haven't launched yet, so, fingers crossed. :)
EDIT: Added plug to boost. Boost is awesome.
Views + a state machine is basically a description of CouchDB and CouchApp style programming, so I've seen the OPs architecture being used in very real life situations.
I've been calling it an event architecture, that that's not a great name. It's not just events, because events can cause the client to query, so there has to be a whole state machine backing up the event system.
It can be worth it, though. I used state machines for a client-side UI in ClojureScript a few months ago. It forced me to think hard about the structure and flow of the app. But after that, my state was in an explicit, contained area. If I had been using something like Backbone, the state would have been hidden among the various model objects. I felt like I had a much better mental model of how the program worked after the initial design process. Keeping state in control reduces complexity. [1]
Another benefit was that the state machine library I used allowed me to audit the trail of states as they happened. When a user toggled a checkbox to trigger an event, I could look in the JS console and see the moment the checkbox was triggered. If something wasn't working, I could often debug it by seeing if the states and transitions happened in the right order. I wouldn't be able to do this with a traditional MVC framework.
There's one very important thing that nobody has mentioned yet: state machines look ugly in your code. When they get big, they are difficult to follow. I started out using a state machine library that was just too simple. Once the interactions became complex, I was getting lost in my code. I looked for a clearer, more succinct way of modeling state machines, and eventually I came to Harel statecharts. [2]
Statecharts are a way to model state machines without explicitly writing out a ton of redundant states. The number of states becomes a problem when you actually try to model an application with a basic non-deterministic FSM. If you're interested in using state machines in your web application, you need to read the linked paper. The example of modeling a digital watch with statecharts makes it easier to see how you could use them in a web app.
I believe statecharts are to MVC as Clojure is to every mutable state language out there. It feels weird at first, but once you get used to it, it's much simpler. It's just not necessarily easier. [3] If you want to try them out, there's a good library called Stativus for writing statecharts in JavaScript: https://github.com/etgryphon/stativus/
[1] See "Out of the Tarpit" for why state and complexity are closely related: https://dl.dropbox.com/u/249607/all/Out%20of%20the%20Tarpit.... (The original link is down, so I made a mirror.)
[2] The original article on statecharts: http://www.wisdom.weizmann.ac.il/~dharel/SCANNED.PAPERS/Stat...
[3] More about the idea that simpler things are not necessarily easier: http://www.infoq.com/presentations/Simple-Made-Easy
I also teach a course on how to combine MVC architecture with statecharts. It's pretty easy, but non-obvious, and once you learn how, you'll end up using statecharts for the rest of your life. No one goes back to the 'old' way of spreading application state among controller objects.
There are two different statechart implementations in Blossom: https://github.com/fohr/blossom
One is for the application logic, the other is for writing individual views (called "behaviors", but they're statecharts).
-----
Shameless plug for my 3.5 hour MVC+statecharts course: http://erichocean.com/training/app.html
Even though it's targeted at SproutCore devs, the concepts apply to any application MVC environment, e.g. Backbone, Qt, Cocoa, etc.
The interface the client uses is always going to be some sort of state transfer system, moving between different pieces of content and displaying elements to transfer between content.
Handling these views on the back end is an entirely different issue.
State machines are useful on the back end, but it can not be used between requests without causing headaches.
I have been experimenting with state machines in a node.js framework to handle asynchronous sub-views (https://github.com/Dashron/roads). It makes development incredibly simple, and breaks up the code so that you can have traditional, or single page apps with the same codebase.
I don't think a state machine would be useful at a higher level than this (in the backend) but I will put more thought into it.
http://blog.nodejitsu.com/scaling-isomorphic-javascript-code
"Javascript is now an isomorphic language. By isomorphic we mean that any given line of code (with notable exceptions) can execute both on the client and the server. On the surface this seemingly innocuous property creates a number of challenges that are not solved by current MVC-based patterns. (...) In conclusion, we will explore a new pattern: Resource-View-Presenter."
Except I call my presenter layer "resources" and my resources "models".
The state machine in my framework is a system within the view layer so you can asynchronously re-route through the "presenter" and re-use code.
Any exception on the way rollbacks the whole state, and we commit only when we reach next interaction node.
It works great.
http://sheddingbikes.com/posts/1278464593.html
Here's the image of the state machine: http://sheddingbikes.com/mongrel2_state.png
Now imagine having something like that (say a prettier version of that chart) for web interactions with your complex web app.
"I love state machines. They turn asynchronous event problems into nice tidy well known problems."
If you have a FSM that can read and inc/decrement a counter, you have something strictly more powerful than a FSM. I expect that dropping the F is entirely appropriate for most controllers.
“infinite” is really huge in the world of computation
Really huge = infinite. I LOLed.