Challenging the Single-Responsibility Principle

2026-03-0812:593923kiss-and-solid.com

2026-01-28kissarchitectureprinciplessolid<

kissarchitectureprinciplessolid

As part of the SOLID principles, the single-responsibility principle (SRP) is one of the most prominent software engineering principles. Unfortunately, it is often used as a killer argument to chop up a software system beyond all recognition.

The problem with this argument is that no matter how small a component already is, the single-responsibility principle can still be applied: every line of code can be assigned its own responsibility. I've seen many teams building distributed monoliths and spaghetti code in pursuit of the SRP.

Minimize code, maximize use cases

When it comes to deciding where to place which code, I found a particular mantra very helpful: minimize code and maximize use cases. The idea is to have as many reusable software components as possible and to minimize the overall code within an organization.

Even though you might not actually have a second project where you might want to reuse something, building for reusability leads to elegant and maintainable software architecture.

The blood group law

A very concrete method on how to approach reusability can be found in Siedersleben's blood group law. This principle is part of the "Quasar architecture style" (see references below). In contrast to other vague guidelines, I find this very easy to apply in practice.

According to this method, you can categorize components into different groups. The following explanations are partly mixed with my own interpretation.

Group 0: Generic components

This is the most generic group. This code is not polluted with technical details or with business logic. In the JavaScript world Lodash, bluebird, jsonpath, Luxon, etc. would be examples of group 0 components.

The big advantage of a group 0 component is that you can consume it within components from any other group (like blood type 0 can be received by any other type). Consuming a type 0 component from any other component will not reduce the reusability of the other component.

Group T: Technical components

These are technical components. Examples are: nconf, knex, metascraper, jsonwebtoken, passport, etc. These components also have value outside your company and are good candidates for open-sourcing.

Group A: Domain components

An A-component contains the domain logic. You should constantly scan your A components, try to generalize logic, and move code into Group 0 or Group T. Once you find such code, you can either replace it with an open-source solution or create an open-source solution. Most developers will be surprised how much 0/T code they find within A components. The goal should be to have as much code as possible in the 0/T group.

Group AT: The anti-pattern

This is a T component that calls or uses an A component. This type needs to be avoided.

References


Read the original article

Comments

  • By HeavyStorm 2026-03-122:393 reply

    > no matter how small a component already is, the single-responsibility principle can still be applied: every line of code can be assigned its own responsibility

    The definition of SRP is to have each class (or module) to have a single reason to change. I don't see how that has anything to do with having each line be assigned a responsibility. If the line changes for the same reasons as it surrounding lines, then, they are part of the same component (to use the author's wording). My guess is that the principle is being taken literally from its name/acronym.

    • By perching_aix 2026-03-127:481 reply

      "Reason" is an "in the eye of the beholder" type human thing. They're taking it in the most tortured sense, because under sufficient pressure that's "exactly" what happens anyways. It sounds silly until everything you touch is 20 indirections away.

      • By bluefirebrand 2026-03-1222:51

        > It sounds silly until everything you touch is 20 indirections away.

        Which is how your standard Uncle Bob inspired codebase winds up looking

    • By pydry 2026-03-128:45

      More to the point the definition of responsibility is ambiguous and rarely shared.

      The SRP is a bit like the original agile principles: the intent in writing them down was good and they definitely alluded to something real and valuable but the actual wording is vague enough to allow almost anything - including the exact opposite of the original intent.

      SRP doesnt need to be tossed away, just redefined more tightly.

    • By atomic_reed 2026-03-126:01

      [dead]

  • By liampulles 2026-03-1210:07

    My evaluation on this is always to ask "are these two things intrinsically the same or coincidentally the same?"

    Answering that question requires domain interrogation. If after that I'm still unsure, then I err on the side of having two copies with maybe a comment on both pointing to the other.

  • By codemastercpp 2026-03-126:511 reply

    There’s some art to identifying what the single responsibility should be at a particular abstraction layer and use that. It’s not meant to be taken literally. there’s an excellent talk in cppcon on this https://youtu.be/Ntraj80qN2k?si=-jsMAccDMKMFQPo8

    • By louhike 2026-03-128:52

      Some parts are hard to follow for a non-cpp programmer but overall it's a great video!

HackerNews