Modular software design can be briefly described as splitting a software system into multiple well-isolated, autonomous parts (modules) that are loosely coupled with each other.
Modular software design is a gold standard of maintainable software design. But to use it properly, you should know its costs and trade-offs:
- It requires more up-front investment.
- It requires more domain knowledge to get right.
- The consequences of getting the boundaries wrong are bigger.
- Changing a flow that spans across multiple modules is safer, but slower, since you have to change multiple modules and their contract/interfaces. This is not desirable when prototyping.
- Debugging on the early stages might be harder, since most early bugs will be integration bugs.
- Integration tests might be harder/slower to write.
- Choosing an interface/contract for each module requires some experience.
- Fully decoupling different modules from a shared database means loosing referential integrity and not being able to use DB transactions.
- Modularization and low coupling makes it easier to understand each module in isolation, but it may be harder to understand the entire system.
- Handling cross-cutting concerns (e.g. observability, privacy policies, authorization) may be harder and more mundane (and the code more scattered across the system.)
Loose final remarks
- You can find my list of the benefits here
- Some of the costs may actually be marginal or even desirable.
- Dan North introduced a technique called “Spike and stabilize”, which can help to mitigate some of those costs and tradeoffs (starts at 15:50). Start with a code that’s not modular to figure things out and then modularize if you intend to stick with the code.