Break Single Responsibility Principle
Single Responsibility Principle (SRP) is not absolute. It exists to help the code maintainability and readability. But from time to time you may see solutions, patterns that break the SRP and are kind of OK. This is also true for other principles, but this time I would like to talk about SRP.
1. Singleton breaks SRP
The oldest and simplest pattern that breaks SRP is the singleton pattern. This pattern restricts the creation of an object so that there is a single instance of a certain class. Many thinks that singleton actually is an antipattern and I also tend to believe that this is better to use some container to manage the lifecycle of the objects than hard coding singletons or other home made factories. The anti pattern-ness of singleton generally comes from the fact that it breaks the SRP. A singleton has two responsibilities:
-
Manage the creation of the instance of the class
-
Do something that is the original responsibility of the class
You can easily create a singleton that does not violate SRP keeping the first responsibility and drop the second one
public class Singleton {
private static final Singleton instance = new Singleton();
public static Singleton getInstance() { return instance; }
private Singleton() {}
}
but there is not much use of such a beast. Singletons are simple and discussed more than enough in blogs. Let me look at something more complex that breaks SRP.
2. Mockito breaks SRP
Mockito is a mocking framework, which we usually use in unit tests. I assume that you are familiar with mocking and mockito. A typical test looks like the following:
import static org.mockito.Mockito.*;
List mockedList = mock(List.class);
when(mockedList.get(0)).thenReturn("first");
System.out.println(mockedList.get(0));
mockedList.add("one");
mockedList.clear();
verify(mockedList).add("one");
verify(mockedList).clear();
(sample is taken from the Mockito page, actually mixing two examples). The mock object is created using the static call
List mockedList = mock(List.class);
and after it is used for three different things:
-
Setup the mock object for its mocking task.
-
Behave as a mock mocking the real life object during testing.
-
Help verification of the mock usage.
The call
when(mockedList.get(0)).thenReturn("first");
sets up the mock object. The calls
System.out.println(mockedList.get(0));
mockedList.add("one");
mockedList.clear();
use the core responsibility of the mock object and finally the lines
verify(mockedList).add("one");
verify(mockedList).clear();
act as verification.
These are three different tasks not one. I get the point that they are closely related to each other. You can even say that they are just three aspects of a single responsibility. One could argue that verification only uses the mock object as a parameter and it is not the functionality of the mock object. The fact is that the mock object keeps track of its mock usage and acts actively in the verification process behind the scenes. Okay, okay: these all may be true, more or less. The real question is: does it matter?
3. So what?
Does the readability of the code of Mockito suffer from treating the SRP this way? Does the usability of the API of Mockito suffer from this?
The answer is definite NO for both of the questions. The code is as readable as it gets (imho it is more readable than many other open source projects) but it is not affected by the fact that the mock objects have multiple responsibilities. As for the API you can even say more. It is readable and usable even more with this approach. Former mocking frameworks used strings to specify the method calls like
mailer.expects(once()).method("send");
warehouse.expects(once()).method("hasInventory")
(fragment from the page), which is less readable and error prone. A typo in the name of the method is discovered test run time instead of compile time.
What is the morale? Don’t be dogmatic. Care programming principles, since they are there to help you to write good code. I do not urge anyone to ignore them every day. On the other hand if you feel that some of the principles restrict you and your code would be better without it, do not hesitate to consider writing a code that breaks the principles. Discuss it with your peers (programming is a team work anyway) and come to a conclusion. The conclusion will be that you were wrong considering to break SRP in 90% of the cases. In 10%, however, you may come up with brilliant ideas.
Comments imported from Wordpress
James 2015-05-12 15:14:48
Mockito doesn’t break the SRP, the class you’re talking about is an implmentation of the facade pattern. That is its SRP is to be a facade to the richer API of mockito…
Also you can make the Singleton pattern observe the SRP by making the Singleton (the thing that holds a single instance of a class) separate from the thing you want to be a Singleton, e.g. SingletonHolder.getSingleton().
Otherwise, yeah totally agree the thing about principals is you can move them when you HAVE TO, but you should have a darn good reason for wanting to do so and it shouldn’t be at the expense of readability/testability/etc.
Simptreat 2020-04-02 01:09:16
But this always leads to an interesting question, which is, should I be writing code that looks like this?
Comments
Please leave your comments using Disqus, or just press one of the happy faces. If for any reason you do not want to leave a comment here, you can still create a Github ticket.