CSE 370: Software Engineering Principles

W03 Learning Activity: Software Design

Overview

Software design, or planning, is the process of determining how software should be built. Design is the bridge that connects the business minded people (SDLC requirements phase) and the developers (SDLC implementation phase). It helps uncover and manage risks that may emerge in development. At its core, design is a communication tool to share ideas with others, and there is a careful balance between being thorough and being concise.

Failure to properly design software can result in costly errors later in the software development lifecycle (SDLC).

Key Points to Remember:

  1. Taking time to design software can identify and mitigate risks early in the SDLC.
  2. There are many ways to document design, from very formal to very informal. Choose the approach that matches your team and its goals.

Preparation Material

Once you have determined the requirements of the system, product, or feature that should be built, the next step is to design the solution. Designs can be formal or informal. They can be done at a system level, or at a detailed component level. The important thing is that by planning out a solution, you can communicate ideas with others and uncover risks.

Connection to Requirements

Software design is directly connected to the requirements elicitation phase that precedes it. During the design phase you translate the requirements you have gathered into a structured plan or blueprint that shows how the system will fulfill those needs.

In addition, during the design process, any ambiguities or inconsistences in the requirements are often identified. This can lead to an iterative feedback loop where the designers go back to the stakeholders for clarification to improve and update the documented requirements.

Traceability

Traceability is the idea that every part of the design should be able to be traced back to something in the requirements documentation. Traceability ensures that each component, module, or feature in the design ties back to a requirement, and that no requirements are overlooked.

As you will see in future learning activities, traceability also extends to future phases of the SDLC as well, where other artifacts such as test cases directly trace back to requirements. Similarly, each part of the implementation should be able to be traced back to a design element, which can then be traced back to one or more requirements.

Effective designs serve as a guide for developers during the implementation phase, ensuring that the system is built according to the specified requirements and design constraints.

Design as a Communication Tool

One of the important aspects of software design is that it serves as a communication tool. It helps facilitate communication of ideas within the development team, between the development team and business stakeholders, and between current developers and those who will maintain the software in the future.

Communication with Business Stakeholders

Software design can facilitate communication with business stakeholders in several ways including:

Communication among Developers

Software design also helps facilitate communication among developers in several ways, including:

Communication for Future Use

Software design also plays a critical role in communicating knowledge and understanding to future developers.

As software evolves over time and bugs need to be fixed or new features need to be added, it is important for the developers to be able to refer back to design documentation (and the requirements they trace back to) to understand the reasons behind previous decisions and the interfaces between various system components.

Finally, there are often decisions, practices, processes, and insights that are known informally within a team or organization but are not documented or officially recorded. Sometimes this type of knowledge is referred to as "tribal knowledge". It is typically passed down through direct communication and experience, rather than through formal documentation or training. This type of knowledge can be very important, but is often lost because of the lack of documentation. Clear, documented software design artifacts preserve this knowledge more effectively for future developers.

Mitigating Risks

A common theme throughout all the phases of the SDLC is to identify and mitigate risks as early as possible. Effective software design can help mitigate risks later in the project by providing a structured and thoughtful approach to planning and building the system. The following are some of the ways that design can mitigate risks:

Many of these issues can be dealt with later in the project, but identifying and addressing these risks during a planning phase helps reduce costs and avoid unforeseen circumstances in major ways.

Design Patterns and Best Practices

During design, experienced software engineers draw on their knowledge of common design patterns and best practices.

A software design pattern is a general, reusable solution to a common problem that occurs in software design. It is a template or blueprint that can be applied to specific situations in the development of software. Design patterns are not finished designs that can be directly transformed into code, but rather templates or guidelines that help solve design problems in a particular context. Here are some key aspects of software design patterns:

There are whole courses, books, and websites devoted to design patterns. While this course does not cover them deeply, it would be valuable to learn more about them in another setting.

Levels of Design

Software design involves planning and specifying different aspects of a software system at various levels of detail. The following is a breakdown of the levels of software design, starting from the larger architectural design down to the finer details within a function:

Architectural Design

Architectural design establishes the overall structure and organization of the software system. It defines how major components or modules interact with each other and how the system as a whole achieves its goals.

Component Design

Component design elaborates on the architectural components identified in the previous step. It defines the internal structure and behavior of each component.

Module Design

Module design (sometimes considered part of component design) zooms in on individual modules or subsystems within the components identified earlier.

Class Design

When using object-oriented programming, class design focuses on the design of individual classes within the modules identified in the previous steps.

Function or Method Design

Function or method design details the implementation of individual functions or methods within classes.

Example: Order Processing System

The following provides examples of each of these levels in the context of an order processing system.

Defining Interfaces

At any level of design, one of the most important pieces to plan out is the interface between two different components of a system. This interface becomes a type of contract that each component can rely on to establish shared expectations.

Diagrams and Design Tools

There are established tools and techniques for describing the various parts of design. The following are examples of some of the most common tools.

UML Class Diagrams

One of the most common design tools is the UML (Unified Modeling Language) class diagram, which represents classes, their attributes, operations or methods, and the relationships among classes. UML class diagrams are widely used in software engineering for visualizing, specifying, constructing, and documenting the architecture of software systems.

The following are the major components of UML class diagrams:

  1. Classes: Represented as rectangles with three compartments:
    • Top compartment: Class name.
    • Middle compartment: Attributes (data members or fields).
    • Bottom compartment: Operations (methods or functions).
  2. Attributes: Properties or data members of a class that describe its state.
    • Shown in the middle compartment of the class rectangle.
    • Typically includes the name of the attribute and its data type.
  3. Operations: Methods or functions that define the behavior of a class.
    • Shown in the bottom compartment of the class rectangle.
    • Includes the operation name, parameters (if any), return type, and sometimes visibility (public, private, protected).
  4. Relationships: Connections or associations between classes, indicating how they interact or collaborate. Common relationships include:
    • Association: A structural relationship representing a connection between two or more classes, often with multiplicity (for example, one-to-one, one-to-many).
    • Generalization (Inheritance): Shows inheritance relationships between classes, where one class (subclass or derived class) inherits attributes and operations from another (superclass or base class).
    • Dependency: Indicates that one class depends on another in some way, often through method parameters or return types.
    • Aggregation: Indicates a whole-part relationship, where one class is part of another class (for example, a car has parts like engine, wheels).
    • Composition: Stronger form of aggregation where the lifetime of the part (component) is controlled by the whole (composite).
  5. Visibility: Specifies the access level or visibility of attributes and operations:
    • Public (+): Accessible from outside the class.
    • Private (-): Accessible only within the class.
    • Protected (#): Accessible within the class and its subclasses (inheritance).

The following is an example of a UML class diagram.

An example UML class diagram showing some of the components highlighted in the text.
An example class diagram.

UML class diagrams are an effective way to communicate the expectations of classes in an object-oriented system.

UML Sequence Diagrams

Another very common design tool is the UML sequence diagram. Unlike class diagrams that highlight the static structure of a system, sequence diagrams show interactions among objects in a sequential manner over time. They illustrate how objects collaborate with each other to achieve a specific behavior or scenario within a system. Sequence diagrams are particularly useful for visualizing the flow of messages, method calls, and control flow between objects during the execution of a use case or a system operation.

The following are the key components of a UML sequence diagram:

  1. Actors and Objects:
    • Actor: Represents an entity (user, system, external component) interacting with the system.
    • Object: Represents an instance of a class or component within the system.
  2. Lifelines:
    • A lifeline represents the existence of an object over a period of time during which it participates in interactions.
    • Drawn as a vertical dashed line attached to the top of the object's symbol.
  3. Messages:
    • Messages are depicted as arrows between lifelines, indicating communication or interaction between objects.
    • Synchronous Message: Indicates a direct call where the sender waits for the receiver to complete the operation before proceeding.
    • Asynchronous Message: Indicates a call where the sender continues without waiting for the receiver to complete the operation.
    • Return Message: Indicates the response returned from a method call, showing the flow of control back to the sender.
  4. Activation Boxes:
    • Activation boxes represent the time period during which an object is performing an operation or processing a message.
    • Shown as a rectangle on top of the lifeline with vertical lines extending downwards.
  5. Control Flow:
    • Control flow arrows show the sequence of messages and the order in which interactions occur between objects.
    • They help illustrate the chronological order of method calls and responses during the execution of a scenario.

The following is an example of a UML sequence diagram.

A sequence diagram showing some of the components highlighted in the text.
An example sequence diagram.
Data Dictionaries

Another common tool used in design is a data dictionary, which is a centralized repository or document that provides detailed descriptions and definitions of data elements used within a system. It serves as a comprehensive reference for data management, helping to ensure consistency, accuracy, and clarity in data usage throughout the system.

The following are key components of a data dictionary:

The power of data dictionaries is that they clearly show the data that is going back and forth between components, including the data types and other details. This is especially important when defining APIs or any kind of interface.

Data dictionaries are ideally defined before a component is built, but they can also be generated directly from the code after the fact.

Amount of Detail

In addition to the few common design tools discussed here, there are many others. As you consider each of these tools and the designs for the various parts of your system, you will have to make a decision on how formal or informal you will be.

Much like the tradeoffs between formal and agile methodologies, there are advantages and disadvantages to being more formal, and also to being more thorough and detailed. You might be tempted to say that being more formal and detailed is always better, but remember that agile methodologies prefer working code to comprehensive documentation.

When designs are more formal and detailed, they can become more difficult to maintain, and often get out of sync with the current system. On the other hand formal designs can often be more precise and avoid the ambiguity that arises from lack of detail.

You should also recognize that you can use formal tools, but lack important detail, or you can be informal in the tools (such as using a whiteboard for a diagram) while at the same time being very thorough. Most companies will define a standard that you will follow with regard to the tools they use, but perhaps the most important aspect to consider when making a decision is that you want to choose a process that your team can reliably use and maintain. A design that is not used, or one that gets out of date and is not maintained is likely worse than not having one at all, because it could convey false information.

Design in an AI World

As artificial intelligence becomes more prominent in the software engineering field, the importance of creating high quality software designs becomes more important than ever. Code generation tools excel at writing code when the problem is very well defined. As time goes on, it may be that engineers spend nearly all of their time in the design, review, and testing phases, and very little in the actual implementation work.

Continue the conversation

After completing this reading, ask 3-5 follow up questions about software design to an AI system of your choice. (You may use ChatGPT, Bing, Claude AI, Gemini, or any other system of your choosing.)

Good questions may include:

Submission

After you are comfortable with these topics, return to Canvas to take the associated quiz.

Other Links:

ChatGPT assisted in the creation of this learning material.