What System Design Does

System design is the work of deciding how a software system will meet its requirements. A requirement states what the system must do or what condition it must meet.

Suppose we are building a content management system. Authors need to save drafts. Editors need to approve a post before it becomes public. Readers need to open published posts. These statements describe what the system must allow people to do.

They do not tell us how the program will record a post, how it will know whether the post is a draft or published, how it will prevent an author from publishing without approval, or where the program will run. Those are design questions.

A design specifies those answers. It describes how work is divided inside the program, what information the program keeps, how people or other software interact with it, and how it is run.

Requirements guide design

“An author can save a draft and return to it later” is a requirement. It tells us that the system must preserve the author’s work and keep an unfinished draft from appearing as a published post. It does not tell us how to represent or store the post.

One design could store each draft in a file and move it to a different location when it is published. Another could store every post in a database and record its current state, such as draft or published. Either design could satisfy the requirement. Choosing between them is a design decision.

Now consider the rule that an editor must approve every post before readers can see it. We may decide to give each post one of four states: draft, submitted, published, or returned. These states let the program distinguish what has happened to a post and decide what an author or editor may do next. This design choice has a clear reason: it helps the program enforce the approval rule.

When we propose a design choice, we should be able to say which requirement it helps us meet. Two designs may meet the same requirement, but one may take less work, cost less to run, or be easier to change.

Some requirements describe what the system must do. Others describe how well it must work. For example, we may require that a published post open within two seconds when a reader clicks on it. We may require the site to remain functional for readers during planned maintenance. We will study these requirements later. The same order still applies: first state what the system must achieve, then decide how to achieve it.

Design changes as we learn

We can describe software development as a series of activities: understand people’s needs, write requirements, design the system, build it, test it, make it available to users, and keep it running. In practice, these activities overlap and often send us back to earlier decisions.

Suppose a requirement says, “Every post must be reviewed.” While designing the system, we discover unanswered questions. Who may review a post? Can an author modify it during review? What happens when a reviewer returns it? Answering these questions makes the requirement more precise and changes the design.

Implementation and testing can reveal more. For example, while planning a test for the approval rule, we may discover that the design records whether a post is published, but not whether it has been reviewed. Here the design needs to be updated to enable testing the approval rule. We may need to revise the design, or the requirements, or both, after the system is made available to users. For instance, using the software may show that the review process takes too long.

System design is therefore not one step that ends before implementation begins. We revisit design whenever we learn something that changes what the system must do or whether the current design can do it.

How we will work in this course

I will usually begin with a small set of requirements and a simple design that meets them. I will then add a new requirement or show that the current design no longer meets one of the existing requirements. We will revise the design, identify what the change improves, and ask what additional implementation or operational work it introduces.

Our goal is to reach a stage where we can design a software system that can support millions of users as it grows in size and complexity. The parts of this system may run on multiple machines and communicate over a network. To users, these separate parts will still appear as one system.

A brief history of software design

In the 1980s and early 1990s, object-oriented design methods directed attention toward objects, classes, inheritance, and the relationships among them. The 1994 book Design Patterns: Elements of Reusable Object-Oriented Software cataloged recurring class-level design problems and their solutions, and that catalog became widely influential. Knowing how to structure a group of classes was an important design skill.

Around the same time, software engineering was turning its attention toward a larger problem. A 1994 report from Carnegie Mellon’s Software Engineering Institute described a renewed interest in software architecture after years of emphasis on object-oriented design methods. The report defined architecture in terms of a system’s components, their connections, the constraints on them, and the reasons for organizing them that way. These decisions affect performance, behavior, the cost of change, and the ability to build a large system from smaller parts.

The two levels did not replace each other. A system still needs well-designed classes and modules, but those local choices cannot compensate for an architecture that gives responsibilities to the wrong components or makes an essential change too expensive. System design asks questions that a class diagram cannot answer by itself:

  • Which responsibilities belong together?
  • Which parts of the system must communicate?
  • What information must cross a boundary?
  • What happens when one part is slow, unavailable, or changed?
  • Which design can meet the requirements without creating unacceptable operational cost?

As software became a larger part of organizations and public services, these system-level questions became a more visible part of software engineering. They also became part of technical hiring. A coding exercise can show how a candidate implements a small, specified problem. A system-design discussion can show how the candidate clarifies an ambiguous goal, identifies important constraints, proposes boundaries, explains trade-offs, and responds when the interviewer changes a requirement.

Recent industry surveys place system design among the skills developers considered most important. The surveys found system-design problems and realistic scenarios appearing alongside algorithmic questions in technical assessments. The exact practices vary by company, but the reason for adding these exercises is clear: employers want evidence that a person can reason about a system rather than only complete an isolated coding task.