One Responsibility Rule

From BertrandMeyer's ObjectOrientedSoftwareConstruction, there was the statement (quoting from memory):

A class has a single responsibility: it does it all, does it well, and does it only.


Classes, interfaces, functions, etc. all become large and bloated when they're trying to do too many things.

When a function has too many responsibilities, it becomes buried deep in SpecialFormatting, which has a CodeSmell.

To avoid bloat and confusion, and ensure that code is truly simple (not just quick to hack out) we have to practice CodeNormalization, which seems to be a variation on OnceAndOnlyOnce and also DoTheSimplestThingThatCouldPossiblyWork.

This is part of ResponsibilityDrivenDesign.


On the XpMailingList, BrianButton gave us this rule of thumb:


I've been looking for this quote in ObjectOrientedSoftwareConstruction and haven't been able to find it. Can someone pinpoint the quote? Thanks. -- JimWeirich

From CodeNormalization: "In OO, a class's statement of responsibility (a 25-word or less statement) is the key to the class. It shouldn't have many 'and's and almost no 'or's (see OneResponsibilityRule). The idea for 25 words or less comes from PeterCoad in his patterns and strategies book." -- JohnStoshMuczynski


Does the ExtremeProgramming simplicity goal "MinimumNumberOfClassesAndMethods" go against this rule? Click to find out.


I think a useful corollary to this rule is the CompleteResponsibilityRule: once a class or method takes on a responsibility, it should take full and sole responsibility. -- BobKerns


What about Toolkits? Do they smell, or is this an exception?

A SwissArmyKnife may have many tools but it does not make the knife into a screwdriver - it has a separate screwdriver.


Criticism

This is often unrealistic for real-world apps. Non-trivial things tend naturally to have interweaving concerns [CrossCuttingConcerns]. Forced isolation will often create problems because it's not modeling that natural interweaving well. There's some existing topics on this somewhere around here. I'll link them as I find them. LimitsOfHierarchies hints at some of the issues. ResponsibilityDrivenDesignConflictsWithYagni is another. -t

It's only unrealistic if you're falling into the naive business domain modelling trap that suggests software objects should mirror real-world objects. Objects and object-oriented programming are most appropriately and effectively used to create computational engines that manipulate business facts, not make business simulators that (badly) emulate business processes. In the former case -- or in domains where there is no inclination to model the "real world" (e.g., developing operating systems, system utilities, productivity tools, word processors, etc.) -- the OneResponsibilityRule makes sense and is highly analogous to normalisation of relational databases.

{Both of you are right. Mirroring real-world objects would tend to greatly exacerbate the need for interweaving concerns, and avoiding that trap can help a great deal. But even if all you're modeling is components for computation - which OO does reasonably well - you're still faced with cross-cutting and interweaving issues: security (authority, secrecy), performance (optimizability, predictability, utilization, scalability, latency, throughput), operations safety (disruption tolerance, correct event timing, well-defined behavior), resource management (files, memory, network, power, energy), concurrency (deadlock, datalock, livelock), extensibility (modularity, plugins, code impact under requirements change), compatibility (backwards compatibility, portability), debug-ability,etc. Mirroring real-world objects will have all the above issues plus those resulting from a rigid and incorrect view of the world.}

{But OneResponsibilityRule is still a good guideline to follow. OptimizeLater. OneResponsibilityRule may result in duplicate code (violating OnceAndOnlyOnce) for distinct responsibilities, but avoids coupling of unrelated responsibilities, thus making the system less rigid under requirements change and modularity.}

I'm not sure I agree as a general rule. Some separation between nouns and verbs supplies flexibility and sharing. In practice there's often many-to-many relationship. If most were one-to-one, then it may be worth it. The "natural" ties between them are often just too weak. Perhaps one can argue that its a UsefulLie, a way to DivideAndConquer our "work units" for better mental focus-unit and staff management, but in my assessment, there are better alternative partitioning techniques. -t

*boggle* You've never written object-oriented programs to meet real requirements, have you?

{Perhaps, TopMind, you should explain the situation you are imagining. In practice, 'nouns' are things like 'connection', 'queue', 'stack', 'functor object', 'input stream', 'output stream', 'unum factory', etc.. These nouns are distinguished by interface and contracts on behavior - by responsibility. You can learn much about the 'nouns' used "in practice" by researching WikiWiki and SoftwareDesignPatterns. It is true that there are relationships between objects... e.g. one might create a message stream atop an octet stream, which is a 'uses' relationship. The OneResponsibilityRule favors constructing objects that perform delegation, such that the message stream is ignorant of what happens after it flushes the octet stream. (i.e. "You give me a tube. I break these messages into bits and put the bits in that tube. What happens after that is not my responsibility.") If there are many<->many relationships, then those relationships tend to be encapsulated by behavior and responsibility of dedicated objects... e.g. using 'signals' in EventDrivenProgramming is primarily a pattern on many<->many relationships, and is a common SoftwareDesignPattern for ObjectOrientedProgramming.}

{I don't know what you mean by "natural" ties between things, nor do I know what you consider to be a 'better alternative' for partitioning. I do know of alternatives to OOP that better adapt behavior implicitly and dynamically to a changing world... though, to my dismay, the majority of these alternatives lack high-performance and portable or compatible implementations. But even these alternatives tend to benefit from some form of OneResponsibilityRule... e.g. for relational, the equivalent of OneResponsibilityRule is that queries are local and that tables are narrow, and this offers similar benefits of modularity, composability, and extensibility... at a similar cost to performance.}

Oh boy, not the "narrow table" issue again. (I will agree that if we had better tools to manage such, I may be more prone to accept them. But so far with existing tools and conventions, "overly" narrow tables suck rotting eggs.) -t


Contributors: TimOttinger


Related: SingleResponsibilityPrinciple (MergeMe?),StreamOfConsciousness


CategoryOrganization


EditText of this page (last edited February 20, 2014) or FindPage with title or text search