|
Tech Talk
Web Programming
Editorial
Music and Patterns
Thanks to Bjarne
Book Reviews
The Joy of Patterns
Trends
Silicon Valley is behind
|
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:
__ctor__(string s): print
"<TITLE>",s,"</TITLE>"
Class HEAD:
__ctor__(string s): print "<HEAD>"
TITLE(s)
__dtor__(): print "</HEAD>"
Class BODY:
__ctor__(): print "<BODY>"
__dtor__(): print "\n</BODY>
Class PHP:
__ctor__(): print "<?PHP ",
__dtor__(): print "\n?>"
Class GetData:
__ctor__():
print 'require("header.php");
$q="select company, st from
locations where rte='$route';"
$r=mysql_query(q);'
Class Init:
string s
__ctor__(string ss): s = ss
HTML h
HEAD hd(s)
BODY b
GetData d;
// 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:
__ctor__(): print "<TR>"
__dtor__(): print "\n</TR>"
Class TBL_CELL:
__ctor__(string s,w): print '<TD
width="',w,'">', s, '</TD>'
__ctor__(string s): print '<TD>'
__dtor__(): print "</TD>"
/* table generator loop */
TABLE t
while(list($company,$st) = fetch_row($r)
TBL_ROW t
TBL_CELL($company)
TBL_CELL($st,"70%") |
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:
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.


References
[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).
|