As a software developer, you get used to lots of acronyms being banded about, but perhaps one of the most important is SOLID.In this series of posts, I will endeavour to explain the ideas behind the terminology and why it should be central to everything you do as a software developer.
So, let’s start with the S
Single Responsibility Principle
Have you ever gone shopping and come home with too many bags, only for one of the handles to snap, leaving you with all your stuff in a mess on the floor. Notice how it’s always the bags with the eggs in it?
Well, just as you can get overwhelmed if you’re trying to do too many things at the same time, so can your code. If you don’t want to end up with egg on your face as a developer, it’s best to make sure your classes and method have only one responsibility.
But why does this matter, I hear you ask? Well, let me give you an example. Let’s say we’re building a brand new Robot that will cater for your every whim. After all, us Software Developers are lazy, so if we can write a program that does everything for us then it’s happy days!
Ok, so we’ll call our Robot RoboSlave and we’ll write a method to make RoboSlave make us breakfast. After making our breakfast, RoboSlave should really clean up so we’ll add in code for RoboSlave to clean up too. Now we have a
MakeBreakfast() method that is responsible for both making our breakfast and for tidying up afterwards, thus breaking the Single Responsibility Principle.
After a year of massive sales for RoboSlave a customer has requested that it would be great if RoboSlave could use the dish washer to clean up instead of putting the bowl in the sink. That sounds like a great idea, so we modify the code.
Our new customer loves the new feature and RoboSlave is once again the talk of the Robot world but then we start to get angry complaints from customers that don’t have dishwashers as RoboSlave is sticking their bowls in the bin. Our method is breaking both the Single Responsibility Principle and the Open Closed principle and by changing the method we have broken the existing usage of RoboSlave, creating problems we weren’t expecting!
What we really needed was some kind of test suite that would warn us if the changes we were making could have caused a problem for the existing customers but writing those tests is difficult because we can’t test making washing up without letting RoboSlave make breakfast and we’d soon start to run out of cereal. There’s only so many cornflakes you can eat!
You can imagine that as we add more and more options to our
MakeBreakfast() method (maybe you want a choice of toast or cereal?), writing tests becomes more and more complicated and you have to write more and more tests e.g.
GivenRoboSlaveIsMakingBreakfastAndIWantToastThenRoboSlavePutsThePlateInTheSinkAndWashesIt GivenRoboSlaveIsMakingBreakfastAndIWantToastThenRoboSlavePutsThePlateInTheDishWasherAndTurnsItOn GivenRoboSlaveIsMakingBreakfastAndIWantCerealtThenRoboSlavePutsTheBowlInTheSinkAndWashesIt GivenRoboSlaveIsMakingBreakfastAndIWantCerealThenRoboSlavePutsTheBowlInTheDishWasherAndTurnsItOn
We’re not even testing what happens if something goes wrong like there’s no cereal left or the bread is mouldy here and we already have to write a lot of tests.
It would be much better if we could isolate the functionality so that we have one method for
WashUp() and another for
MakeBreakfast() and then we can test the two actions in isolation, resulting in less tests for us to write, and lets face it, writing tests is boring so the less we have to do the better. We could also write another test that makes sure RoboSlave does indeed wash up after making breakfast.
So, how do you decide when you need to write a new class or method? When I’m building software, I tend to break down the problem into logical chunks until I end up with a To Do list of steps the feature should do. Each of these To Do list items should be separate methods or even classes depending on the what it is you’re doing and how likely it is that you’ll want to do the same thing again in another part of your system.
That’s another benefit of sticking to the Single Responsible Principle, you end up with small chunks of code that can be reused in many different places and you don’t end up repeating yourself, writing very similar code over and over again. This also makes it easier to maintain because if you spot a pesky bug, you only need to fix it in one place rather than trying to remember all the places which you had that erroneous copy and paste code.
In the next post, I will cover the Open Closed Principle!