Software is a knowledge product in that its value lies in the executable representation of domain expertise. Design is the process of modelling that domain knowledge and so bridges the gap between analysis and construction (SWEBOK). These three areas overlap to some degree and the boundaries can sometimes get a little fuzzy. For example, given that the manufacture cost of software is essentially zero, a frequently made assertion is that the source code is the design (Beck). This is a not-insignificant point that we will return to at the end of this article.
Design can be roughly broken down into high-level and low-level design (SWEBOK). High-level design is concerned with determining what the "pieces" are and how they fit together. The term architecture generally refers to the scheme by which the pieces fit together. Common architectures today include client-server and 3-tier. Some emerging architectures are the rich-client and the software bus.
The other aspect of high-level design - finding the pieces - is concerned with defining and packaging components, generally in such a way that each component corresponds directly to a specific knowledge area and so that the dependency among components is minimized. Ideally, a component/package is the unit of release and re-use (Martin). Incidentally, these emerging architectures and the concept of the package as the unit of re-use are ideas that have evolved out of attempts at distributed object architectures (DCOM, CORBA) in the 90's.
Low-level design, sometimes called detailed design, focuses on implementing the components as defined by the high-level design. Whereas a component is a more-or-less "whole" piece of functionality, the implementation of a component usually consists of many interrelated pieces. A component may be implemented using object-oriented, structural, functional, or other design method. Sometimes low-level design encompases outlining the various classes and methods that make up the design, so that it is clear how to attach the code to the skeleton. This is usually done in a pseudo-code or Program Design Language (PDL), and it is clear how this step overlaps with construction (McConnell).
In order to evaluate a design it is necessary to validate it against the requirements and verify that it works as intended. The most important quality of a design in this context is understandability. A design that cannot be communicated or understood is useless as a knowledge product. To communicate and understand a design we use a variety of different models, such as class-diagrams, object-diagrams, sequence diagrams, ..., flow-charts, method-call hierarchies, and in general whatever method is necessary. Software designers face complex products and work with various stakeholders. Multiple viewpoints are necessary in order to communicate ideas about software design. Numerous design methods and notations for design descriptions had been developed over the past years to satisfy those needs as well as the need to transfer design knowledge to future designers.
There are fairly concrete design attributes that contribute to the goal of understandability. Among these are high-cohesion, low-coupling, and "simplicity" as can be measured using a number of metrics, such as number of classes, number of methods, size of methods, etc. We can also take advantage of design-patterns and idioms in order to further reduce the thought-load needed to understand a design. All of these qualities are valuable for both high- and low-level design.
Returning to the topic mentioned at the head of this article, while the notion that "the source code is the design" may be literally true, it is not practical. Any software package complex enough to be useful (i.e., that embodies useful knowledge) is too complex to be understood in full by any mere human, and so these other models - and the process of constructing them - continue to be useful (Djikstra).
While many models are used opportunistically, constructed as needed an forgotten after their use, it is often practical to archive these models as blueprints that are more systematic, rigorous, and standardized. The IEEE Standard 1471 (Recommended Practice for Architectural Descriptions) and in particular the (pending) IEEE Standard 1016 (Standard for Software Design Descriptions) both place their focus mainly on blueprints.