Introducing
He is a principle to be followed and not a project pattern. So it already shows that it is difficult to define a line where they are being used correctly or not. My experience indicates that only qualified experience (and not just quantified) helps to develop the ability to define this line.
The qualification has to do with the number and types of projects that developed, the people who were participating, their dynamics, the individual attitude of the person in relation to the learning and evolution of their knowledge. And of course the ability to understand problems and abstraction is important as well. No use decorating how to use tools or how to code. You have to be able to interpret problems which is something more difficult than interpreting texts and which is somewhat deficient in most people. It is not enough to know how to use the tool you have to know what to do with it. And this is not taught in books.
Definition
The principle indicates that an application component should be responsible for only one task. Having only one feature. It has to do with cohesion.
Some people consider that this is related to OOP, but it is something general and that has been applied for decades. There was a lower use in the past because its application hindered a little the performance, what was very important at the time, today it does not weigh more and it is often possible to optimize to neither have the slightest influence that this principle causes when it breaks everything in smaller parts.
How to use it
The secret is to define what is unique functionality. If you exaggerate you will have a function running an instruction of your code more or less equivalent to a processor instruction, because this is the most unique responsibility. If you do not apply the principle you can have a "linguistics" that does several things.
Well, of course the last case only people who know nothing about it or very stubborn write something like that (we’ve already had a question here with a function of 35 thousand lines). It’s common for them to have trouble seeing all they could.
This can be easily noticed here on Sopt in the codes people post. In general the person cannot structure what is a class and what should be the methods and functions, and even worse, what should be in each one. It is even difficult to provide the best encapsulation and other techniques that help the good design of the application.
But we must think on an architectural level as well, not only of code.
When the person discovers the principle and finds it sensational he dazzles and starts to break into many small parts too.
The need for future change determines much that must be broken. And, in most situations, it is not easy to define this in advance. Unless the programmer already has previous experience with exactly the same problem. Not mastering the domain (Pun Unintended ?!? : ) ) is a requirement to achieve SRP in its fullness. What is rare happens.
The principle has much to do with the administration of change. If it were possible to make software that you never need to change (even during initial development) you would not need SRP. But it virtually doesn’t exist (scripts simple are exceptions). We are talking about maintainability. A change should have to change only one component of the application. The more granular what is the smaller change should be this component.
Arbitrarily putting things together hurts SRP? It hurts, but it doesn’t always cause problems. It happens a lot in classes whose members are all static. Of course, the ideal is not to have such arbitrary grouping, but it’s stupid to think that you can’t have all the major mathematical functions together in a class called Math
. Believe some people think this because they memorize the rule and don’t look at the context and practicality. So we conclude that decide the granularity is subjective.
Other principles that help
This has to do with DRY also. If you break the pieces well it is easier to do DRY. Imagine how difficult it is to have information (a data structure, an algorithm) canonical when she carries more than she should. Imagine what would happen if you had to change it somewhere and it causes a widespread problem because part of what you had with it no longer matches the change made in one part. Without adopting SRP the DRY is impaired. And this is the most important principle to facilitate maintenance (in my opinion).
How much flexibility do you need? Let’s assume you have a tax calculation that there are several steps to perform. Does each step need to be in a different method? In a different class? It depends on the problem. If you apply the principle blindly, you incur the problem described in YAGNI. You need to see if there is a real need for each step to be changed independently.
But that’s not always a good criterion. MVC is something that reduces responsibility and increases the effort to maintain (most changes in a model must require at least one change in vision). There to avoid this problem you have to think about other forms of development not so obvious to most people. Others even know how to solve because they learned some cake recipe.
Fragmentation can get in the way of not only having to change in more than one place, but also having things spread too much. Of course there are techniques where you can fragment to have everything granular when you need it and additionally you can create "combos" ready to have things more ready to hand when it is needed.
Obviously components that join things together to facilitate common use may violate the SRP. And if it is not necessary it is bad.
Studying other principles such as those cited here helps. Another that helps is the SOLID (yes the SRP is inside it, but the other points help organize this way). Only use without exaggerations.
Never forget the YAGNI and the KISS. Study code Smells, anti-patterns.
Techniques that help
Give good names for what you’re doing help much to adopt the SRP correctly. Most people have difficulty with this. If the name is correct, it indicates what to do. But often we can only give good names when we know what it does, which makes it a paradox :)
There are only two difficult things in computing: cache invalidation and naming things.
-- Phil Karlton
If it is difficult to give a name it is because you must do more than one thing. Rethink!
Looking at the size of things helps nothing. This is a common misconception. What has to be great can be great as long as there is a reason to be so. Look at the widgets of a GUI, are monstrous.
Collecting requirements properly is another task that people do not master well. And it is critical. If you do not know ask the right questions, interpret the answers, fill in the gaps of information that you cannot get through the laymen of computing and put it all together in an organized way can’t architect the application, can’t define good names, can’t do SRP at the right level.
So I’m going to repeat that learn to code is the tip of iceberg. Developing software is solving problems, not coding. So this activity is considered by many as engineering or architecture. It’s a bit science, a little art. Or how some like it, it’s like gardening or gastronomy. We can’t even define what it is :)
Example of the question
The answers to the example cited in the question can only be given with a thorough analysis of the specific case, with all the requirements well collected. That only the AP has. Obviously ask code review in specific cases can help gain experience.
Questions that may help:
- The break will make the most reusable code in various circumstances without causing side effects?
- It will be easier to read the code and understand what it does?
- Code can be easily extended?
- He is being represented canonically?
- Can be tested independently?
- The information contained therein is directly related?
- Some are too related and together are part of another entity?
- Will it be intuitive to use this way within the requirements? How will it be used?
- Will it be used in how many places? This can be guaranteed?
Examples
The MVC pattern is an example inductive path of SRP. He tries to make it clear which data model will be used (M), how to present this data (V) and how to operationalize it (C). Before it was common to have a single component that did all this and it was difficult to change one of the parts.
But to demonstrate how controversial what is SRP and what is not, MVC seemed to break the parts very well on this architectural level. But some people disagreed and created not only other similar models but also models that broke into more parts, for example the MVVM.
It is true that presentation and model should not be together, but most of the applications we see around are like this, and often end up working.
The most obvious example of abuse would be to create a function where it sums up two numbers. There is something ready that does this.
But that doesn’t mean I should never do this. For example: if the function does not declare that it is a sum and this is just an implementation detail, then ok. It may be that one day is not a simple sum more, or the types may change, that is, the details change despite the API remain the same.
Another example where you use something very simple would be a method that just takes one field of the class. Often the name of the method is longer than calling the field itself. It seems an exaggeration, right? It depends. Whether the method creates a better abstraction may be interesting. That is, it goes that further ahead is another field to return or that the field needs to be manipulated before returning. Breaking very simple things provides better abstraction and better documentation than that. Giving names for certain actions helps much code readability.
Business rules must go together with the persistence of the data? They are two different things. It seems obvious that they must, right? Yeah, but a lot of people don’t do that and get along very well. It decreases complexity. Of course it doesn’t apply to all cases. Then we begin to question whether all the rules should be together. Or is it just those that relate two or more parts of the entity? Or should they be grouped by some criterion? Difficult to say.
Note that the fact that a class does both is not bad in itself. It may be bad that the implementation of everything is within this class. Knowing what is abstract and what is concrete helps define responsibility. We often forget that. An interface has an abstract responsibility. And almost always people get it right :) So it seems that concrete is more complicated to define.
Separating mechanism and business rules is important, but how much? What price will you pay for it? Which parts to separate? Where to dock them?
Completion
The fact is that in any design there will be people who will say that it must be done one way and others that it must be done another way. It is something "almost arbitrary". With some criteria, of course, but it’s still something that everyone has their own way of doing. And explanations in specific and concrete cases can convince someone whether it’s right or not.
References
Wikipedia. I don’t like the article much, it is limiting and follows a source, marketeer.
Term that should also be studied together.
Study on the subject.
Alternative view to Uncle Bob’s definition that really is a little rough.
I’m just not going to put another bounty on it because there’s an answer from me and I don’t think it would do any good, I don’t know why that one didn’t pan out. It’s something very important and general, has all the requirements to be one of those popular.
– Maniero