Software Design
What to know
Design turns requirements into a structure: architecture (modules, layers, components, interfaces) and detailed design (classes, algorithms, data structures). Know the classic architectural styles: layered, client-server, pipe-and-filter, event-driven/publish-subscribe, microservices, and MVC. Understand coupling and cohesion: aim for low coupling and high cohesion; distinguish content, common, control, stamp, and data coupling (data coupling is loosest) and functional vs coincidental cohesion (functional is strongest).
Design principles include separation of concerns, information hiding, abstraction, and the SOLID principles: Single Responsibility, Open-Closed, Liskov Substitution, Interface Segregation, Dependency Inversion. Design patterns (creational: Factory, Singleton, Builder; structural: Adapter, Decorator, Facade, Proxy; behavioral: Observer, Strategy, Command, Template Method) are reusable solutions to recurring problems, not libraries.
Traps in questions
- Pattern vs principle: Singleton is a pattern; Dependency Inversion is a principle. Questions mix categories.
- Coupling direction: a subclass depending on its parent's implementation is tight coupling; programming to interfaces loosens it.
- Liskov violation: a subtype that throws on a method the supertype promises breaks substitutability even if it compiles.
- Style mismatch: pipe-and-filter suits stream processing, not request/response UI; event-driven suits decoupled producers/consumers but complicates debugging.
Rule of thumb
When two designs both work, prefer the one with fewer reasons to change per module (single responsibility) and interfaces that expose behavior, not data.
Worked example
A class that both parses CSV and writes to the database has low cohesion and two change drivers. Split into a parser (functional cohesion) and a repository (data access), coupling them through a narrow data interface.