I agree. In a way that's one of the strengths of SOLID in my opinion. All places I've worked at had slightly different versions of what e.g. SRP meant. And that's ok. It's a way to make sure your team writes code in a way their teammates would expect. Whether that's objectively good code or not doesn't matter as much to me.
> What counts as a "responsibility", for instance. Where I see one responsibility some people see two and vice versa.
The Single Responsibility Principle is not a rigorously defined Scientific law, where the "responsibility count" can be exactly measured and minimised.
It is a subjective design guideline, with elements of experience, of context and of "I know it when I see it".
This does _not_ make it useless. It is still very useful indeed. But you do have to understand that disagreements over it are not always about "who is objectively right" but "which style makes the most sense in context".
shrug I think every time I've ever seen a disagreement about code quality it's boiled down to both developers thinking "I know it when I see it" about their separate approach.
If a set of principles lets them both think they're both correct and the other one is wrong, what exactly is the point of those principles?
This isn't just a coding thing. It's also, say, why society follows a body of laws rather than something like the 10 commandments.
There are so many instances in code where two options are just as good as eachother by some negligible margin. The actual problem that needs solving is figuring out how to compromise and collaborate.
That's why, if I am on a team project, I much prefer working in opinionated frameworks with strong idioms. It actually doesn't matter if I think I could do it better, the framework has chosen a different way and that is fine. We all have to do it that way, and we can all compromise and collaborate. No one bickers about best, and we can get real work done.
Different when it is a project of my own, but if it requires teamwork you need a framework of collaboration as much as a framework of code.
> lets them both think they're both correct and the other one is wrong, what exactly is the point of those principles
Guidelines can be useful even when subjective. Vitriolic disputes over whose (subjective) view is "correct" is an example of toxic behavior, not a problem with the guidelines being used to justify such behavior.
What would you think of someone who loudly insisted (without humor) that putting pineapple on pizza was wrong as a matter of principle? Is such expression in any way useful?
Some developers will say a (data structure) Controller is a class obeying the SRP
Some others will say the class can manage itself and not need a controller, so M and C can be one thing.
Some other will argue that it's better to make 2 controllers, one for complicated thing 1 and another for complicated thing 2, all based on the same Model.
That's not a problem, it just means the set of design tradeoffs to consider when solving the problem is nontrivial.
The principle draws focus to certain (arguably important) design aspects. Multiple possible approaches are identified. Various concerns are raised in response. A good solution needs to balance these concerns against one another in context.
The principle is just one of many cognitive tools to employ when thinking about the problem.
I think that is a feature, not a bug. I think it makes sense in different contexts for "responsibility" to be abstracted differently. The two extremes are lots of files and functions versus fewer files and functions, and the optimal balance to strike is probably based on whether it is important for people to focus on the modules, or the arrangement of those modules. For high-performance C++ libraries with a good design/architect, it could make sense to split up to a lot of files/functions, so that each function can be iterated upon and improved. For a less-performance sensitive Java library where understanding and usage is most important, you would want less files/functions such that the development focus is more on the high level ideas, the arrangement of the parts (or refactoring).
With any paradigm, there is often ambiguity with certain elements, because those elements should be dynamic. What SOLID aims to do is say that these main points are not something you should dedicate brain cycles towards, as they are best spent elsewhere in the design.
>With any paradigm, there is often ambiguity with certain elements, because those elements should be dynamic.
It's because, unless you're careful, human language is insufficiently precise by its nature for many domains.
This is why mathematicians communicate with mathematical notation, for instance. It's why lawyers use special lawyer only terms (or why interpretation of the law is an explicitly separated function).
With SOLID the lack of precision renders the whole exercise rather pointless.
You're supposed to be able to use these principles as something you can agree upon with other developers so that you have a shared understanding of what constitutes "good" code.
However, it doesn't happen. Instead we argue over what constitutes a single responsibility.
SOLID isn't the only example of this. "Agile" is actually far worse.
> With SOLID the lack of precision renders the whole exercise rather pointless.
If your assumption is that design guidelines can have mathematical precision, then you're going to be perpetually disappointed.
> Instead we argue over what constitutes a single responsibility.
I'm sorry that you can't reach consensus. but IMHO, the false idea that there is a single, mathematically correct answer (and if people differ, therefor someone must be be Wrong, capital W) is often part of the problem, of what stops an agreement on how to move forward pragmatically being reached.
Being vague isn't the only thing wrong with SOLID. The idea that there is "one true way" is partly what bugs me about it (and uncle bob in general).
I don't think that there is a set of design guidelines that can be applied with mathematical precision, but there are a set of code "costs" (like cyclomatic complexity) which can be measured with mathematical precision.
That is to say, all other things being equal, if a pull request non-negligibly reduced cyclomatic complexity I'd be happy to claim that it increased code quality. I don't believe that this idea is false.
> there are a set of code "costs" (like cyclomatic complexity) which can be measured with mathematical precision.
"Responsibility" is IMHO about intent and meaning, which as a human concept is not reducible to measurements of this kind. Cyclomatic complexity is all fine and well, but it cannot tell you if an intent is being met or not. It is silent as to meaning. It's relevant only if you can compare two pieces of code that do the same thing; it's not talking about what that thing should be.
> The idea that there is "one true way" is partly what bugs me about it (and uncle bob in general).
I tend to agree with that, and the original article in general. Mr Martin's approach helped originally, but the dogma now can and should be moved on from.
Yes that is definitely true, human language is very limited. Although, a paradigm is only as strong as it's adoption, and by reducing the barrier to entry (using common language as opposed to overly precise notation), the principles can spread faster and with less friction say inside of an organization. Nuance is always more optimal, for sure. How many people can rattle off the Fundamental Theorem of Calculus? I would think that most people remember the idea behind it, but not the precise mathematical definition. In fact, the definition learned in undergraduate calculus is not 100%, as early undergraduates are not expected to have the rigor and experience to handle real analysis.
A responsibility is an obligation to perform a task or know information (authoritatively). If an object performs two tasks, it has two responibilities, and so on.
For example, an Entity part of the persistence layer in the app, has the responsibility to persist the state of the Entity to the database, but the responsibility to know the information is with an object that is part of the business logic layer. The information that is stored in the Entity to be able to persist it to the DB is just a cache of the information in the Business Object, the Entity is not responsible for it, it just holds a cache. If the same object would be responsible for both holding the information and persisting it, it would have 2 responsibilities.
This might sound somewhat confusing and useless, but it isn't so. Imagine a future where computers have a form of RAM that is not volatile. There is no need for a database, in the classical sense – whatever is in RAM when the computer is powered off/rebooted will still be there when the program resumes running.
I don't disagree, and that lack of common interpretation can be both good and bad. Good because it lets you apply your own understanding and experiences to it, and bad because it introduces the potential for conflict when two people have different understandings.