Presentation layer / Pagemaker
The part where most of the actual application work will happen is in the presentation layer of µWeb, also referred to as the PageMaker. This is largely represented by the
class PageMaker, or typically subclass in µWeb projects. When the routes for a project are defined, each route gets assigned a handler method, which will be looked up on the class which is assigned to the router’s PAGE_CLASS.
When the application has been set up and requests are handled, the request dispatcher will go through the defined routes until it finds a match, and immediately delegate the request to the method specified on the route. This is also the first shortcoming of the PageMaker and request router system.
Request handler selected only by route match
While route matching itself works fine for many frameworks, the direct coupling of a route to a handling method leaves very little flexibility in the system. There is no built-in functionality to discriminate and delegate requests based on
- request method (GET, POST, PUT etc);
- match-values from the route regex;
- content type of the request body;
- accept headers (for content negotiation);
- whether or not the request is an XMLHttpRequest.
This follow-up to the initial post about µWeb’s development history is running on the long side, so I’ve split it up into two parts. This one will deal with the high-level view and an in-depth analysis of the template system. The next part will deal with the presenter, database interaction layer and the standalone server.
µWeb is tagged as a minimal-size micro web-framework, and it does deliver on that promise. The code is spread out over a core of a dozen files and some included libraries and weighs in at a bit under 5000 lines of code (see Appendix A). While small, it’s certainly not the smallest out there. The smallest (in popular use) I’ve seen so far is Bottle. It provides a full web-framework in a single file, clocking in at just over 2300 lines of code. While less code is preferred, it’s not a compelling reason to pick one framework over another. Features and the ease with which you can get things done are.
We started development of µWeb without a clear set of design goals, and a number of decisions were made with a lack of information, experience and clairvoyance (though the latter is a common problem). This means that the current product suffers a number of unfortunate flaws. A good few of these can be easily fixed and improved upon, but others would require rewriting major portions of the code base. While a rewrite is an option, it would take a serious effort and there are other, more complete and functional web frameworks readily available for use. For my own day to day work I’ve migrated to Pyramid, which provides a simple and easy interface which contains solutions for all of the most common requirements, and is easy to extend.
This is the first part of a series that looks back on previous projects. There is a lot to learn from looking critically at ourselves, both admitting mistakes and acknowledging achievements. The first project will be µWeb, and will likely take up more than one installment. The foundations for this were laid in 2009, and that’s where the story starts.
During my time at Google, even working on the operations (hardware) side, there was a good bit of software involved. We made small scripts and applications that made everyday life go better and smoother. The tool of the trade was Python, and I quickly developed a strong liking for it. My fondness for it turned out to be infectious and my partner in programming developed a similar preference. To be fair, coming from a PHP background, what was there not to like…
Where it all began
In early 2009, we had started to become fond of pylint for analysis of our codebase. Static analysis in a dynamic language like Python isn’t perfect. In fact, it’s very far from it, but it still makes life easier, and a useful tool. It will point out a fair amount of type mismatches (sometimes ones that aren’t), unreachable code, unused or missing arguments, name- and style errors.
We liked it enough in fact, that a script was written to run pylint on our entire codebase in a comprehensive manner. The script would run periodically, checking out each of the new revisions and linting all the (Python) source files that were changed in each revision. The messages and final score would be stored in a database, providing a look at code quality over the course of development of the code.
Of course, storing data is no good if you’re not ...