{"id":12082,"date":"2014-03-17T10:02:36","date_gmt":"2014-03-17T08:02:36","guid":{"rendered":"http:\/\/mozaicworks.com\/?p=6469"},"modified":"2014-03-17T10:02:36","modified_gmt":"2014-03-17T08:02:36","slug":"the-single-responsibility-principle","status":"publish","type":"post","link":"https:\/\/mozaicworks.com\/blog\/the-single-responsibility-principle","title":{"rendered":"The Single Responsibility Principle"},"content":{"rendered":"
Let me tell you the story of a developer. His name is John and he\u2019s working in a medium-size company, developing with 10 colleagues the internal tools for users from: accounting, customer relations, human resources, marketing, management reports and operations. Since John is mainly specialized in HR, he gets requests such as:<\/p>\n
We\u2019re introducing our first bonus: 5% for employees who get more than 9\/10 from the 360 feedback. We need an alert in the application to show when someone qualifies. The bonus will apply automatically for the next month\u2019s pay.<\/em><\/p>\n John starts the task by looking at the following piece of code:<\/p>\n and suddenly understands he has a big problem. Can you see it?<\/p>\n Before we find out what the problem is, let\u2019s analyze the context.<\/p>\n Software changes because users ask for changes. They ask for changes because something in their life has changed, and there is a gap between what they have and what they need.<\/p>\n In terms of code, this means that\u00a0some changes are more likely to happen together<\/strong>. HR departments are more likely to ask for changes in the way the pay is computed. Managers are more likely to ask for changes in reporting. IT is more likely to ask changes for things such as the database server or the operating systems. These three types of users are more likely to ask the changes separately than together.<\/p>\n Since we expect the software changes to come in a certain way, could we optimize the design of the code for it? Sure we can. The idea is simple and powerful:\u00a0separate the code that changes together from the code that changes separately<\/strong>. This idea is known as the\u00a0Single Responsibility Principle (SRP)<\/strong>. You might have seen it stated in different ways:<\/p>\n Every class should have a single responsibility, and that responsibility should be entirely encapsulated by the class<\/p><\/blockquote>\n or<\/p>\n Any class or method should have only one reason to change.<\/p><\/blockquote>\n or<\/p>\n Things that change for the same reason should be kept together.<\/p>\n Things that change for different reasons should be separated.<\/p><\/blockquote>\n Looking at the code, John probably has to change the\u00a0calculatePay()<\/em>\u00a0method to take into account the bonus. When doing so, the class\u00a0Employee<\/em>\u00a0obviously changes. This means anything that depends on the class Employee needs recompilation and redeployment. But the Operations department hasn\u2019t requested any change, why do we need to redeploy the Operations module that uses\u00a0Employee.reportHours()<\/em>?<\/p>\n Moreover, if John works overtime to finish his task and inadvertently introduces a mistake in the\u00a0reportHours()\u00a0<\/em>method on Friday evening before the release (we know this happens often<\/a>), the situation gets very weird. A change requested by the HR department has caused all the Operations reports to fail. The Operations module wasn\u2019t retested, after all the change was in the HR module, right? John will be in a tough position, answering to at least two angry managers.<\/p>\n Even if John has no idea of the application architecture and doesn\u2019t see this coming, he probably has to ask the IT team to deploy at least two modules. That implies lots of paper work that John would rather not do. Moreover, the IT team will be unhappy about the change.<\/p>\n Briefly, John is in a lot of trouble because one class doesn\u2019t follow the\u00a0Single Responsibility Principle<\/strong>. TheEmployee<\/em>\u00a0class is responsible to at least three different roles:<\/p>\n The example above is one of the typical SRP violations:\u00a0class methods that do very different things<\/strong>.<\/p>\n Let\u2019s explore other typical violations. How about this method stub:<\/p>\n }<\/p>\n This method has at least three responsibilities (or reasons to change):<\/p>\n The method name is deceptive. It should becomputeAverageAndSaveToDatabaseAndReportErrorIfSaveFails()<\/em>. The SRP violation becomes clear becausethe method name contains And<\/strong>.<\/p>\n The third type of typical SRP violation is having\u00a0classes with generic names<\/strong>. The ones I\u2019ve met the most are:\u00a0Manager<\/em>,\u00a0Bag<\/em>,\u00a0Stuff\u00a0<\/em>or my favorite one coming from WordPress:\u00a0functions.php<\/em>\u00a0(technically not a class, but the point still stands). If you take time to try to name this type of classes so that the new name expresses what it does, you will probably end up with a lot of\u00a0And<\/em>s in the name. These classes are typically places where developers drop any method that doesn\u2019t belong anywhere else.<\/p>\n We\u2019ve seen how to visually identify SRP violations, but how about measuring them? There\u2019s no easy way to do it, but there is one. The key is to focus on the files that change together. The best source of information is therefore your source control. Michael Feathers (whom you can meet at the\u00a0I T.A.K.E. Unconference this year<\/a>) wrote a few scripts to build graphs that show the files that change together most often. As far as I know, there is no tool to do this now, but his\u00a0talk<\/a>\u00a0is nonetheless showing a useful direction for measuring your design quality.<\/p>\n The key is to extract the responsibilities where they belong. Of course, that\u2019s not always easy. Sometimes it\u2019s not clear where the responsibilities belong. Other than building a design sense and reviewing the design with your colleagues, there\u2019s not much you can do.<\/p>\n If we take as example the last method, it should probably turn into:<\/p>\n where\u00a0StudentRepository<\/em>\u00a0and\u00a0AverageCalculator<\/em>\u00a0are interfaces. This code allows us to change separately:<\/p>\nclass Employee{\r\n\u00a0\u00a0\u00a0 public Money calculatePay(){...}\r\n\u00a0\u00a0\u00a0 public void save(){...}\r\n\u00a0\u00a0\u00a0 public String reportHours(){...}\r\n}<\/pre>\n
What is likely to change?<\/h2>\n
Taking advantage of change patterns<\/h2>\n
What\u2019s John\u2019s problem?<\/h2>\n
\n
Spotting SRP violations<\/h2>\n
public int computeAverage(Student student){\r\n \/\/ compute average for student\r\n ....\r\n \/\/ save to database\r\n try{\r\n \/\/ save average to database\r\n } catch(SQLException exc){\r\n \/\/ report error\r\n }<\/pre>\n
\n
Measuring SRP violations<\/h2>\n
How to refactor SRP violations<\/h2>\n
public class AverageCalculationService{\r\n\r\n private StudentRepository studentRepository;\r\n private AverageCalculator averageCalculator;\r\n\r\n public AverageCalculationService(StudentRepository studentRepository, AverageCalculator averageCalculator){\r\n this.studentRepository = studentRepository;\r\n this.averageCalculator = averageCalculator;\r\n }\r\n\r\n public void computeAverageForStudent(Student student){\r\n List marks = studentQuery.getMarks(student);\r\n int average = averageCalculator.computeAverage(marks);\r\n studentQuery.saveAverage(average);\r\n }\r\n}\r\n\r\npublic class ArithmeticAverageCalculator implements AverageCalculator{\r\n public int computeAverage(List marks){\r\n \/\/ compute average\r\n return average;\r\n }\r\n}<\/pre>\n
\n