Part Three: Refactoring the MVC Pattern
In this third and final part of the article, we retrace the footsteps used by Trygve Reenskaug to isolate the MVC design pattern and apply his modeling techniques to the servlet framework tier. We also introduce a new design pattern that specifically addresses the needs of servlet framework developers in the J2EE sphere.
Fortunately, we're not bound to the MVC pattern. If we're willing to do some legwork, the techniques developed by Dr. Reenskaug to arrive at an appropriate design for the problem of servlet framework architectures are at our disposal.
While we're designing this new pattern, we must keep in mind the five requirements listed above for a component framework. We know that we must create a system that can be decomposed into modular components, that the behavior of each subsystem component should be transparent to the larger system, that components should be able to plug in to the larger system, and that the system should therefore be capable of continuous growth without adding complexity or management chokepoints to the development process. Finally, the inner workings of the system should be subject to some form of manual override, wherein a manager can redefine the system behavior at runtime without taking it offline.
Concerns of Architectural Components
We have to start by considering the different roles that different objects play in our system. There are only a few higher patterns of behavior for all of the different architectural components in a servlet framework. If we are able to isolate those behaviors and capture them into interfaces, then our system will become more flexible and modular.
By considering the nature of the different components in a servlet framework and employing basic separation of concerns, we arrive at three different roles for objects — three higher patterns of behavior that can be observed in all existing systems:
- DataSource: In the most abstract sense of the term, this is a place from which data can be gathered and stored. It could be a message bean, a request object, or a map, and would have a set of very simple method signatures similar to a map.
- Action: An action is the basic logical building block of a business system. Actions are all executed and needn't necessarily know the order of their execution.
- Workflow: The core concern of the servlet framework is to manage the execution of a sequence of Action objects using one or more DataSource objects. The internal logic of the framework that determines the flow of control over the request can be isolated in a Workflow interface.
And what about presentation components? First, bear in mind that the user interface for a system needn't necessarily be visible. It could be audible or thermal or even olfactory, so "View" components is an inappropriate and limiting term. Second, considering the requirements, it follows reasonably that our framework should easily plug into any type of presentation technology, several of which are becoming extremely advanced and needn't be replicated.
Trying Out the New Design
How do we know this would work? Let's try applying this new design concept to a simple application like a card catalog, and if it doesn't work, out we'll refactor. The data written on the cards should probably be kept in some kind of DataSource objects so it can be stored, retrieved, examined, and altered. There are many different types of data object solutions. EJBs, POJOs, and XML are just a few — the list goes on for miles.
Next, we'll want to operate on the data in the cards. Pulling them out of storage, putting them back in, shuffling them, erasing their contents, using them as coasters, etc. This logic can be encapsulated in actions (preferably as fine-grained as we can get them). If we break down the actions into small enough pieces, we can use them in different combinations to get different effects.
The decisions governing the order in which these action combinations are executed represents the application's workflow. To encapsulate this logic, we can write a series of workflow controllers whose job is to execute actions in a certain order. This workflow could be hard-coded into the program, but it would probably be better if we incorporated a dynamic, rules-based system like Drools , so that the workflow logic could be controlled and altered at runtime to meet the changing needs of the business.
Of course, all of the different, dynamic rules approaches require some kind of external data for directing traffic. Do we need to refactor the design and add another category for components? Not at all — workflow descriptors and user input are just two more types of DataSources.
The actual human interface for the web application can take place in another tier, and its developers can use whatever solution they like for building their components. They can share access to the same DataSource components, and can implement their own presentation components and tools for manipulating the data however they want. If they're smart, they'll probably use MVC or some variant in their component design, because UI is where MVC shines.
Abstracting the Feature Platform
If we were able to break down system in this interface-heavy manner, we would be able to abstract the actual features provided by the platform. Things like form validation, value caching, dynamic EJB bridges, security integration, and other actions could all be abstracted into a platform that actually rests on top of the underlying workflow system (or plugs into it — I say potato ...). At that point, developing feature platforms of useful and common actions could be a cooperative community effort. Businesses could develop their own libraries to implement application-specific, or even system-level, actions without having to alter the underlying workflow system or even know how it works, and development teams could combine their efforts to build libraries of mission-critical action components for common use.
The interface-heavy design could also potentially allow us to swap out entire portions of the workflow or action subsystems at runtime and replace them with custom, more specialized subsystems that are tailored to our individual needs. Imagine: exchangeable parts for servlet frameworks. With Maven , we could dynamically assemble the framework and feature platforms at build time from specialized component subsets.
But it doesn't have to stop there. The social benefits of such a flexible, modular, and extensible system should be obvious. The different factions of the development community could reassemble around implementing commonly needed features instead of warring over architectural minutiae. Businesses could develop strategic, proprietary feature platforms that are fine-tuned to the needs of their companies, or could collaborate on common component libraries without having to get their changes accepted by the team developing the workflow core.
And perhaps the best news of all is that the investments we've already made into the feature platforms of different frameworks could easily be ported to this new infrastructure. Features from Struts could be rewritten as action platforms and plugged into the framework without a hitch. It might even be possible to write compatibility layers for existing action implementations, so that the end users don't suffer unnecessarily in making the transition forward.
Results and Conclusion
We all have this task in common: to implement a framework that will reduce the complexity of bridging the web interface to the application server, and to do it in such a way that it is flexible, extensible, and capable of constant mutation throughout the coming years.
As open source middleware developers, we also share a common desire to improve ourselves, our businesses, and our communities by collaborating to build better tools. The time is long overdue for each of us to reconsider our assumptions about the MVC pattern, to acknowledge the negative effect it has had on our community, and to work together to address the problem. We need to reevaluate our common technical and social needs, overcome our stubbornness, and completely abandon the MVC design as the cornerstone of the servlet framework architecture. A new solution is waiting that addresses those needs.
In the next piece in this series, I'll back up my assertions with actual code and introduce the Shocks Servlet Framework, a full implementation of the design I've outlined here. I'll go over the architecture of the framework, discuss how it evolved conceptually, and show how it addresses each of the five challenges for frameworks Dr. Reenskaug laid out over thirty years ago.
N. Alex Rupp studies theoretical geometry and classical literature and is conducting ongoing research in declarative programming.