Steve Mushero line
Technology Advisor for Startups and Investors

About Steve





Developing Software -> Design

Formal Design Process

The formal design process generally occurs after a functional specification is written and you know what you are building.  While it's possible and often useful to play with designs and prototypes before everything is known, the devil is in the details and it's important to have an entire picture before carrying out hard core design.

The actual design process can vary greatly, depending on the structure and purpose of the system; for instance, building J2EE web applications can be quite different than assembler kernel modules.

A Group Project

Good design is a group project, especially at the system and architecture level.  This group includes QA and sometimes other groups who have a significant stake in how things get developed.  Most companies forget to include QA or Support and end up with designs that lack basic features needed to support the efforts of those groups.  This is especially true of QA's role, as many designs are very difficult to test; modest changes at the design stage can vastly improve the quality of the system.

Basic Architecture & Technologies

Next, decide on the basic structure of the system and the general technologies to be employed.  For instance, is this a web-based system using J2EE on application servers, or is it a COBOL middle-ware system to run on Windows NT.  These choices, which should not be made lightly, go a long way in determining the design approaches used throughout the process.

Architecture & Logical Modules

Now, look at how the system might be put together (everything is still at the trial stage at this point), including some listings of obvious system modules and how they might fit together.  Pay attention to how data and events will flow in and out of the system, and between modules.  Good design generally dictates a modular (and probably object-oriented) architecture, so figure out how this relates to your system.

More Detail

Once you make a single pass at modularization, you should begin to have some sense of the scope and structure of the system.  Next, dive down another level or two in discussing various aspects of the system, including basic data objects (customer, account, article, etc.), how things are stored, memory management, database interaction, session management, error handling, security, etc.

Then, the next level architecture - What are the components of the system, including major classes?  How do they interact; who calls who, what's the exact flow, what are the alternate flows - this needs a full system flow and diagram set that can be carefully managed later.  How flexible is everything. How encapsulated is everything?  How is memory handled, in detail, for network, parsing, read/write, flow-through, etc., who releases it, when?  What are high/low water marks for things, when/how do we shed load?

Third level design - What do the classes look like in detail, how do we interact with subsystems and memory. How are logging, diagnostics and stats done. How is parsing done (hand or lex parsers). What functions are needed in what classes, do an interaction diagram.

Code layout - Layout the source code files in a way that makes sense, working hard to reduce the possibilities of collisions. This includes using directories for major subsystems and lots of files, plus a good include system that makes sense.  Deal with any multi-platform issues right up front, including how these will be organized and made, including platform QA issues.

Functional Breakdown

At this point, people will know how the system is put together and generally how it will work.  The next step is to create a functional list of things for people to work on.  This will include which modules go to which person, what the initial areas of responsibility are, etc.  From this point, the process moves to the Development Stage.

Just keep peeling away the onion to determine data structures, detailed information flow, error recovery, etc.  In general, developers tend to resist getting too deep on this, but experience has shown that group design even at low levels ends up with superior results and fewer missed challenges.

Services & Abstractions

Once you have a handle on the structure of things, begin thinking about common services and abstractions.  Services include configuration, logging, diagnostics/debugging, security, communications, user tracking and statistics, database management and similar functions.  These should all be pushed into dedicated modules or objects, allowing for abstract interfaces and minimal repetition in the main system.

Abstractions are also important in combining common characteristics.  Commonly implemented as base classes in OO systems, these are just ways of sharing common functions, data structures, etc.  Re-factoring, discussed later, is a key method of continual abstraction and combinatorial design.

Use of UML in design

If at all possible, consider using UML in the design process.  The Unified Modeling Language is a very useful set of tools and methodologies that both builds and documents the knowledge base in and around the design.  Some people sell UML as being able to write code for you, but this is not its primary utility - having good, easy to update, documentation and a process for working out the design are the key benefits.

Mathematical Modeling

If the system involves performance requirements or complex processing, consider the use of mathematical modeling of key issues.  This allows for additional thought on potentially problematic areas and provides for some guidelines to measure against once the system is built.


Also See

"Steve provided by far the best requirements that we've ever received from a client... our COO and software team passes along their thanks"

- Engineering Team Manager