I don't love the single responsibility principle
1–10 of 125 posts
Re: I don't love the single responsibility principle
#2when one writes code, there are only real, present requirements. The future is pretty irrelevant
I'd disagree with this. The future of your codebase matters unless you're writing a throwaway prototype. And when you rewrite a codebase N times, you'll discover that there are ways of structuring it so that future tasks will become far easier. E.g. for Lisp you'd refactor common patterns into utility functions, and for C you'd carefully craft the interfaces between modules so that they're unlikely to be used improperly / unlikely to be surprising.
Re: I don't love the single responsibility principle
#3I find the author's alternative much more useful in practice.
Re: I don't love the single responsibility principle
#4I try very hard not to get attached to code too much, refactor agressively and will throw it out when I feel it needs redoing. For larger codebases I tend to rip out a chunk between a pair of interfaces and tackle that section indpendently. I'll change either the code or the interfaces but never both in the same sitting.
Re: I don't love the single responsibility principle
#5All the examples I see are one-way towards simply creating a million single method classes.
That's a phenomenon that I've definitely seen a lot; often with the accompanying obfuscation that the method bodies have only one or two statements in them, that just calls into some other methods. It may look like it's made the code simpler locally, but all it's done is spread the complexity out over a wider area and increased it. This isn't "well-designed" or "straightforward", it's almost intentional obfuscation. I've seen this effect most with programmers who were taught OO design principles very very early, possibly before they even had a good grasp of concepts like procedures, loops, and conditionals. "When all you have are classes, everything turns into an object."
Re: I don't love the single responsibility principle
#6When you can't stop citing Uncle Bob slogans or Martin Fowler anti-pattern definitions, you're exercising Mantra-Driven Design. You've given up thinking, and you're making project decisions for religious reasons, citing what various deities said, and interpreting it like the Devil interprets the Bible.
The solution to OP-s problems:
1. Define a clear, minimal interface between "Stan's" classes and your own classes.
2. Communicate via that interface (when I say "interface", it doesn't have to be one interface type, BTW), and only via that interface.
3. Let everyone code their classes as they wish, and let the results speak:
- If either developer produces significantly more defects and issues over time than the other, have the decency and courage to learn from your team-mate. Because the interface is defined (see points 1, 2) it means you can refactor all code that isn't part of the interface. You can add classes, remove classes and you can assign from zero to infinite responsibilities to your classes, do whatever you want.
- If not, then this is one more instance of a valuable lesson: there's more than one wrong way to do things, but there's also more than one right way to do things. Maybe both developers have a good approach, they're arguing over B.S.
Re: I don't love the single responsibility principle
#7The example of the client needing to instantiate B to pass it to A's constructor seems like a poor example of tight coupling. The only reason to instantiate B is because A needs it. The client doesn't literally need to know about B, it simply needs to know how to construct/build A. This could be done through a factory or service locator, or it could be done by A having B autowired into it, which would free the client from having to instantiate B directly.
I do, however, agree that SRP is poorly defined in most of the resources you find, so if anyone has links of case studies of applying it properly, they'd be interesting to review.
Re: I don't love the single responsibility principle
#8The future is irrelevant? That's exactly what design is for -- to protect you from the future. If you didn't care about the future there would be no need to design at all.
A good way to evaluate various candidate designs is to imagine future use cases and ask which design holds up better. A good design will respond really well (ie., require fewer modifications) to novel use cases. Many people think this means design starting with future use cases. But you really just need to design with good principles. Future use cases are useful however at objectively evaluating designs and resolving arguments, such as Which design is better for futures that we care about?
>> Stating that "binding business rules to persistence is asking for trouble" is flatly wrong. Au contraire, It's the simplest thing to do, and in most cases any other solution is just adding complexity without justification.
Everything is a tradeoff. It doesn't make sense for many cases (hacking, etc) to avoid the simplest thing. But if you are building a project that's longed-lived, I can give you countless examples of how coupling business rules to model objects resulted in pain and copious paper cuts.
For me, I'll always decouple them. Why? Because it costs me nothing extra to do it and I have internalized the value in this principle from experience.
>>> Not all applications are big enterprise-y behemoths that benefit from Perfect 100% Decoupling™
You're right. It depends on how much you care about your future. Do you want your codebase to respond with agility to the future. Or are you okay with increasing your technical debt?
>>> Therefore, classes should be: >> small enough to lower coupling, but >> large enough to maximize cohesion.
Not sure I understand. Author seems to suggest these two are in contention with each other.
>>> Coding is hard and principles should not take the place of thinking.
Absolutely. There are many cases where the rules are to be broken. Systems with too much flexibility are just as bad as monolithic ones. It's an art what we do.
Re: I don't love the single responsibility principle
#9Hence a bug fix does not constitute a "change" since it does not change the responsibility of the class, neither does a refactor for code clarity or performance improvements. The purpose/responsibility of "what" the class does, does not change when you do any of those things.
"sometimes a class with more reasons to change is the simplest thing" Could you give an example of this? I can't think of one instance.
"Stating that "binding business rules to persistence is asking for trouble" is flatly wrong. Au contraire, It's the simplest thing to do, and in most cases any other solution is just adding complexity without justification" Now this statement here is flatly wrong precisely for the reason specified in the Uncle Bob's example. Let's do a thought experiment. Consider that you have an Employee class that is a black box to you. Someone else wrote that code and didn't have any exception handling logic in their code. The Employee class did business logic and persistence control. When you tried to use the class there was an error. Now which part of the class was faulty? The business logic part or the persistence control part? Now consider that you needed to use the same Employee class in another project but it needed a different set of business rules but the same persistence control, you would not be able to use this Employee class you would have to create a new one and duplicate your persistence control code.
Design principles have been developed to make sure that code written is maintainable, extensible, clear, comprehensible. Sure me as a single developer who is working on a simple project, who knows what each of my class does and has a small enough code base such that I don't need to separate the application into layers (e.g. call my database directly from my view because I just need this one value and don't want to write a couple of classes to that) can indeed write classes that have more than 1 responsibility. There's nothing to stop you but it does violate the SRP which will make it tougher for someone else to come in and maintain your code or extend it.