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