A short explanation of the 5 SOLID principles for object-oriented programming. The principles are:
- Single Responsibility
- Open / Closed
- Liskov Substitution
- Interface Segregation
- Dependency Inversion
These were grouped by Robert C. Martin, who invented 1), 4) and 5). 2) was formulated by Bertrand Meyer and 3) by Barbara Liskov. The acronym was coined by Michael Feathers.
The SOLID principle is controversially discussed. See this slide deck by Dan North for a concise critique.
Are you a budding Product Owner? Check out our compilation "Skills for Successful Product Owners"
Content of the 1-Pager:
Single Responsibility Principle
Each class has a single purpose. All its methods should relate to function.
Reasoning: Each responsibility could be a reason to change a class in the future. Fewer responsibilities -> fewer opportunities to introduce bugs during changes.
Example: Split formatting & calculating of a report into different classes.
Open / Closed Principle
Classes (or methods) should be open for extension and closed for modification. Once written they should only be touched to fix errors. New functionality should go into new classes that are derived. This is popularly interpreted to advocate inheritingfrom an abstract base class.
Reasoning: Again you lower the odds of breaking existing code.
Liskov Substitution Principle
You should be able to replace an object with any of its derived classes. Your code should never have to checl which sub-type its’s dealing with.
Reasoning: Prevents awkward type checking and weird side-effects.
Interface Segregation Principle
Define subsets of functionality as interfaces.
Reasoning: Small, specific interfaces lead to a more decoupled system than a big general-purpose one.
Example: A PersistenceManager implements DBReader & DBWriter.
Dependency Inversion Principle
High-level modules should not depend on low-level modules. Instead, both should depend on abstractions. Abstractions should not depend on details. Details should depend upon abstractions.
Reasoning: High-level modules become more reusable if they are ignorant of low-level module implementation details.
Examples: 1) Dependency Injection, 2) Putting high-level modules in different packages than the low-level modules it uses.