I think it's strange that people discuss "MVC" without specifying which MVC they talk about - - because most of MVC patterns are VERY different and used in very different contexts (e.g. Rails and Smalltalk). About a year ago I did a blog post about the history and usage of MVC* and for me it does not make sense to talk about MVC as a general pattern, because the implementations, contexts and ideas are very different from one MVC to another. If you want to discuss MVC please specify which MVC pattern you talk about.
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.
Yes! State machines are a natural paradigm for complex UIs.
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!
State machines are this neat thing they teach you in freshman Computer Engineering courses, but I've met a lot of CS or SE graduates who have no idea, which is too bad--they're a useful tool. Anyone who doesn't know state machines should definitely read up on them.
This is why I prefer Sinatra-style programming. You don't have to waste brain cells on unnecessary abstractions that don't correspond to anything real.
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).
This works for small services and apps, but I think it'd be quite a maddening exercise to try and keep a large codebase consistent and organized with that method.
In my opinion it also works for a large codebase. You just have to define your (REST) resources carefully, but they scale very well. The smaller details (on class/object level) are in your lib directory and have no direct relation with your Sinatra app. In fact your Sinatra app could also have been a command line app or something else.
It seems like with Sinatra if you do it right, you'd be doing MVC* anyway. Your route handler functions are the controllers, and your models are basically domain objects that handle business logic. Of course, if you do it wrong, you end up with request handler functions that are full of business logic, which is what a lot of MVC apps end up looking like anyway.
* Or at least, what web developers refer to as MVC.
Route functions aren't like controllers. Controller is an abstraction that has nothing to do with http. It doesn't correspond to http.
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.
I don't really understand your point. In MVC, we use functions on the controller to handle the incoming request and the response. There is usually a router that routes an incoming request to the corresponding controller and function.
How is this different than what a route function does?
Similar thing with the web frameworks I use. I don't need MVC, but in reality I end up using something similar anyway. I render a template (essentially a view, Jinja2's pretty powerful), request functions are essentially controllers, and I have a set of functions and classes for manipulating data and performing operations that essentially form the models.
I think that's what is really important; understanding what concerns need to be separated instead of blindly creating models, views and controllers because that's how it is supposed to be done.
Yep. This design is partly because of lessons learned from experience: PHP development showed me that mixing things together and code duplication is a bad idea.
I read through the whole article twice, and I think OP is using the term "state machine" very, very loosely. I have a very tough time believing that the vast army of MVC web developers out there know about Mealy machines and Moore machines in any significant depth, if at all. How many of them do you think know how to formulate a Moore machine, convert it to a Mealy machine, explain the differences between a finite automaton and a Moore machine, how to negate lambda transitions, produce a context free grammar...seriously, if you are the sort who, when given a problem, thinks of FSMs and Moore machines as a first level abstraction, are able to construct a delta transition function as the cartesian product of the set of input states Q times the set of input alphabets sigma...you are so far ahead of the rest of the pack in both theoretical competence and intellectual ability...you wouldn't even bother with nonsense like MVC at that point.
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 ?
I'm a hardware designer by profession--digital logic specifically. A very large portion of our work involves FSMs. I don't think I've ever done a design without one, and usually several.
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.
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.
I have found that using (F)SM to model a REST API makes everything a lot easier. (It is after all state transfer)
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.
Isn't the REST API role just limited to synchronize the model (state) between the client and the server ? If state transitions are taken care by the API, your API is not REST anymore, it includes RPC actions.
Throwing my 2 cents into the bucket:
I'm involved in a small embedded device project, where we wanted our UI to be completely decoupled from a legacy, very heavy, single-threaded component.
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. :)
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.
One problem with a state machine approach compared to MVC is that it isn't as familiar. Do you use a Moore or a Mealy machine? A combination of the two? Most people don't use state machines to model the flow of an entire web application, so if you try it out, you might feel like you're on your own.
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/
I introduced statecharts to the SproutCore community in 2008, and there are a few really nice libraries that have grown out of that. Statecharts are now a standard part of SproutCore development, both at Apple and in the larger community.
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 have been a couple web services I've done which we've modeled as a state machine. I found the approach gave the architecture and API much more consistency, especially when paired with REST.
I might be reading the blog wrong, but it seems he is using the MVC view (templates separated from the logic and sent to the user) and the user interface interchangeably. These are two very different things.
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.
"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."
I use state machine of sort (jbpm) in the backed to drive business processes. We have thin client connecting to database, nodes in state machine are actions on databes, or screens we show to user (with inputs possibly). Edges are transitions between screens. Edges can have conditions on them. It's all saved in database between requests, and request/response moves state throught transitions to the next interaction node (possible going throught a few action nodes doing sth on the databsae).
Any exception on the way rollbacks the whole state, and we commit only when we reach next interaction node.
I would like to develop this idea further. What if we store all the state in a specialized state storing server application? What if we develop a portable language for querying and updating this state? What if we introduce a "transaction" mechanism in the state storage system so multiple users can interact with the state at the same time? We can call the state storing server a "data-base management system". It would be awesome!
I have used both the state machine pattern and MVC in large projects and in some cases used both together. There is no problem with MVC. It can work with any number of supporting patters. If your problem is your controller doing too much work.. you're just doing MVC wrong! MVC is not the answer to life, the universe and everything. As long as you use it with that understanding you'll be fine. MOVE with its operations concept seems very similar to MVC with command pattern which is a perfectly viable solution which I have used in a project which involved making our own document editor and we had no issues with it. So, I really don't get what all the fuss is about. STFU and use what supports your requirements. Design patterns are evil themselves. Design according to your requirements and empower your models. That's all you need to do!
I thank all of you so much for this very enlightening discussion! What was a loose idea in the first place, I should definitely develop in deeper detail as soon as possible.
> BTW I willingly omitted the “F” of the (F)SM since this might be subject of discussion here, despite the fact that “infinite” is really huge in the world of computation.
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.
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.
* http://amix.dk/blog/post/19615