I thought this week we’d check out the SOLID principles I touched on in previous posts (here and here). I’m thinking get a quick overview like we did with Design Patterns and may be we can then take another look at each principal again in more detail in the future.
So what exactly are the SOLID principles? They are really good guidance on how to design and develop highly maintainable, flexible, and easily understood software. Initially coined by Uncle Bob, if you read my previous post you know to check out one of his books, Clean Code, in a paper he wrote in 2000 called Design Principles and Design Patterns with the term SOLID coming later.
SOLID itself is made up of 5 principles, each a letter in the SOLID acronym, so lets get started…
Single Responsibility Principle
The first principle, and the ‘S’ in SOLID, is the Single Responsibility principle. This principle at its core means:
‘There should never be more than one reason for a class to change‘
In essence a class should only ever do one thing, it should have one responsibility. This allows us to know exactly what our class is doing and why.
One of the easiest ways to apply this principle is if the description of your class or method has the word ‘and’ in it you may well be doing more than one thing.
By following this principle we can reduce coupling between classes and improve the maintainability of our code.
Next up is ‘O’, that is the Open-Closed principle. The Open-Closed principle states:
‘Software Entities (Classes, Modules, Functions, etc) should be open for extension, but closed for modification’
So what does that mean? It means our goal is to ensure we can always extend the behaviour of an entity, lets say we have requirement changes or future developments but at the same time we do not modify the existing behaviour of an entity.
Personally I view this more from the perspective of the interface, we should always strive to maintain compatibility and, ideally, never introduce breaking changes by modifying existing entities but we can add modifications by extending it.
Liskov Substitution Principle
This one initially I found more confusing that the previous two but the more you use and understand these principles the better. Developed by Barbara Liskov in her keynote in 1987 called ‘Data Abstraction”, within the realm of SOLID it is defined as:
“Functions that user pointers or references to base classes must be able to use objects of derived classes without knowing it”
This principal states that an object of a base class must be replaceable with an object that is of a child class (Polymorphism?).
As above I like to apply this by thinking interfaces, if I expect an interface within my code base, then any class than implements that interface and therefore fulfills the contract can be used.
Interface Segregation Principle
The ‘I’ in SOLID is for the Interface Segregation Principle, developed by Uncle Bob when he was consulting for Xerox. The principle is defined as:
“Clients should not be forced to depend upon interfaces that they do not use.”
Similar to the Single-Responsibility Principle mentioned above the goal here is to reduce the amount of “stuff” our code does and so reduce the complexities within the code base.
This one I like to think of as we should aim to define a lot of related interfaces instead of one massive ‘Jack of all Trades’ interface. The aim is to provide clients only with what they need instead of forcing them to use something “bloated”. The nice outcome of having multiple interfaces means a client can implement only those they require and are not forced to provide implementations for functionality they won’t or don’t need to use.
So our goal is to have a number of interfaces that can be used to make up the whole but can also be split and implemented on a smaller scale.
Dependency Inversion Principle
So the last principal, ‘D’; the Dependency Inversion Principal. Again developed by Uncle Bob, in a report he produce in 1996 called ‘The Dependency Inversion Principal’ (certainly worth a read). Interestingly this principal actually comes in two parts, defined as:
‘ A. HIGH LEVEL MODULES SHOULD NOT DEPEND UPON LOW
LEVEL MODULES. BOTH SHOULD DEPEND UPON ABSTRACTIONS.
B. ABSTRACTIONS SHOULD NOT DEPEND UPON DETAILS. DETAILS
SHOULD DEPEND UPON ABSTRACTIONS.’
What this principal is trying to enforce is that changes at the low-level do not cause cascading effects to the high-level. Our high-level modules contain the business logic of our applications, now if these modules depend on our low-level modules changes to the low-level may have direct consequences for our high-level and vice versa. Our goal should be to decouple the high-level modules from the low-level (again vice versa).
Why? Mainly re-usability and less fragility, by decoupling our code we increase the portability of our classes or modules (don’t reinvent the wheel) and we make our code less prone to breaking when changes are made.
Well there we go, this has been a short introduction to the SOLID principals and hopefully has given you some information on what they are and how they may be used day to day. I may produce a post for each principal and provide examples in C#, if the interest is there.
One thing I have found is that the principals play well with each other and so as we try to apply them more and more each day to our development practices they quite easily become habit.
As usual feel free to get in touch either by the comments or the contact us page.