By Reg Charney
This article was inspired by four things: my current project to build an n-tier web-accessible application; Rich Moen’s introductory notes on PHP; Kylix 2’s Adapter Page Producer class; and Bjarne Stroustrup’s presentation last month on modern C++ design. However, since I put all this together in my own way, any errors or omissions are mine alone.
My project requires that I generate web pages on the fly using a database whose parameters come from user requests. For example, to get a delivery report, an end-user presses a button on a form that sends a predefined SELECT statement to the database backend that gets a series of records and fields. An application server then applies these records and fields to a text template to generate HTML that a web server sends back to a browser.
Kylix 2’s Enterprise Edition has an extremely powerful class called an Adapter Page Producer to assist with this task. However, since I am hoping to do a review of this product later, I will leave this solution to another article. It also requires the presence of Borland’s Kylix 2 Enterprise Edition software.
The solution to this problem that Rick Moen suggests is to use PHP (see www.php.net ) and generate the HTML inside PHP code. Using PHP, his algorithm is the normal one:
| <?php
require(" header.php" ); $q="select company, st from locations where rte = '$route';" $r=mysql_query(q); while(list($company, $st)= mysql_fetch_row($r) { echo "$company<BR>"; echo "$st<BR>"; } ?> |
While this works, it is very maintenance intensive. Changes in the database means that this page may need to be changed also.
Looking at the design of the code, we see that it has an initialization section where the query is executed, an iterative body where most of the work is done, and an optional epilog where a dependent footer could be generated.
In object oriented terms, this corresponds to a constructor, a “run” member function, and a destructor. Since PHP 4 (and earlier versions) offers only very limited support for object-oriented programming, I will use a pseudo-OO language for the rest of the examples in this article.
The following pseudo-code uses the constructor/destructor paradigm to generate most of the overhead code needed in any HTML page.
| Class HTML: __ctor__(): print "<HTML>" __dtor__(): print "\n</HTML>" Class TITLE: Class HEAD: Class BODY: Class PHP: Class GetData: Class Init: // generator program Init myInit("This is my title") /* main body of code—see below */ Note that there was no need to write code to close off of the various tagged sections. For example, if something went wrong in generating the body of the web page, the correct terminating tags would all be generated. |
Using this same design approach, the body of the web page might contain a simple table like:
| <table
border="1" width="100%"> <tr> <td width="50%">Name1</td> <td width="50%">Addr1</td> </tr> <tr> <td width="50%">Name2</td> <td width="50%">Addr2</td> </tr> </table> |
Note the repeat of the row and cell tags. The code for generating this might look something like:
| Class TABLE: __ctor__(b="1",w="100%"): print "<TABLE " print 'border="',b,'"', 'width="',w,'"', '>' __dtor__(): print "\n</TABLE>" Class TBL_ROW: Class TBL_CELL: /* table generator loop */ TABLE t |
Notice three things. The definitions of TABLE, TBL_ROW and TBL_CELL can be in include files and can be used anywhere that tables are to be generated. Second, again there is no cleanup necessary for any of the objects, the constructor/destructor pairing does this for you. Lastly, while we are using anonymous instances of TBL_CELL, we need to create named (albeit dummy name) for TBL_ROW instances. This has to do with when the destructor is called. In the case of the TBL_ROW, we don't want the destructor called until the end of the while loop for each iteration over the rows. On the other hand, anonymous instances are usually destroyed at the end of the statement in which they appear.
However, this method still too dependent on the page layout — the presentation and the logic are too intertwined.
By now, most of you experience people will know a better method: using template files. This file contains most of the layout information in the form of tags and place markers for data values. Let us assume that the file table.tmpl file contains the template for the table mentioned earlier. It would look something like this:
| <table border=$TB
width=$TW> <tr> <td width=$CW1>$V1A</td> <td width=$CW2>$V!B</td> </tr> <tr> <td width=$CW1>$V2A</td> <td width=$CW2>$V2B</td> </tr> </table> |
There are now two issues here: finding and resolving embedded names (or place holders); and dealing with iterations. One approach is to rewrite the template as:
| <table
border=$TB width=$TW> <??foreach (x,y) in list($r)> <tr> <td width=$CW1>$x</td> <td width=$CW2>$y</td> </tr> <??endfor> </table> |
Notice also the reversion back to mixing code with presentation data. To get around this mixing of presentation and executable code, we must abstract the concept of generating a table. Let us say that we have a new TABLE class whose constructor looks like this:
| Class TABLE: __ctor__($COL_WIDTHS, $SELECT_STMT, $TB=1,$TW="100%"): /* table generation code */ __dtor__(): print "</TABLE>" /* use the object */ $q="select company, st from locations where rte = '$route';" TABLE t(("%30",), $q) |
In this fragment, a list of column widths and the select statement needed to generate the data are provided along with the default border and width for the table. Now we are ready to put it all together: templates, constructors/destructors, and page producers.
To produce a web page, we need a template file, a way of interpreting the template and a way of determining which interpreter to use; and we may also want to introduce a new construct into the language to make generating code easier for us. For example, we may define the token $! to represent an iterative call for all elements in a list so that the statement containing $! is repeated for each element in the list (I.e., it is a notation for the map function.). Thus, for each row of a table, the cells can be generated with one statement:
| <td>$!</td> |
Where $! is set equal to a row in the table returned by a select statement.
The page producer class now can look something like this:
| Class PgProd: __ctor__($template, $datasrc="", $interp="php"): /* constructor code */ __dtor__(): /* detructor code */ PgProd p1("index.tmpl") PgProd p2("prodlist.tmpl", "select * from prods") |
I have not elaborate on the contents of these pages, but you can see that the templates have most of the visual candy predefined, while the executable code fills in the relevant data. The page producers can also have more attributes. You can even have page producers inherit from one another or have them be embedded. For example, you might want to combine a table and a graphical representation page like so:
| Class
PgProdTable(PgProd): /* inherit from basic PgProd */ Class PgProdGraph(PgProd): /* also inherit from PgProd */ Class COMBODPP: __ctor__($tmpl1,$tmpl2,$data): $t1 = $tmpl1; $t2 = $tmpl2 $d = $data PgProdTable($t1,$d): /* produce table page */ PgProdGraph($t2,$d): /* produce graph of data */ $q="select * from sales;" COMBODPP cpp("salestab.tmpl", "graphtab.tmpl",$q) |
We are now using the best features of object oriented technology to simplify the production of arbitrarily complex web pages.
By Reg. Charney
Imagine a piece of software that has the beauty and timeless grace of a great symphony.
By symphonic beauty, I mean more than just sounding great, I mean that internally things fit together smoothly and compliment each other. I have always wanted to compose such a system. I realize that this may be hubris on my part—I might not have it in me. However, I am hoping some, perhaps many people have this talent.
However, before this can be done, we need to create a set of “tools” from which to build such symphonies. Even Beethoven and Mozart build on the work of others. So too, must we. Until recently, we talked about doing this using function libraries, APIs, OO, and reusable components. But evidence seems to refute the claims that these are all the tools we need to build beautiful systems. For example, even the best systems today, while presenting a beautiful face, are horror shows to maintain, extend, and debug.
Patterns may be the answer. It is still too early for us to have designed patterns for the ages, but image software that lasts 20, 50, 100+ years. It is possible. For example, software that controls spacecraft to the stars, monitoring software for nuclear waste dumps, humongous data bases cross-indexing the Web of 20+ years from now. Replacing such software will not be possible, only augmenting it will be a reasonable strategy. Such symphonic software will take on a life of its own and top-notch software practitioners will be arrangers of classic software just like now we have arrangers of music and the symphony itself will be the pattern.
The February meeting was our most successful one to date. We had standing room only. Bjarne’s presentation was one of the most interesting and valuable that I have heard him give.
The Joy of Patterns by Brandon Goldfedder, Addison-Wesley, ISBN: 0201657597
I read this book twice and still can't decide if I like it or not.
Brandon Goldfedder tries to teach the use of patterns in software development, but I feel there is depth missing. The subtitle “Using Patterns for Enterprise Development” is a bit misleading. The examples in the book have little to do with Enterprise development. The examples are Burger Shop, Black Jack and Product Configurator. Not exactly Enterprise topics, I'd say.
The book starts out by giving a short introduction to what patterns are and how they originated in the world of architecture. Then a small historical overview of object-oriented development discusses the transition from structured programming to encapsulation and component technologies. The next few chapters introduce some of the GOF patterns using the examples I mentioned. There is talk of how to use the pattern paradigm regardless of programming language, how to build a system from scratch using several patterns, and how patterns can benefit product maintenance.
Goldfedder's work has lots of big illustrations and diagrams and almost a third of it consists of source code printouts, which are not all that well commented. I liked the explanation of how the Decorator pattern can solve the problem of class hierarchy explosion, but I'm not sure I needed as many class diagrams to get it as there are printed.
The book is easy enough to read, and 170 pages is short enough to make you feel it's not an entire waste of time. Goldfedder's writing has its ups and downs. His attempts at humor fail for me most of the time.
Since I have not read any other introductory works on Patterns, and only used the GOF book as a reference, I don't know if there's anything better out there, but I strongly suspect there is.
You may learn something new, but I'm not sure I really did. If you have $30 to spare on a book that does an average job of explaining patterns without going to great depths, this might be it. However, if I had had to pay for this book myself, I'd feel disappointed now.
—Oluf Nissen
By Ali Çehreli
Fortunately the situation is positively less dull compared to the recent months. Once again, the jobs market is showing signs of improvement. This time it's different because Silicon Valley in general and software engineering in particular are behind (Figure 1).

After Reg.'s nice interjectory article of magazine page counts last month, we are back with the Silicon Valley job market figures.
I will have to delay the introduction of Windows XP for another couple of months. This is because of the difficulty in separating 'XP' in Extreme Programming from 'XP' in Windows XP. [1]
An interesting observation is in the Windows 2000 jobs. While it has been the only dropping platform (18%, Figure 2), it has also been the only platform with improving need for device driver skills (Figure 3). [2] I suspect, even though the job descriptions contain Windows 2000, the device drivers are actually needed for Windows XP.


[1] There is a similar problem with C and C++: just like people don't distinguish them as separate languages on their resumes, most search engines treat C and C++ as equivalent. While a series of questions starting with one as simple as "what does virtual mean" can easily translate 'C/C++' to 'C' on the resumes, identifying the actually required language skills for the jobs is really difficult without reading the job descriptions.
[2] Please note that these two figures do not compare the trendiness of different platforms. They chart the history of individual platforms on the same graph. For example, 0.5 for a particular platform would mean that the total jobs for that platform are 50% less compared to a specific date in the past (01/23/00 for platform jobs, and 09/28/00 for device driver jobs).