I’ve been doing some reading lately on Design Patterns. I find myself trying to relate the examples to Web applications.
One of the interesting ones is the State Pattern. This says that an application is really just a collection of states, or situations the application might find itself in.
This theory postulates that any application is a Finite State Machine and should never find itself in “the wilderness.” Put another way, at any moment in time, it should be able to clearly define just what it’s doing and how the user is interacting with it. All states should be known.
I find that this one relates to Web application development quite a bit. If you have a large application, and it’s getting complicated, I think it’s easier to examine the app in terms of all the different states it could be in.
Consider an article management system. In relation to an article, you could be in any of the following states:
Viewing an article
Viewing an article’s editing form
Submitting an article
Deleting an article
Confirming the deletion of an article
The idea is to be able to define match all requests up with a defined state. So, how do you do this? As near as I’ve been able to figure, you can identify state by two things:
So, from the above example, “Viewing an article’s edit form” might be defined by a URL pattern of
/articles/[some id]/edit and a request method of GET. “Submitting an article” would be the same URL pattern, but with a request method of POST.
(I imagine there are other things to determine the state. Cookies, session variables, etc. But URL and request method are the two big ones.)
I’ve written a little URL mapper class for this in the past. It lets you define a set of URLs, request methods, and corresponding states. Instantiating the object examines the inbound request and returns the state. How you handle it from there is up to you.
The “official” State Pattern calls for a series of state classes which handle the different states of the application.
This may be a little complicated for the average app. In a lot of cases, I just use the current state to load a file with the correct procedural code for that state.
In the end, this really helps clarify a large, complicated application because it lets you drill down from the big picture to a series of self-contained states which is much more manageable.
For a particularly large app I was working on 18 months ago, I actually had an spreadsheet listing all the states and their descriptions. It made the app so much simpler. In one place, I had the entire picture, and the goal was to be comprehensive enough that every single known state was on the sheet.
Besides simplicity and clarity, focusing your app through states has a few other benefits:
It generally results in cleaner URLs, which is think is critical in Web apps. Since you have to identify your states from the URL and the request method, you tend to put more thought and care into the URLs.
It helps with security because you can map states to security settings. For an app with binary security, you can have “protected states.” If a certain state is protected and the user has not logged in, you just change the state to “Not Logged In” before executing any business logic. Protecting other parts of your app is as simple as defining the applicable states as “protected.”
Some other random notes:
I’ve also found some connection between state-mapping a Web application and wireframing. About three years ago, I generated wireframes for every single screen in a Web application (which, sadly, never got built). In the end, I had 43 screens…and, it turned out, all the possible states my application can be in.
Of course, Ajax plays the spoiler here because it allows for states that aren’t represented by a visual screen or a URL. It gets trickier to map these since you have “intra-page load” states, which is like the 7 1/2 floor in Being John Malkovich.
You can find an example of states right here in Movable Type. Its admin section runs off a “mode” querystring argument:
This defines a state where you’re viewing a comment. I’ve done this on a few apps before too – just pass in a mode argument which defines what’s going on. Bonus points if you re-write it.