What does a 1972 paper have to do with the Single Responsibility Principle?
wasabigeek.com
wasabigeek.com
A common misunderstanding is that a function or class should "only do one thing". This lead to futile discussions about what "one thing" really constitute, and tend to lead to "ravioli code" with innumerable tiny functions and objects, which is really hard to read and understand.
But the principle is about business requirement which might change independently. Don't put the tax rate calculation and the color scheme into the same class, since they might change independently, due to events outside the control of the developers. But otherwise, cohesion is just as important as decoupling. If two things are logically coupled, they should be tightly coupled in the code, otherwise you introduce accidental complexity.
Right I dont understand this either. Instead of one file with a few hundred lines of code lots of people prefer 20 classes/files. Drives me nuts.
The critical thing here is: these classes reflect terms from the domain model that can be easily intuitively understood, not some made-up abstractions adding to incidental complexity, like -Manager, -Util, -Provider, -Context, -Wrapper, and so on.
Conversely, you can imagine that you wrote a sentence, took some words from it, assumed these words don't exist, and replaced them with their dictionary definitions. Repeat a couple of times and you have your one big class. Extracting classes to capture domain language terms is like reversing this obfuscation/serialization process.
Cool article on the topic: https://www.yegor256.com/2014/11/20/seven-virtues-of-good-ob...
But realistically what happens is, e.g., each franchisee wants us to treat phone number differently than eachother. USA wants no country code. Europe does. Japan wants strict number validation. Taiwan doesn't care. And so on.
At the end of the day it all gets stored as a simple string in the database, and there's software other companies have written that can set it to whatever the hell they want so we have to handle that anyways.
Really all I need is a simple string and a validation function.
https://martinfowler.com/bliki/BoundedContext.html
It is a huge topic. Hard for me to discuss this further without knowing the specifics. But intuitively, if it was as simple as "Really all I need is a simple string and a validation function." then you wouldn't need a class with several hundred lines of code.
Or you could have UsaPhoneNumber, JapanesePhoneNumber, etc.
And instead of doing:
IsValidUsaPhoneNumber(str);
you could do:
var usaPhoneNumber = new UsaPhoneNumber(str);
and now you have the validness captured as a type:
https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-va...
This is why SRP and this paper are important: They give qualitative guidelines for how to partition systems, not cuter-productive quantitative guidelines.
Ideally, you take a term or phrase like "single responsibility principle" and use it to discuss a particular design, interface, or implementation. If you can't do that, you have to find a different way to discuss your code.
It's like "clean code". Most people will agree that code should be "clean", but not come to any sort of agreement about what makes code "clean," or whether some specific code is "clean." The way to dig yourself out is to ban the word "clean" and ask people to explain things using different terms.
You've used one of my favorite phrases to describe code... "hard to read and understand". It is, of course, subjective. Alice may think it is easy to read and understand, Bob may think it is hard. However, it's easy enough to agree, in most cases, that everyone on the team should be able to understand the code. Therefore if I find the code hard to read and understand, that's a valid criticism of the code, even though it's a subjective criticism.
I can say, "This code is hard to understand because there's a bunch of color scheme information mixed in with the tax rate calculations." Or I can say, "This code is hard to understand because there are too many small functions." Honestly, just throw SRP in the garbage.
Being easy to understand is nowhere on it. Why is it that everything must be dumbed down? If thousands of people can't get the principle, but it gets good results to the people that understand it, it is a good principle, and those thousands of people either study a bit or decide to live with their worsened condition.
If you take the GP's single paragraph that explains the principle and tries to use it to discuss a particular design, you will see that it's perfectly possible. The fact that people can't do the same if they read a paragraph less and stop at the name is not very relevant.
If you can't communicate the principle, then it's not a principle any more. It's just personal judgement. It's "tacit knowledge".
https://en.wikipedia.org/wiki/Tacit_knowledge
Principles are the opposite of tacit knowledge, they are explicit knowledge.
> Being easy to understand is nowhere on it.
I don't understand what this sentence means. I don't know how to parse "on" in this context and it's unclear what "it" is.
> Why is it that everything must be dumbed down?
Are you saying that "easy to understand" means "dumbed down"? If that's what you're saying, I don't agree with that.
> If you take the GP's single paragraph that explains the principle and tries to use it to discuss a particular design, you will see that it's perfectly possible. The fact that people can't do the same if they read a paragraph less and stop at the name is not very relevant.
The paragraph was vague.
The problem is that the SRP does not help you communicate problems with code. It does not help you understand problems with code. It is too vague.
Following SRP does not help you write good code, IMO.
I recently read this article about how everybody misunderstands the SRP and uses it wrong: http://www.softwareonthebrain.com/2022/01/the-misunderstood-...
Notably it was retweeted by the author of the SRP himself: https://twitter.com/unclebobmartin/status/148522452187556249...
Now neither of them went this far with it: but if we have a programming principle that nobody understands or uses right, is it really all that useful? Maybe it at least shouldn't be the first one in SOLID?
On the criteria to be used in decomposing systems into modules (1972) [pdf] - https://news.ycombinator.com/item?id=30138468 - Jan 2022 (27 comments)
Also:
On the criteria to be used in decomposing systems into modules (1971) - https://news.ycombinator.com/item?id=8849468 - Jan 2015 (5 comments)
Surprising that there haven't been more threads, since it's such a frequently mentioned classic.
> We propose instead that one begins with a list of difficult design decisions or design decisions which are likely to change. Each module is then designed to hide such a decision from the others.
SRP has always confused me even though (in retrospect) this is certainly how my designs work.
I disagree with those who say it’s a bad principle, but maybe we can come up with a succinct name that expresses the idea better?
FWIW, I tend to think that hiding design decisions is the purpose of bounded contexts. But I don’t think that’s a great term either, due to all the context required to understand it (no pun intended)
How about 'Don't Ask Me How?'
(I have for a while felt that abstraction at the class level is very much overrated, while abstraction at the system level tends to be glossed over. This has lead me to enjoy building systems with microservices. Because the interfaces tend to be dictated by the external systems that use the service, but the guts of a service can and do change dramatically.)
If this is supposed to evoke feelings of "wow that's so old, how could anybody know interesting stuff back then?", and that's your attitude, you're simply missing out. So much interesting work from ye olden days...
And of course there could hardly be a better example than Parnas.
do you have a "best of" list to share?
This Parnas paper we are discussing is one, and lately Ive been poring over "Document Processing in a Relational Database System (83)" by Stonebraker, et al, and I also really enjoy Ousterhout papers, though he seems to be enjoying a bit of a renaissance so a search is likely to pull up his modern work, which is fine - you'll find raft papers, philosophy of software design, and performance measuring, which to me still feel like they're channeling a bit of the same spirit as these more classic papers we're discussing.
Since we're discussing classics - i'd be keen to have others jump in here too and (again) raise the profile of some perhaps underloved gems.
Do you have a suggestion on how the article title could be better? I came across Robert Martin's post while trying to build a better intuition for SRP, and it referenced the Parnas paper. So the title was really me thinking "What does this paper have to do with the SRP?", though the '1972' was both for convenience (e.g. "What does 'On the Criteria to be Used in Decomposing Systems' have to do with the single responsibility principle"? is too long) and intrigue. Perhaps "How a 1972 paper relates to the Single Responsibility Principle"?
The Parnas paper wasn't one that Martin initially credited for the SRP as well (see https://www.cs.utexas.edu/users/downing/papers/SRP-1996.pdf), so I didn't feel comfortable claiming that it had direct influence (e.g. "The paper that influenced the Single Responsibility Principle").
> Do you have a suggestion on how the article title could be better?
I read "What does x have to do with y?" as implicitly dismissive, based on my experience. Its often rhetorical. "How a Paper From 1972 Solved Your OO SRP Problems From The 1990s and Beyond" seems more charitable and interesting to my ears. That title needs some editorial attention itself, but its a start.
Anyway, you got a discussion started and hopefully illuminated some to good design, so your submission was a success.
- Functional programming started with Lisp in 1958 (McCarthy), and theoretically before that with Lambda calculus in the 1930s (Church)
- Object-oriented programming started with Simula in the 1960s, extended with Smalltalk in the 1970s, before C++ picked it up in the 1980s.
- Unix was invented in 1969, which drew on ideas from Multics several years prior
- Virtual memory was implemented in Atlas (1962) and popularized in the 1970s
- Virtual machines first appeared in IBM CP/CMS around 1967
- Concurrency issues and solutions like semaphores, locks, condition variables, etc were invented in the late 1960s (Dijkstra)
- The concept of cloud computing was invented in the 1960s with commercial time-sharing services
- The concept of a database was invented in the 1960s with the Integrated Data Store (IDS) in 1964 (Bachman)
- The relational model for databases was invented in the early 1970s (Codd)
- SQL was invented in the 1970s (Chamberlin and Boyce)
And many more.
Now I'm older, I am getting that "hit" of "whoa that is offensive" more than I expected, vs when I first contemplated Ageism as a young software engineer. I thought it wouldn't be something I'd see much of, back then. I've yet to quantify the negative impact, today.
Wasabigeek apologizes, here, for that perception as being unintentional, which is totally understandable ... and I believe bias is difficult to spot in oneself, from personal experience of having unintentional biases. Subjectivity vs Objectivity when it comes to oneself is ripe with tragedy. [Human condition.]
It's not some concept people hype. It's just there on the foundation of software engineering. So, it's not "new again", it's just there.