1
=========================================
2
How to go about writing a web application
3
=========================================
5
-- Steve Alexander <steve@z3u.com>
11
This document presents an approach to constructing web applications,
12
emphasising well-designed user interaction.
14
In summary, we write a web application by
16
1. Design the database that lies behind the web application
17
- Entity relationship models
19
2. Design the web application's user interface
20
- Table of URLs (see later)
21
- Page tempate mock-ups
22
3. Write the Interfaces that the application will use to access the database
24
4. Write the code and templates of the application
27
- application components
29
Of course, this isn't a completely linear process. Steps may be carried out
30
in parallel, and ongoing work in each step will feed into the other steps.
32
So that we can make rapid progress, and learn about the application as early
33
as possible, we should do steps 2, 3 and 4 focusing on just a few URLs at
34
a time (say, five or so). Then, when those are finished, we can make any
35
necessary changes to the database model, and then repeat steps 2, 3 and 4
36
with some new URLs and new application functionality.
40
Web application architecture
41
----------------------------
43
For the purposes of this document, a web application is put together as
46
+--------------------------------------------------------------------------+
47
| { Amorphous cloud of URLs } |
48
| URLS { /rosetta/foo/bar/baz.html } |
50
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
52
| PRESENTATION { Views Templates |
53
| { Traversal Support classes |
55
| WEB APP ------------------------------------------------- Interfaces |
57
| APPLICATION { Utilities Components |
58
| COMPONENTS { Adapters |
61
| LIBRARIES { Python standard library |
64
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
66
| DATABASE relations, fields, constraints |
67
+--------------------------------------------------------------------------+
69
The boundaries of our web application are URLs at the top and the database
70
at the bottom. So, we must carefully define these things that lie at the
71
boundaries, so that we can work out what must go in the middle.
76
URLs are the boundary between the web application and web browsers. When you
77
point a web browser at a URL, you'll get one of the following:
84
- "unauthorized" error
86
We'll be mostly concerned with pages, forms and redirects. We'll be concerned
87
with image and other data only when they are "managed content" and not just
88
part of the skin of the site. The photograph of a member of the site is an
89
example of managed content: it is stored in the database and may be
90
manipulated through using the application. CSS files, javascript files,
91
icons and logos are typically elements that make up the "skin" of the
92
application, and are not managed through the application.
94
Another example of image or other data that is managed content is if we want
95
to allow users to download a .po or .pot file of translations.
97
Forms are rendered in HTML and will typically be "self-posting forms". That
98
is, the address posted to when the [submit] button is pressed will be the
99
same as the address the page was got from. This allows browsers' bookmarks
100
to work properly, allows us to straightforwardly validate data entered into
101
the form, and keeps the URL space neat.
103
The "not found" error is the familiar "404 Not Found" given when someone
104
tries to access a URL that is not known by our system.
106
An "unauthorized" error means that accessing the given URL requires some
107
authentication. The browser will prompt the user to provide some additional
108
authentication. Alternatively, if we use other login schemes than HTTP Basic
109
or HTTP Digest, then the web application may present a login form to the
112
A "redirect" causes the browser to immediately fetch a different URL. This
113
process is usually not noticed by the user.
119
We need to construct a table describing the URLs used in our application. We
120
won't bother about the protocol part or any leading path segments of the URL.
121
In the table below, we'll assume all URLs start http://example.com/rosetta/...
123
The table has the following columns
125
- URL: The rest of the URL after /rosetta. For clarity, we'll start it with
126
a "./". So, the rosetta application's main page might be "./index.html".
127
If this table is written in HTML, this may be a link to a mock-up HTML page
128
showing what will be found at that URL.
130
- Default: For application components, the default page to use. More about
133
- Type: This is one of "app component", "page", "form", "redirect", "data"
135
- Description: A textual description of what is found at this URL.
136
This may be a link to further information about the functioning of that
137
page, form validation constraints, and so on.
139
When you get an App Component at a particular URL, what does that mean? At
140
certain points in our URL space, we want to expose a set of related
141
functionality under a particular URL. For example, the URL
142
"./projects/mozilla/show-teams" might show the teams working on the Mozilla
143
project, while "./projects/mozilla/translations" might show the translations
144
of the mozilla project. Users of the system will come to understand that
145
things related to Mozilla are to be found at URLs starting with
146
"./projects/mozilla". We want to present some page at "./projects/mozilla".
147
Rather than make a special "no name" page for this, we choose one of the
148
other pages that we want to return. Mozilla is a Project. So, if the
149
default page for a Project is "translations", then going to
150
"./projects/mozilla" will return the same page as
151
"./projects/mozilla/translations". The usual default page is "index.html".
154
Here's an example of a table for the Rosetta project::
156
URL Default Type Description
158
./ index.html app component The rosetta application
160
./index.html page Initial navigation page
162
./intro.html page Introductory page
164
./signup.html form Allows a new user to
165
register with the system.
167
./projects index.html app component Collection of rosetta
170
./projects/index.html form Shows ways to search
173
./projects/$PROJECT translations app component A particular project
174
$PROJECT is the name of
175
the project. See key below.
177
./projects/$PROJECT/translations page Shows all translations
183
$PROJECT The name of the project. This is the name attribute of
184
the IProject interface, or the name field in the Project
185
relation. Case is not significant, and is normalized to
186
lower-case in the UI. Examples: 'mozilla', 'gtk+'.
188
We can use the URL table for simple automated functional testing of the web
189
application, given some suitable $VAR substitutions.
192
Structure of a web application URL
193
----------------------------------
195
We need to know what types of things are at a particular URL. Here's an
196
example of a typical URL in a web application. This time, I've included
197
the "rosetta" path segment at the root.
199
/rosetta/projects/$PACKAGENAME/teams/$TEAM/add-member.html
201
| | | | | page to add a new member
202
| | | | Name of a particular team "22"
203
| | | The teams working on this project
204
| | A particular project name, such as "mozilla"
205
| Collection of projects that can be queried
206
The rosetta application
212
* Make your URLs from lower-case letters, numbers, '-' and '+'.
214
* Avoid '_', capital letters, other symbols.
215
Using these things makes the URL harder to read out over the phone or
216
write down unambiguously.
218
* When you have a collection of things, such as people or projects, use
219
a plural noun for that part of the URL. For example, "./projects".
221
* Consider using "+" as the last URL segment for the URL that adds things
222
to a collection. For example, "./projects/+" to add a new project.
224
* Where possible, use self-posting forms. So, you would go to the URL
225
"./projects/+" to get a form asking you for the information needed to
226
add a new project. When you submit the form, it POSTs to the same
227
URL. If the provided informaiton is invalid, you'll get the form back
228
with an error message. Otherwise, you'll get a "success" message, or be
229
redirected to the next page in the workflow.
233
Development iterations
234
----------------------
236
When you're developing a new system, don't try to write the whole table of
237
URLs at once. Instead, we can work in iterative cycles, designing pages
238
and URLs, and making these work in software. That way, we can learn earlier
239
on if the URLs and pages we want will actually work in practice.
241
Here's the overall process of developing the application.
246
1. Lay out the total functionality of the system, and divide it into a number
248
2. Pick the next iteration. Go through the Iteration Process described below.
249
3. Review / refactor the specification for previous iterations based on what
250
we learned during this iteration.
251
4. Refactor the whole application implemented so far to match the refactored
254
Each iteration (that is, step 2 above) looks like this.
259
1. Write the URLs required for this iteration into the URLs table.
260
Ideally, there should be 3 to 7 URLs in each iteration.
261
2. Document the functionality required for each page.
262
3. Produce page template mockups.
263
4. Implement the functionality, using stub application components rather
264
than real application components.
265
5. Connect the functionality to the real database, by replacing the stubs
266
with real application components.
269
I will note that these processes are just guidelines on how to go about writing
270
the software. You might choose to prototype the application in order to learn
271
about what URLs are required for some tricky interaction. Or, you might decide
272
to write two iterations' worth of URLs into the URLs table all at once, but
273
then implement them in two iterations. The important thing is to understand
274
where you are in this process, and why you are doing what you are doing at any
277
Keep the iterations short!
284
The way the user interface looks in a web browser. The elements of this
285
user interface, including CSS, images and an overall site template.
287
It is possible to provide multiple skins to the same web application,
288
for example a simple one and a very complex one.
291
Something that is made available at a particular URL is said to be
294
Presentation component:
295
Some software that interacts with the browser's request and returns
296
information to the browser. This is typically a page template or a
297
page template plus a supporting class.
299
Other presentation components are traversers, which know what to do
300
when further path segments are given in a URL; and resources, which
301
are CSS files, javascript files, logos, icons, etc.
303
Application component:
304
An object that represents application functionality, but not presentation
305
functionality. It should have a well-defined interface so that different
306
implementations of a given application component can be presented by
307
the same presentation components.
310
An object that has clearly defined interfaces.
312
These interfaces may represent what it offers, or what it requires in
316
A component that is looked up by the interface that it provides.
319
A component that knows how to use a particular interface in order to
320
provide a different interface.
323
A software-readable definition of an API provided by some object.
326
A kind of presentation component that provides a representation of
327
some other component.
329
Browser presentation:
330
Presentation intended for a web browser, as distinct from a presentation
331
intended for XML-RPC or webdav. Or even email.
333
Non-published {view,resource}:
334
A {view,resource} that is used by other presentation components, but
335
that is not itself addressable by a URL.
338
An HTML document returned to a browser in response to a GET or POST
342
A page that contains HTML form elements and at least one "submit"
346
A form that's "action URL" is the same address that it was loaded from.
347
So, a form that was loaded from "./projects/+" would start::
349
<form action="http://example.com/rosetta/projects/+" method="POST">
352
# arch-tag: cf2cb34d-52a5-4615-b135-439d70f43f36