Software design

Software design is concerned with how you assemble lines of code – the structure of classes, functions, and modules within a single codebase, and the decisions that shape how they fit together. It sits in contrast to system design, which is concerned with how you assemble services – the structure of a distributed system’s components, interfaces, and data across process and network boundaries.

The two are points on the same spectrum rather than a hard boundary. Architecture and design draws a similar line using reversibility: architectural decisions are expensive to undo, design decisions are usually local and recoverable. Software design tends to sit at the recoverable end of that spectrum – renaming a class or extracting a function is cheap – while system design decisions, like how services are partitioned or how data is distributed, tend to sit at the expensive end. But the correspondence isn’t exact: a code-level decision such as a poorly chosen public interface can be just as hard to reverse as a service boundary, once enough of the system depends on it.

Within a single codebase, software design plays out through design principles such as preferring cohesion over coupling, and through reusable design patterns that solve recurring structural problems. Modular design – organizing code into self-contained modules with narrow public interfaces – is one of the central concerns of software design. Low-level design is the more granular label sometimes used for the same activity, in contrast to the high-level design of a system’s major components.

See also