"There are two ways of constructing a software design; one way is to make it so simple that there
are obviously no deficiences, and the other way is to make it so complicated that there are no
obvious deficiencies. The first method is far more difficult."
- C.A.R.Hoare
.. outline showing the main features of something to be executed
a plan or protocol for carrying out or accomplishing something ..
I often work on designs early in the morning, coffee cup in hand - scribbling notes and diagrams on
sheets of paper, many, at first, get crumpled and thrown away, but soon there's a small stack of papers,
perhaps five or six, convincing me that the project is sensible, do-able, and has a clear starting point.
Implementing code is a consuming mental task. We think about the context, semantics, and syntax of each
line of code we write. That doesn't leave too many mental cycles for building a well structured
program that is quick, robust, elegant, and easy to use.
That's why project design begins before coding, again in breaks between coding sprints, and finally as
a post-mortem process to get documentation user-ready.
Program Design Concept:
Concept is the starting point for design. Concept development may precede creation
of a specification governing program build. It focuses on users and uses, program structure,
and issues.
Users and uses considers who the users are and what they need from the program. Exploring this thoughtfully
could make the difference between a satisfactory outcome and creation of "shelfware" that no one
wants to use. These considerations help to specify program operations.
Structure deals with what top level parts are needed to build the program. This doesn't get into a lot
of detail, but should identify program phases and data flow.
Issues lay out all the things we can think of that may affect program function or ease of
construction, use, and maintenance.
Design:
The purpose of design is to think about structure and process strategies before diving into coding.
We want our designs to:
Explain, in brief, unambiguous, and relatively complete fashion, the project goals, structure,
processing concepts, and delivered information.
Extract away all of the details of platform and language so that our ideas take precedence.
Be small and simple enough that team members will acturally read the document.
Try to implement the
"Goldilocks principle" - not to much,
not to little, just enough to guide your implementation.
It is important that the description of a design be pragmatic and concrete. No vague statements like "optimum"
or "user-friendly" Those words provide almost no guidance for an implementation. Prefer statements like
"program options are supplied with named command line arguments of the form '/P .' to specify a search path is to
start at the current working directory".
Design Evolution:
None of us has perfect foresight. It is not uncommon that a good design evolves a bit as it is implemented.
We think of better ways to process some data or decide that the structure needs refactoring to add a part or
two that will handle some processing that turned out to be more complex than expected.
Evolutionary development is a powerful way to be effective, both for individuals and teams. The agile movement
has shown how well that can work - if applied with some wisdom.
That means that design will happen repeatedly, once for each evolutionary step. When used in this enviroment,
each design phase is relatively small, focused, and results in brief documents. Each phase will probably build
on the document from the preceding phase. This reuse has the same benefits as code reuse.
The evolutionary process is a good way to manage this extension of design.
Design of a Software Design Document:
A design document represents a program design, providing:
A brief specification, if one doesn't already exist. A one line statement of what the program does,
then pre-conditions: the program's environment and inputs, post-conditions:
a list of the things it must provide.
Use: how will users interact with the program: what inputs do they supply, how do they interpret program
results - the program is, after all, going to supply information, not raw data - right?
A list of tasks the program must execute, more or less in the order they occur during operation.
Each task becomes a candidate part in the program's structure. Some will become parts, some may not.
A structure consisting of a network of named parts, where each part has a stated responsibility. Parts might
be functions, or classes, or packages.
One or more diagrams showing the structural relationships, e.g., a call stack diagram, or class diagram,
or package diagram, or some combination.
A description of the major processing parts. If you help your friend work on her motorcycle you might
describe in words and a diagram how to clean and adjust the bike's carburetor. You do the same
thing here, perhaps briefly describing a directory tree traversal or messaging process. Pseudo-code may
work well for this.
A description of error handling. What errors may occur? How will they be handled?
Testing description: test name, description, procedure.
Thoughts about future expansions, not implemented, but which may be in future versions. That could lead us
in a design direction that we would not otherwise follow.
Very brief outline of a prototype developed to verify feasibility of one or more operations.
What do you mean small and simple! There's a lot of steps here. Look's like
Goldilocks slept in today.
Robin Mathew said "Design is where science and art break even". Here is where the art comes in. Speaking
and writing in clear, simple, brief statements. If in doubt, throw it out!
If a project is small - perhaps a week's work, then a small design is appropriate; just enough to
think about processing and use. Some of the steps, above, would be unnecessary. Big projects with
several developers working for a month or more will likely address each of the steps described here.
"Put it before them briefly so they will read it, clearly so they will appreciate it, picturesquely
so they will remember it and, above all, accurately so they will be guided by its light."
- Joseph Pulitzer, Editor
Why Write one:
Should you write a design document for every project you build. No! If the project is relatively small, in
a domain in your comfort zone, and similar to things you've built before, writing a design document is
probably a waste of time.
Write a document when:
The project is relatively large with some complex processing. Write a document to help you think
through processing and communication. When the implementation is complete, the document will live
on as a maintenance manual.
The project has more than one developer. You need to name parts, specify interfaces, data flow, and
test processes so that work can be partitioned for the team, everyone knows their obligations, and
the means of communication are clear.
User interactions with the program are complex or unspecified. You need to define the user interactions,
think about how to make them as simple and intuitive as practical, and partition program parts to allow
changes to input and output processing without major surgery to the other parts. The document will live
on, after program completion, as a user's manual.
Remember: a design document is not some large ediface. It should be small, clear, and readable. Documents
for your own use might be two or three sheets of paper. For sharing with others, the document may need more
than that, but keep it short and simple - the KISS principle.
Building a Design:
You might scribble ideas on a few pieces of paper, then build your design by writing the design document, thinking
and creating as you go.
One of the best ways to think clearly about some complex topic is to try to write about it. Expository
writing is very similar to developing code. You start with an idea, then describe it, bound by the
syntax, context and conventions of your topic. Essentially writing is coding ideas rather than functions
and classes. Same issues of connections, process, and structure.
Sometimes I have written design documentation after the implementation is complete - providing information for
others. I've often regretted not working through the design process first. I've found
things I wish I had done differently. Sometimes I am quite dissatisfied with the code structure or its
processing mechanisms or its user interface. While that post-mortem is useful, it is also dissapointing to find
that you could have built so much better.
Presenting Designs:
Let's assume you present using slides. Allow 2 minutes per slide (that is optimistic). So a ten minute
presentation means you will have 5 slides including your opening and closing slides.
Clearly you have to cherry-pick the design document, selecting small pieces of of each design topic as
representative of your design. You may have to eliminate some of the design topics altogether. Pick those
with the most impact for your audience.
Be very careful to stick to the script. Don't ramble, use one strong statement per topic with perhaps
a very few words of elaboration.
Finally, talk to the audience - don't read your slides. The slides are there for your audience and to keep you
on track. Remember, you know more about your presentation topic than the audience - trust me, you do!
So don't be terrified :-)
Epilogue:
We want to make our programs elegant and simple, make their intents clear, and make them quick and reliable.
That is most likely to happen if we think first about design.