The SOLID acronym encompasses five fundamental principles of object-oriented design. Penned by agile and software craftmanship pioneer Robert Martin, the aim of SOLID is to provide some basic guidelines for writing robust, flexible and extensible code.
Although these guidelines are exactly that: guidelines, and so shouldn’t be treated as laws, considering each of the SOLID principles when writing or refactoring code is a good basis for writing software that is easy to maintain.
A brief overview of the five SOLID principles follows. Over the next week I’ll be covering each principle in detail.
A class should have one and only one responsibility. More specifically, any class should have only one reason to change.
This is important because it reduces the likelihood that a given class will need to change, and changes introduce bugs and complexity.
Software entities should be open for extension but closed for modification. This means an entity can be extended without being modified. Code adhering to this principle will only need to change if there are bugs.
This reduces the risk of new errors being introduced by changes to the code base, and limits the extra unit testing required for new functionality.
This states that any client of a class must be able to use a subclass of that class without modification. In other words, if some code uses a base class, you should be able to substitute that class with a subclass without your code knowing about it.
This can be a little difficult to envisage due to it being largely semantic rather than purely syntactic, but careful application of this rule can reduce the complexity of code which relies on inheritance.
Many client-specific interfaces are better than one general-purpose interface; that is, no client should depend on methods it does not use.
Larger classes which implement multiple smaller interfaces are more loosely coupled with their clients, resulting in code which is more robust and resilient to change.
Dependency Inversion Principle
Depend on abstractions, not concretions. This means that not only should developers code against interfaces (or abstract classes) rather than concrete implementations, but they should also provide those abstractions at both high- and low-level code.
Following DIP means code is more testable and maintainable.