These notes are based in part on my more detailed 2503ICT Web Programming notes.
Requirements analysis depends on the context:
Design: Textual interface design, graphical interaction design using transition diagrams.
Implementation: URL design, model design, view design, template design, form design.
Software engineering: prepare for modification and extension.
First, recognise that the best Web applications are personalised (page views are tailored to individual users), collaborative (users provide much of the content), and community-based (users with common interests may collaborate independently of other users).
Second, recognise that for any Web application to survive, it will need to be modified and extended continually over time. The ability to do this requires planning in the design and implementation stages.
Third, almost no-one is good at organisational analysis, programming and graphics design, so Web application development must be a team effort.
Designing the data model, preparing for modification and extension (models.py).
Design the URL patterns that initiate the transactions (urls.py).
Design the transactions: queries, insertions, updates, deletions, transfers, etc. (views.py).
Design the page views, links and forms that indirectly initiate transactions (via URLs), and show the results of transactions (forms.py, /templates/). (Avoid unnecessary form elements.)
Design the page transitions. Which page should be shown after the transaction initiated by submitting each form. This is suprisingly difficult. Document your design as a page transition diagram.
Design the unit tests to ensure the implementation is consistent with the design.
Perform preliminary usability testing. Show your (paper) design to potential users; ask them to perform typical tasks; observe their difficulties; consider their suggestions.
Select the tools:
Implement the design:
Transitions diagrams (sometimes called interaction diagrams) are important for both specification and design. A transition diagram is a directed graph with annotations on (some) edges. The nodes of the diagram describe page views and actions (that do not correspond to page views) in the application. Nodes should be labelled by verbs, e.g., show all users, enter new user details, add new user. The edges describe transitions between nodes. The start or home node should be identified.
Transition diagrams are important for specification. Developers can use a diagram to check that all requirements have been considered and that all required transactions have been identified, and that all transitions are appropriate.
A transition diagram may be implemented (using Django) either (1) with a separate view for each node or (2) by a single (large) view (with parameters) that implements all nodes. Each approach has its pros and cons, but personally I find an implementation with many small views easier to manage. To support the design, nodes may be annotated with their URL pattern (and corresponding view). Edges may be annotated with the variables whose values are passed in the corresponding page transition. Other annotations may also be useful. Developers can use the annotated diagram as a guide to the actual implementation.
If a template system is used, a separate template file will probably be associated with each page view in the diagram.
It's important to distinguish between nodes that describe page views and nodes that describe actions only. Django views that implement action nodes must perform an HTTP redirection after each database update to avoid the reload-redo problem.
Examples of transition diagrams are shown below.
You can read more about these examples in the 2503ICT Web Programming lectures.
Obviously, these examples have not (yet) been adapted to a Django context.
See the 2503ICT Web Programming lectures for some basic principles of user interface design and implementation.
(These notes did not need to be changed much in adapting them from PHP to Django.)
Python (and hence Django) provides a powerful framework for writing and running unit tests. See Testing Django applications.
The advantage of writing a comprehensive suite of unit tests for each app is that the tests can easily be run as a group after every change to the app to ensure that the app still behaves as required. It is normal to write one or more unit tests for each view in an app.
The file tests.py created in each app includes a very simple unit test example.
The Django testing framework allows developers to perform the following tests in each project:
Django tests are performed on a temporary database (not the working database), which can easily be populated with initial data stored in an app's fixtures directory.
An initial set of unit tests are provided in the files entries/tests.py of the initial guestbook application and items/tests.py of the list-detail application. Both applications use fixtures for initialising the database (for production and testing).
One test case in the file items/tests.py is the following.
from django.test import TestCase # Assumes the database contains an item with id=1 and title="Catch 22". class DetailTest(TestCase): def test_detail(self): """Tests that get requests for the URL /items/n/ behave correctly.""" response = self.client.get('/items/1/') self.assertTemplateUsed(response, 'detail.html') self.assertEqual(response.status_code, 200) item = response.context['item'] self.assertEqual(item.id, 1) self.assertEqual(item.title, "Catch 22") self.assertTrue(len(response.content) > 0)
Generally, it seems to be convenient to write a test case for each URL pattern. See Assertions for a useful list of tests that can be performed.
To be extended...?
Suggestions for design, implementation, testing and debugging techniques are invited.