If you ask ten developers what characterises good software design, chances are you will get ten completely different answers. There are many principles around, plenty enough to choose from. Just have a look at the wikipedia entry List of software development philosophies to get a glimpse.
Yet, if we synthesise the many principles, it all boils down to three fundamental rules:
- Make it small
- Make it replaceable
- Make it composable
Separation of concern, single responsibility, high cohesion/low coupling, information hiding, encapsulation, dependency inversion, composition over inheritance, etc. are all subsumed by the three rules above.
Software design is about controlling dependencies between the parts of the software–the inner wiring of the software.
If you were to pick only one rule between the three, pick number two, “Make it replaceable”. Aiming at replaceability, you’re almost forced to make things small and composable.
Rule number two gives a very simple but very effective design tool: the question “is this object replaceable?”. If you can’t image another implementation of an object, not even a stub in a unit test, or if you can’t replace one object without replacing other objects, then you should maybe go back to the drawing board. That said, not all objects are replaceable. Domain entities for instance aren’t, and it’s fine.
The very same three principles apply to all levels of abstraction of the software: from classes to modules, from modules to systems, and from systems to systems-of systems. Microservices and SOA are only slightly disguised forms of “Make it small, replaceable, and composable” at the system level.
What is funny about software design, is that problems frequently arise because pieces of the system do too much–not too little. The natural tendency to fix the problem is the add more logic and make it even worse. It takes a lot of courage to instead follow the three principles and break something big into many small pieces. We must be brave if we want to make things small, replaceable, and composable in order to ultimately make them simpler.