In software design, there is a direct, strong, and
undeniable correlation between principles and quality. These principles guide us to create good
designs which become good code which becomes good software. It is absolutely worth your time to
understand these principles and remember them.
There are many more principles than these, but the ones
listed here are solid, proven, fairly well known, and will guide you to create
strong designs.
The Single
Responsibility Principle says that each class and each function should have
one single, specific, and well-defined purpose, and it should never do anything
that is unrelated to its purpose. This
principle is essentially just a reminder of the importance of cohesion.
The Hollywood
Principle says, “Don’t call us, we’ll call you.” What it means is that some classes should
serve a high-level purpose and be the ones that drive processes, while others
should simply perform the low-level tasks and nothing more. High level classes should invoke methods of
lower-level classes, but never vice versa.
The Principle of
Least knowledge says, “Only talk to your immediate friends.” When diagramming your design in a UML class
diagram, each class should only invoke methods of classes that are directly
connected to it. This provides many
advantages; one of the most significant being that it greatly reduces coupling.
Occam’s Razor is
a well-known scientific principle that we can modify slightly to fit the
purpose of software design. It says if
two different designs are both satisfactory, then the simpler one is better.
The Open/Closed
Principle says that classes should be open to extension but closed to
modification. The idea is that code
should be designed so that new functionality can be added without changing the
existing, working code.
The Liskov
Substitution Principle says that if you can design your classes to depend
on abstract classes and interfaces, then any subclass of those can be
substituted in later regardless of how it implements the functionality behind
the scenes.
Favor composition
over inheritance. In many (but not
all) cases, using composition for code reuse works just as well as using
inheritance. Composition has the
advantage of looser coupling, improves reusability, simplifies testing and
maintenance, and provides numerous other benefits.
Separate the aspects
that vary from the aspects that stay the same. If your design must work within several
different contexts, identify what is different between those contexts and what
stays the same. If you can separate the
part that stays the same, then you only need to worry about adapting the part
that differs.