Design Engineering covers the principles, concepts, and practices that guide the development of a high-quality system or product. The primary goal is to create a model or representation—the "design model"—that ensures the final product exhibits Firmness (no critical bugs), Commodity (suitable for its intended use), and Delight (is pleasurable to use). This model details the software's data structures, architecture, interfaces, and components needed for implementation.
Data/Class Design: This is where the structural foundation is laid. It transforms the high-level class-based elements from the analysis model into the detailed data structures and classes required for the actual software implementation.
Architectural Design: This stage defines the overall structure or "skeleton" of the software, outlining the relationships and interactions among the major structural elements of the system. It's derived from the class-based and flow-oriented elements of the analysis model.
Interface Design: This describes how the software communicates internally, with other external systems and hardware, and most importantly, with the end-users. It is built upon the scenario-based, flow-oriented, and behavioral elements identified during the analysis.
Component-level Design: This is the most detailed level. It transforms the structural elements defined in the architecture into a complete, procedural description for each software component, specifying its internal data structures, algorithms, and processing logic.

Software design is defined as both a process (the sequence of steps to describe the software) and a model (the final blueprint providing different views of the software). The principles below guide this process and ensure the quality of the resulting model:
The design process should not suffer from 'tunnel vision.'
Designers must consider multiple alternative approaches and architectures before settling on one. Focusing on a single solution prematurely often leads to missed opportunities for a better, more efficient design.
The design should be traceable to the analysis model.
Every component and design decision must be trackable back to a specific requirement defined in the analysis model. This ensures that the final software actually satisfies all the customer's needs.
The design should "minimize the intellectual distance."
The structure of the software should, as much as possible, mimic the structure of the real-world problem it is solving. This makes the design naturally self-explanatory, easier to understand, and simpler for maintainers to map the code back to the user's domain.
The design should exhibit uniformity and integration.
Uniformity: The entire design should look like it was created by one person (even if it wasn't). This requires defining strict rules of style, format, and notation for the design team before work begins.
Integration: Components must connect seamlessly, which is achieved by taking great care in defining clear and consistent interfaces between them.
The design should be structured to accommodate change.
Change is inevitable, and a good design must anticipate it. The structure should use concepts like modularity and low coupling to isolate design decisions, meaning a change in one area has minimal ripple effects across the rest of the system.
The design should be structured to degrade gently.
Well-designed software should not simply "crash" or "bomb" when unusual data, events, or operating conditions occur (the system should be fault-tolerant). Instead, it should handle the problem gracefully, perhaps logging an error and continuing to function, albeit with reduced capacity.
The design should not reinvent the wheel.
Time and resources are limited, so designers should leverage existing, proven design patterns, reusable components, and established software structures. Don't waste time solving a problem that has already been solved and documented by the industry.