TomcatExpert

Non-MVC Frameworks for Social and Web 2.0

posted by jbrisbin on August 23, 2010 08:00 AM

Trying to keep up with web development trends is a full-time job. I don't mean that as hyperbole and anyone that is actively engaged in staying on top of emerging trends in web development knows how difficult it can sometimes be.

The developers actively involved in creating the new frameworks and defining the new meta-patterns aren't always helpful, either. Some web development communities—lived out largely in the form of forums and mailling lists—can be irksome to beginners and visual learners. Many developers feel a "you should be able to figure it out by reading the source code" attitude in that community. This deters many people from trying to learn these new patterns. They wait until there is a critical mass of developers and industry attention before taking the plunge. But this presents a software community with a classic catch-22: they need users to test their code but they can't get users because their code isn't tested. The process of accumulating enough users of a framework, including the essential bloggers, tutorial writers, and industry OpenSource "patrons", can often take four or five years—sometimes longer.

This was the case with MVC (Model-View-Controller, for those new to web development) just a few short years ago. I remember going to a Java user's group meeting where Spring (during the 1.0 timeframe) was presented and I was excited. I liked how the framework was put together and it was such a pleasant alternative to hooking servlets and JSP pages to EJBs. I was so opposed to using the "accepted" J2EE methods, in fact, I wrote my own XML-based framework from scratch rather than subject myself to the overhead and complexity of a J2EE application.

Now that Spring has gained market dominance and MVC is at least a majority-accepted development pattern, it has overflowed into other web frameworks and languages—though fanboys of other languages and frameworks will graffiti your office if you so much as suggest their pet framework wasn't the first this-or-that on the block. That said, most web frameworks, no matter the language, offer some rendition of the MVC pattern—and have for years. Ruby has Rails. Python has Pylons. Java has Spring. Groovy has Grails. DotNET has MonoRail. And that's leaving several out for each language. There's even a sort-of MVC framework for Smalltalk web developers. I didn't even realize until recently there actually were Smalltalk web developers. Most frameworks also offer some kind of database persistence integration to abstract away the drudgery of working with raw SQL (the "M" in MVC).

But now that NoSQL databases are finally coming to mainstream development, the web is going truly and fully asynchronous, and the ignominious cloud architecture is spreading its shadow, the MVC design pattern is getting, in the view of a surprising number of developers, to be getting a little long in the tooth. It may seem heretical to some to suggest that the MVC design pattern doesn't always fit Web 2.0 and Social applications. Be that as it may, I hope to introduce you to a couple alternative frameworks that don't fit the MVC design pattern and are proud of it—but still offer the developer all the tools they need to meet the demands of new applications and clients. I can't show you everything, but I'll try and hit the high spots.

Pick yer Poison

I couldn't talk to everyone, of course. So I chose to talk to David Pollack, the creator of the Lift web framework to get grounded in the non-MVC pattern. Lift is written in Scala. Scala is one of a new class of development languages that run on top of the Java virtual machine and can transparently interact with Java's profligate third-party library community. Scala is not a loose, interpreted language like Groovy. Scala is functional (in the Functional Programming sense—though not purely functional), unabashedly type-safe, and compiled, not interpreted. Lift draws from the Scala language itself, as well as from the decidedly MVC frameworks that came before it.

It was clear in my discussion with David that it isn't just about Lift the framework. There is a paradigm shift embedded in Lift that is reflected in other areas of the industry and in communities that already have that four to five year bake time I mentioned earlier. He feels that MVC frameworks are "fundamentally flawed." In defense of that assertion, consider the home page of a social media site. How many segments of the page have their own, disparate pipelines of information? Are there RSS feeds embedded on the page? How about recent activity links? Updated content teasers? In an MVC framework, to accommodate all this unrelated information, the developer has to create a "HomePageController" of sorts, which is an aggregation of all that information. But very quickly, controllers multiply and become simplistic data retrieval methods that simply load a bunch of objects from the ORM and place them in the template context to be rendered by the page. Non-MVC frameworks take the approach that one ought to call a Spade a Spade and simply acknowledge that the user interface—the page itself—is the focus of the application, not an arbitrary, intermediate controller, and that it should be constituted of components embedded in it that are concerned only with their own data and event callbacks. Generally-speaking, Non-MVC frameworks abstract the entire HTTP request/response cycle such that developers only need to hook into well-defined lifecycle callbacks that may exist beyond the scope of a single HTTP request.

Lift, JSF, and ICEfaces

I would liken Lift—at least in a very general sense—to JavaServer Faces for Scala. That may not win me many fans in the Lift community, but I see things in Lift that remind me of JSF. The way JSF ties a user interface action (a la clicking a button) to a server-side method call on a stateful bean of some sort is similar to the method employed in Lift.

David explained to me that Lift intentionally takes a "view first" approach. This means each component on a page—Lift calls them "snippets"—is an instance of a Scala object that is responsible for both displaying output and processing input data; this rather than interposing an arbitrary controller object that's responsible for setting objects to be displayed by the template into some sort context and also processing input parameters from POST data that may (or just as likely may not) have come from a browser form. Because of this behavior, Lift doesn't force application code to know anything about HTTP requests. By tying application code to, say, a form button, the developer doesn't have to worry about where the data is coming from nor what to do with it. The Lift framework takes care of the logistics for you. This should be no surprise to ICEfaces or JSF developers, who have had this kind of programming paradigm in their conscienceness for a long time now.

For the visual and learn-by-example folks out there, you're probably wanting to skip ahead to the examples. Although this isn't really a technical HOWTO, here's a good example that demonstrates the functionality of Lift and ICEfaces:

Lift

All output in Lift is kept in XML format internally, so to output data from your Scala object, you would put a special XML tag in your template that is in the "lift" namespace (from the HelloWorld Lift example included whenever you create a new Lift project):

<code>
<lift:helloWorld.howdy>
<span>Welcome to my-web-app at <b:time/></span>
</lift:helloWorld.howdy>
</code>

In your Scala source directory you would create a Scala class named "HelloWorld", defined in a special package named "snippet" (which is actually a sub-package of your project package name). For the purposes of our example, the snippet class would be "com.my.webapp.snippet.HelloWorld". In that Scala class we would define a function named "howdy". Lift knows to call this function because the XML tag name is an aggregation of the class name (you can even lowercase it and put underscores between words: "hello_world" would work, too), a dot ".", and the function name. A simplified example of the actual Scala method would be:

<code>
class HelloWorld {
def howdy(xhtml: NodeSeq): NodeSeq = 
Helpers.bind("b", xhtml,
"time" -> Text(date.toString))
}
</code>

You might recognize some of the syntax of Scala if you're familiar with ActionScript. In particular, types come after variable names (after the colon). Unlike ActionScript, however, functions are always assigned with an equals sign and the language itself is type safe. Without going into too much detail (this isn't a HOWTO, remember), this function demonstrates a lot of powerful Lift functionality.

ICEfaces

ICEfaces (and plain JSF applications, for that matter) use "backing beans" to tie user interface events to server side code. If we were to express the Lift example in terms of an ICEfaces application, we might put something like this in our JSF page:

<code>
<ice:outputText value="#{helloWorld.howdy}" />
</code>

Unlike in Lift, our Java bean would need to be configured with a specific lifespan (e.g. "request" or "session") and bound at application startup time using the application-wide "faces-config.xml" (or you could use Spring to instantiate your beans). Our backing bean would contain a traditional JavaBean property called "howdy" that's backed by getters and setters.

Security

In Spring MVC or Grails, the developer would need to apply additional security checks to their MVC code using something like Spring Security to protect against common attacks. In Lift, security is baked into the framework at the sitemap level.

In other MVC frameworks, replay attacks are a common exploit that have to be especially considered when coding an application. By requesting your form, an attacker could learn what request parameters he would need to bombard your application with. In Lift, replay attacks are next to impossible because the names of request parameters are basically random. When a user requests a page with a form, for example, Lift ties request parameter names like "F2812254715K3N" to properties in your Scala object. In this case, the field is a first name field. When the user submits this form, Lift will properly set my Scala object's properties because I've "bound" the form to my internal String called "firstName". I can't submit the same values again and again to get the same result because I've already passed a value to my bound object.

ICEfaces is JSF on Ajax steroids, so it isn't as inherently susceptible to the garden variety of automated attacks as a "plain" MVC application (where a controller responds to a known, constant URL request). Like Lift, it benefits from the basic HTTP Request/Response cycle abstraction that make it easier for the developer to use. That said, ICEfaces applications don't have baked-in security like Lift and require an additional layer to protect your application.

Pattern Matching

Because it's written in Scala, Lift benefits from the daunting, but powerful Pattern Matching programming metaphor. At first glance, pattern matching seems to be an elaborate "switch" statement or simply a condensed "if/else". In my estimation, pattern matching is more like the latter than it is the former—but it's also more than either.

In Java, switch statements are frustratingly simplistic because they only allow types like "int" and "char":

<code>
enum Type {
ONE, TWO, THREE
}
...
Type t = getMyType();
switch(t) {
case ONE:
something();
break;
case TWO:
somethingElse();
break;
}
</code>

To even approximate pattern matching in Java, you would have to deeply interrogate an object with a series of "if/else if" statements:

<code>
MyType t = getMyType();
...
if(t.getType().equals("one")) {
something();
} else if(t.getType().equals("two")) {
somethingElse();
} else ...
</code>

This is not only fragile, but verbose and a little hard to follow. The equivalent in Scala is much cleaner:

<code>
val t:MyType = getMyType
...
t.getType match {
case "one" => something()
case "two" => somethingElse()
}
</code>

Lift (and Scala web development in general) use this pattern matching paradigm to simplify code that branches logic. Since Scala is type-safe, the pattern matching takes on new levels of functionality that are, to be honest, a little confusing and hard to really understand fully. To treat pattern matching any more fairly in this article would ballon its size two or three times! It's a big topic because it's a powerful part of Scala and Lift.

There is no Java, Ruby, or Python equivalent to Scala pattern matching.

The Big Downside

ICEfaces applications have tooling, heavyweight though it may be. IntelliJ IDEA, NetBeans, and eclipse, et al have many hundreds of lines of application code designed to help the developer create JSF and ICEfaces applications. There's a bit of a learning curve with ICEfaces, but generally speaking, a traditional J2EE developer will be able to transition to ICEfaces development without a lot of trouble. They could even mix ICEfaces and Spring MVC in the same application and use ICEfaces more as a traditional view layer than as a holistic application framework.

Lift and Scala, however, have no mature toolset in the popular IDEs—though command-line support is pretty good, all things considered. You can use Maven to build Scala/Lift projects, so most IDEs encourage Scala users to pursue building their projects with Maven. But since Scala is a compiled language, code has to be constantly re-compiled and the sophisticated parsing engines of IDEs like IntelliJ IDEA don't offer the developer as much pre-compile support as there is for other languages.

Scala also has a steep learning curve. I still feel like a n00b, even after a couple months. Though Lift is at version 2.0, going on 2.1, there aren't an over-abundance of tutorials and blog posts to help the developer new to Scala and Lift. I'm told it's worth it in the end, if you can stick with it.

Finally, The Wrap-Up

I hope I've at least piqued your interest to learn more about Non-MVC frameworks. There isn't enough time in two (or even 10) articles to really do justice to either Lift or ICEfaces. As with anything, though, you'll learn more by playing around with them than you will by anyone telling you about them. I encourage you to visit their websites, view their demos, and read through their documentation.

MVC is a tried-and-true method for deploying web applications. It's been around a long time and is not likely to go away. But Social and Web 2.0 have changed the rules of the game. It behooves us as developers to keep watching out for those technologies that help us do our jobs better or help us offer better functionality to our clients than can our competitors.

Good luck!

Further reading:

Jon Brisbin is an Architect/Analyst/Java Guru at NPC International, the world's largest Pizza Hut franchisee. He's been deploying web applications on Tomcat for over 10 years and currently focuses on cloud computing (virtual, hybrid, and private). He built a private cloud from scratch using VMware ESX, Ubuntu Linux, packing tape, and rusty baling wire. He's done consulting work with industry leaders and Mom-and-Pops alike. Prior to NPC, Jon developed new application frameworks, integrated the AS/400 with UNIX and Windows systems, developed Lotus Domino applications, hacked websites together with Perl CGI and a text editor, and served with US Air Force Intelligence in a very hot and sandy, but undisclosed, location. He lives in the rural Midwest.

He blogs on Web 2.0 (and sundry topics) on his website: http://jbrisbin.com/web2

Comments

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.