Modular design
Modular design is an approach to software design that emphasizes the separation of concerns and the creation of self-contained, reusable components called modules. A module is a unit of code that owns a cohesive set of responsibilities, exposes a narrow public interface, and hides its internal workings behind that interface. The rest of the system depends on what a module does, not on how it does it.
Modularity is a static quality attribute of a software system. It describes how the system is structured rather than how it behaves at run time, and a design either has it or lacks it regardless of the work the system happens to perform. Its payoff is felt most when the system needs to change. A modular system can be understood, tested, and modified one module at a time, where an undifferentiated whole must be grasped and edited all at once. That is why modularity is a foundation of evolvability and of refactoring at scale.
The driving mechanism of modular design is abstraction. Abstraction is the general practice of distilling a system down to its essentials and hiding the rest. Modularity is abstraction applied to the structure of a system, dividing it into smaller, self-contained modules that can be developed and maintained independently, each one hiding its complexity from the other parts. The discipline that enforces the boundary is encapsulation, also known as information hiding. A caller only needs to understand a module’s interface, not its implementation, which keeps the cognitive overhead of using the module low.
A well-modularized system keeps coupling between modules low and cohesion within each module high. The two pull in the same direction. A module that groups only closely related responsibilities has fewer reasons to reach outside itself, and so tends to depend less on its neighbors. The active work of keeping that coupling low is decoupling, and the broader discipline of drawing the boundaries in the right place is separation of concerns.
Modularity is the result of decomposition, the technique of breaking a system down into smaller parts. A top-down design proceeds by decomposing the whole into a hierarchy of modules, while a bottom-up design composes a system from small, reusable modules. Both target the same modular structure, seen from opposite ends. At the scale of a whole deployment, the same impulse produces a modular monolith, a single process whose internal modules are kept as independent as if they were separate services, and, taken further, a microservices system.
Modularity is not free, and pursued for its own sake it becomes its own problem. Every module boundary is a seam a reader must follow and a place where behavior can go wrong. Splitting too eagerly produces a swarm of tiny modules whose interactions are harder to follow than the original whole, the pitfall decomposition flags as over-decomposition. The single responsibility principle is often misread as "do one thing" and used to justify this over-splitting. The aim is not to maximize the number of modules but to draw boundaries that align with likely axes of change, so that each module can be replaced, tested, and reused without dragging its neighbors along.