An Example
The following example shows a simple contacts list with email addresses. The layout of the page is already set up, so we just insert a simple tag, <?Widgets::membershipList?>, to create the list. It looks like an HTML tag, but it automatically expands into the full contacts list.
Obviously this is a simple example, but you can see how easy it would be to move this widget around, change the CSS styling, relocate to another page or change the entire look and feel of the site around it. Even if the whole layout of the portal changes, this widget will still provide the same functionality.
Some readers will point out that there have been a number of implementations of this approach, and they’re absolutely right. This technique has roots going all the way back to Server-Side Includes, or “SSI”.
SSI and CGI Paradigms
Traditionally there have been two approaches to building dynamic web applications: the CGI approach and the SSI approach. The difference between these two approaches has major implications for a web application so it’s good to know which approach you’re going to take and why.
In the CGI approach, a server-side script often generates an entire web page from top to bottom, including the HTTP headers, although in some cases the script performs an action on the server and then redirects to a landing page. The CGI technique works really well for creating an API for handling actions, and it can work well for a large web sites with lots of pages using the same layout.
In the SSI approach, the document being requested contains snippets of code that get converted to HTML before it is sent to the browser. SSI excels when it comes to presentation, allowing everything but the dynamic content to be written in plain old HTML. The SSI approach can be very useful for separating out the functional parts of a portal from the layout and presentation.
The Widgets Pattern uses both CGI and SSI paradigms. Understanding the difference between SSI and CGI Paradigms is an important part of the approach.
N-Tier Architectures and the MVC Pattern
The well-known MVC pattern and “N-Tier architectures”, are good design practices that separate the data, presentation, and application logic. One principle from MVC that works well regardless of the scale of the project is to create a clean break between the data store and the rest of the application. A great way to do this is to wrap the database in a web service of it’s own, a la Service-Oriented Architecture. In a LAMP situation I would recommend using JSON or XML-RPC, never SOAP. The reasons for this would require another article, so let’s just move on...
Assuming that our database is nicely encapsulated in an XML-over-HTTP interface with the requisite create-read-update-delete methods, lets see how the rest of the Widget Pattern works.
The Principle of Linear Includes
The diagram above is the core of the Widgets Pattern. One of the key features of this design is the principle of linear includes. Each file contains a class, and includes only one other file at most. This is different from a lot of code bases where each class file contains a long list of includes. It might seem like this would make code organization difficult, but I found that it forced me to organize the code very efficiently, to encapsulate responsibilities carefully, and to build clean, intuitive interactions between the layers. It might also seem like the files would get really huge, but I found that with the responsibilities cleanly divided like this, the methods within each class were very concise - often just a few lines.
The Widgets Layer
The Utilities Layer
The Utilities Layer is where application logic resides. The Utilities Layer does one thing, and one thing only! It issues messages and correlates responses. This could mean for example that it sends a message to read a user’s account information, another message to read subscription details, and combines the two responses into one array of data to return.
The Messages Layer
The Messages Layer does one thing, and one thing only! It knows the syntax of the messages to issue for each of the CRUD operations supported by our data store. If the database is behind an XML-RPC interface, this means that the Messages Layer has a bunch of methods that contain the correct XML syntax for each of the operations supported by that interface. When one of these messages is invoked, the variable parameters of the message are filled in, the message is fired off and the response is returned. Again, a very simple and limited scope of responsibility.
The Connection Layer
The Connection Layer does (you guessed it) one thing, and one thing only! It manages the connection to the database server. Utilities that require multiple messages reuse the same connection.
The Configuration Layer
Throughout the code there will be, of course, parameters that should be configurable, whether it be an IP address, the action to perform on submit of a form, or the landing page to redirect to after an action. So the Configuration Layer is the lowest layer in the stack, meaning all the other layers can make us of it. The Configuration Layer does one thing only! It provides getter methods for a list of parameters that are defined in a config file. In the LAMP stack, the config file is just a “.inc” file with a list of variable declarations in name=value syntax. Couldn’t be simpler.
Note that, if your server is configured properly, ".inc" files are parsed as php files, never sent as text. The extension you use is largely a matter of preference.
The Action Handling Layer
Borrowing a page from CGI, the last component, sitting a bit off to the side, is the Handler. This is the component that handles actions from the user interface, particularly submitting information for updating the data store. This component again does just one thing. It receives requests, typically POST requests, extracts the variables from the request, including the action being requested, invokes the appropriate utility methods, and redirects to a (configurable) landing page which may or may not be the same as the page that issues the request. It includes the Utilities layer so it has access to all the Utility methods. In practice there will be some utility methods used by Widgets, some used by the Handler, and some used by both. But the handler doesn’t need to provide any output to the browser other than a header that redirects it to the correct landing page, in the case of success, or an error page, in the case of failure.
Performance
The question of performance often comes up. Please refer to my article “A Policy of Simplicity” which talks about getting exceptional performance from LAMP-based applications. The venerable APC cache will be of interest in this regard, although other byte-code caching and code optimization tools are available. APC is among the best options and performs extremely well. In fact, I have yet to come across a platform that can perform better.
On the way to really elegant web portals
This article is really nothing more than the application of some good design principles in a popular medium, and I hope it helps some designers who might be thinking through different approaches and leads to some really elegant web portals!
This approach has been used for portals in a number of 1st-tier telecommunications companies. It has enabled rebranding and feature requests to be implemented with unprecedented rapidity, and enabled clients to implement their own functionality with very little assistance, very quickly. Having seen the success of this approach in the field, I wouldn’t go back to using a cumbersome application framework unless there was clearly a performance benefit to be had. One possibility would be the LYME stack, and I’d like to spend some time with it. I expect that the Widgets Pattern would also work very well with it.
In the next couple of weeks I’ll try to post some code examples that demonstrate the Widgets Pattern in action. Till then, take care and have fun!
No comments:
Post a Comment