Small and Simple Web Applications - the Friki Way (Part 1)Frank Carver, February 2003
Abstract
This article is the first of a series which laments the bloated and
unmaintainable state of so many J2EE web applications and looks at ways to keep
web applications small, simple and flexible. The series uses the author's Friki software as a case study, and
discusses ways to design and build a powerful, flexible and usable web
application in less space than a typical gif image.
This article introduces some problems of J2EE applications. It also gives
some requirements for a wiki-like application. First steps are taken in the
design of the application, with a focus on deferring storage decisions and
deciding on a technology for dynamically producing web pages.
Introduction
Java is extremely popular for developing server-based web applications. Lots
of big name web sites use Java technology to drive their customer interactions.
Any Java developers' web site is full of material about J2EE, JSP, EJB, JMS,
JNDI, JDBC, XML, SOAP and many more. It's an alphabet soup of abbreviations and
jargon. New technologies are added to Java faster than we can keep up. Making
sense of it all and trying to use the best of each bit could drive anyone
crazy.
Sure, all this stuff is powerful, but sometimes it pays to stop, calm down,
and think for a while.
- If it is not useful or necessary, free yourself from imagining that you
need to make it.
- If it is useful and necessary, free yourself from imagining that you need
to enhance it by adding what is not an integral part of its usefulness or
necessity.
- And finally: If it is both useful and necessary and you can recognize and
eliminate what is not essential, then go ahead and make it as beautifully as
you can.
The above is a quote from Shaker
Built: The Form and Function of Shaker Architecture by Paul Rocheleau and
June Sprigg. You can read a little more about this quote, and this book
(appropriately enough) on Ward
Cunningham's Wiki.
I have worked on many server-side Java applications in my years as a
consultant, and vanishingly few of them exhibited any of the virtues of that
simple Shaker quote. I've seen applications with a maze of twisty JSP pages, all
(almost) alike. I've seen business data squeezed in and out of XML just because
it seemed "cool". I've seen software which only works on old and unsupported
versions of application servers and databases. I've seen software where none of
the developers dared touch the existing code for fear it might break something.
I've seen software where changing a text label on a web page required a database
rebuild. I've seen a project running on six high-spec Sun workstations and
needing a team of over 20 developers, testers and managers to maintain it
switched off and replaced by a spreadsheet!
I don't want to build unmaintainable monsters like this, and I hope you don't
either. But how can we learn to do things right? Surely there are some
well-thought-out applications to study? Sad as it may be, there are very few,
particularly if we are interested in Java web applications.
In this article I will use one of my own applications (Friki) as a case study. I don't claim
that it is perfect, and I actively encourage anyone reading this to look for
ways to simplify things. I also encourage you all to look for other examples of
web applications which do a useful job in a simple, small and flexible way.
About Friki
Friki (pronounced "freaky") is "Frank's Wiki". A "Wiki" is a
web site, where any user can create new pages, edit existing pages,
create links, and search the site whenever they want to. This may seem weird,
but it can be an extremely powerful and flexible way to take notes, collaborate
and work on the web.
All you need to view and edit pages is the browser you are using to read
this. Every page on a Wiki has some sort of "edit button", which shows the text
of the page in an edit box, and allows you to change it and re-save the new
version. Once you have created or edited some pages, most Wikis have a built-in
"search" facility to find them. Making links and creating pages is as easy as
typing the name of the (new or old) page while editing. You don't need to know
HTML, Java, XML or any of the other buzzwords to use a Wiki. In most cases you
can just type paragraphs of text, and the software will do its best to lay it
out for you.
Friki is a pure Java web application which can be installed as simply as
dropping "friki.war" into any modern servlet container or Java application
server. Strictly that means anything which implements version 2.3 or later of
the Java Servlet API. Friki is small, fast and flexible. The complete web
application archive (war) file is just 66k bytes, and needs nothing apart from a
servlet container to run.
Pre compiled web applications, source code and other documentation for Friki
is available from http://www.efsol.com/. The
original Wiki implementation by Ward Cunningham is in Perl and hosted at http://c2.com/cgi/wiki. For more information I
highly recommend the definitive book: The Wiki Way
- Quick Collaboration on the Web by Bo Leuf and Ward Cunningham. ISBN
0-201-71499-X.
Let's Make One
To show the design techniques which can help us keep things small, simple and
flexibile, let's work through the process of designing and building a Wiki
(which we'll call "Friki").
The most important part of a Wiki is the collection of pages. Pages are where
people put their information, notes or opinions. Pages and their content are
what makes a Wiki come alive! Such a page collection must support a few basic
operations: The system needs to get the content of a named page to display it,
save some new content to a named page, create a new page, and search all the
pages for some supplied text or pattern. Although not strictly necessary, most
Wikis also support a "does this page exist?" operation, so that an indicator can
be shown to users if a linked page has no text yet.
If you are like me, your mind is already fizzing with ideas how to implement
such a page store -- maybe a JDBC database, or perhaps a JNDI repository, even a
high-performance distributed caching package you have recently read
about....
Stop! That is the way to a bloated, multi-megabyte, undeployable,
unmaintainable nightmare.
Instead, I suggest we defer the implementation details of how to store pages.
Instead, we'll create an interface (a special type of Java class), with
the operations we need, and use that. When we actually need to store some pages,
we can use the simplest implementation we can get away with, as long as it
implements this interface. Later, if we ever do need more performance,
scalability or distributability, we just need to code a slightly more complex
implementation of the same simple interface. Eventually, this approach might let
us automatically build several specific versions of the software for
different situations, each containing only what is actually needed and used.
package com.efsol.friki;
import java.util.Iterator;
public interface PageRepository
{
public Page get(String name);
public void put(String name, Page page);
public boolean contains(String name);
public Iterator matchingPageNames(String pattern);
}
There are a few things to note about this interface:
- It's short. One of the many causes of bloated code is having to write lots
of useless methods, just because they are required by an interface. If you
have ever tried to write a class which implements java.util.Map, you'll
understand what I mean. So be ruthless with what you don't put in an
interface, and consider splitting methods into more than one interface
wherever possible.
- It has a simple, descriptive but abstract name ("PageRepository"). It's
easy to imagine classes implementing this interface, and to recognize the sort
of names they might have: DatabasePageRepository,
FilePageRepository, etc.
- We haven't decided how to represent a page and its contents yet, so we
have deferred the decision by just inventing a class name for it.
- It only uses classes from the core Java APIs and this application. By all
means use code from other sources when you are implementing an
interface, but using external classes in an interface is extremely dangerous
and can end up forcing your application to include some large jar file which
it never even uses!
- Design doesn't stop just because we have started writing code. This
interface may change or even disappear before any code is released. Don't
worry. It has expressed what we know so far in simple, usable terms and
enabled us to move on to design other parts of the system.
The next most important part of a Wiki is the user interface. We have already
decided that we will be using a web interface, so it's pretty obvious that we
need at least some way of producing HTML to send to a browser. What's not
obvious is the best way to do this.
Conventional Java "wisdom" would indicate that this is a natural fit for JSP.
Indeed, I did try an attempt at this using JSP, but found far too many problems.
The main problems with JSP stem from the way that pages are compiled by the
server after deployment (the rest of the code is compiled much earlier on the
development machine). To run even the simplest common-sense validity check on a
JSP can often involve building a war file, transferring the war file to the
server machine, deleting an old directory structure, restarting the server,
waiting for the server to expand the war file, using a browser to navigate to
the page being tested (pausing for all intermediate pages to be compiled and
loaded as we go) and eventually attempting to run the page. Only to see it fail
with a simple syntax error in an embedded script. Yuck!
Testing JSPs is hard and slow. Debugging JSPs is hard and slow. Hard to test
and debug means hard to change and hard to keep simple. If we are going to use
JSP, we need to get all that code out of the pages and into real Java which can
be compiled and tested before it is deployed.
In an attempt to solve this problem, the J2EE jargon machine provides "custom
tag libraries", or "taglibs". Taglibs are a way of formalizing JSP scripts and
referring to them using XML syntax in the JSP pages. For each script you would
have put in the page, you create a class which implements an interface or
extends a supplied base class, then make a method in your new class containing
what you would have put in the script, then describe your new class in 10-20
lines of XML or so in a "TLD" file, put the "TLD" file in the right place, then
make sure the application "web.xml" configuration refers to the TLD file. Does
that sound easy, simple, or error-free? It isn't.
The latest enhancement added to JSP is JSTL, a "standard" tag library which
is provided by the container, and you just need to link in to your "web.xml".
Using JSTL can simplify the use of tags a bit; sometimes you can use the
provided tags instead of writing your own. Taglibs can definitely help reduce
some sorts of JSP problems. But maybe if you didn't use JSP, you wouldn't have
these problems in the first place!
So, JSP seems problematic. But what other implementation choices are there?
JSP is usually contrasted against a beginners' approach to server-side code:
embedding random fragments of HTML all through some huge servlet. In this case,
the comparisons are right, even JSP is better than that! Imagine how slow and
cumbersome things would be if you had to edit, recompile and redeploy the whole
application every time you made a tiny change to the HTML.
Happily, there is another alternative. One that seems strangely absent from
the J2EE examples. It's called "templates", and is actually very simple. In
essence, a template is just a file with some "tokens" in it. Before the file is
shown to the user, the "tokens" are replaced with real values. No compilation,
no messing about.
For maximum flexibility, I like to allow web pages to be designed, produced
and viewed using whatever tool the designer is most happy with. That may be
Dreamweaver, it may be Notepad or Emacs. For this to work, we must be able to
use "tokens" which don't get in the way of the text of the page. That means no
"pseudo-html" (as used by JSP, Zope and FreeMarker). I reckon there aren't many
"~" characters in most web pages, so let's use that as a way to indicate our
tokens, at least for the moment.
In the case of Friki, all we really need is one token for the page content
and one for the page title. To keep things simple, we'll use ~title~ for the
page title, and ~content~ for the content. A very simple example web page using
this format might look like:
<html><head><title>Friki: ~title~</title><head>
<body>
<h2>~title~</h2>
~content~
<hr width='100%'>
<a href='edit?~title~'>edit this page</a>
</body>
</html>
I hope you can see just how easy that is. You can create and edit such HTML
with any tool which can work with basic web pages. No fancy support for weird
formats needed.
How are We Doing?
Well, we haven't made a Wiki yet! So far we have an interface which defines
the API for a page repository, and an example HTML page with tokens for viewing
page contents. This may not seem like much, but if we were working in a team,
we'd already be able to start working three times as fast. One person could make
the page repository, another could design some web pages, and another could
carry on thinking about servlets and template processing and stuff. This is
important, we've done just enough design to split off some achievable
tasks and get productive straight away.
Next session we'll go into more details about how to make our own very
lightweight template "engine" to expand these templates into web pages, and how
to get some page content to put in them. In the meanwhile, to see what you can
do with "full fat" templating software, you might enjoy looking at WebMacro and Velocity. Remember :-
don't just take their word for it; it's your job to keep software small, simple
and flexible.
Return to Top
|