The purpose of the design document is to be the guide for someone who needs to understand the code to maintain it, extend it, or re-use parts of it. While "all of the information" is in the code, the concepts that underlie it are lost in the details. Consider this document a tutorial for your code. While it is true that the reader of the document will be familiar with basic programming and object-oriented concepts, that is all that you can assume. Do not assume a knowledge of the domain of the application. (How good was your understanding when you started the project?) Consider as a driving use case that you hand this document to a new developer with a specific task to accomplish. Will they have the tools to accomplish it in a reasonable time?
In the first two sections, you are more apt to find that graphical representation helps in the understanding, but in the later sections, you will probably find that text will work fine.
Specific elements to be included in the design document are:
This is the starting point for the reader of the document. Basically, here you will put an expanded and final version of your architecture diagram. Perhaps more boxes, more arrows... more detail now that the system is built and the foggy parts have cleared from your first architecture diagram. As before, it is a high-level summary of the technical structure, in that not every module and every detail will be represented. But you should be able to put in a touch more detail than the first time around. Your goal is to make a diagram that conveys as clear a representation of the system structure as possible; this means a balance -- show as much structure as you can in a compact space (one "diagram") without swamping understanding with complexity.
This section has three components that together give different views of the model defined in the architecture. The terminology used here is not object-oriented because not all class projects are necessarily OO. If your project is OO, feel free to use the OO terminology (like "class" for "module").
This is the next level of decomposition from the architecture. It should flow from the architecture and relate the components, but not define any of the components completely. If you are extending other people's code, you need to explain how pieces relate, but do not need to detail code that you have not written or modified. That's what the next two sections do!
For each module, you now will describe its specifics, including the interfaces, details of decomposition, and key algorithms. If this is a class, you will define its attributes and their types as well as all of the associated methods. You need to describe what functions the methods are doing and a natural language explanation of the attributes. In addition, if there are identifiable invariants, pre- or post-conditions of the methods, they should be documented here. In addition this is the place to define any of the key algorithms that you use. If you are using a standard routine or data structure (e.g., a binary tree), you do not need to do more than state that fact. You should be using a document generator like Javadoc. I do not expect anyone to be creating this section completely manually. A reference to the generated document is sufficient.
For any file or database, a complete definition of the format needs to be included. The definition should include both the format and use of each field within the application. If there are constraints on fields (such as "number_of_frammitzs must be >= 0"), they should be included. The relationship of individual fields (such as "field8 must always be between 0 and the value of field4", or "speed will only have a value greater than 0 if mobile is true") are also defined here. If there is no external data associated with your application, this section is not needed. Again a reference to a tool-generated description of a database can be used and augmented as needed.
This is the place to document any decisions that you made that effected the overall design of the system that you have been capturing on your website. Any dependencies that the application has should be explicitly stated here and the reason for that dependency explained. Decisions about things that you chose not to do are as important as those that you chose to do.
In addition, consider this the repository of any other information that will be helpful to the next developer.
Consider this the one document that survives for the developer. It should include references to the other formal deliverables: the functional spec, user manuals, and the test plan, as well a pointer to the code repository.