Ask
27

When are the SOLID principles the wrong thing to apply?

I come from a mathematics background, where a counterexample often teaches more than an example. I have read a great many demonstrations of how to apply the SOLID principles and essentially none of when not to.

That asymmetry is suspicious. Any principle applied without exception stops being a principle and becomes a ritual.

So: where does enforcing these actively make code worse, and how do you tell that you are in one of those situations rather than just finding the work tedious?

4 answers Share
Report

Answering anonymously — a moderator will review it first.

  • @architect_ayla · 4d ago

    The framing that answers this: these principles all buy the same thing, and it is not free. They buy the ability to change one part without disturbing others. The price is indirection — more types, more interfaces, more files, more distance between what a thing is called and what it does.

    That trade is excellent when change is likely and expensive. It is a straight loss when change is unlikely or cheap.

    So the cases where applying them makes things worse:

    • Code with one implementation and no realistic second one. An interface with exactly one implementer, forever, is a file you now have to open twice to read one thing.
    • Small, self-contained scripts and tools. A hundred-line utility does not need a dependency inversion layer.
    • Exploratory work. While you are still learning what the problem is, structure encodes assumptions you have not tested yet, and every one you get wrong is now load-bearing.
    • Code you intend to delete. Prototypes, migrations, one-off imports.
    29
    Share
    Reply

    Answering anonymously — a moderator will review it first.

    Report
  • @maintainer_mika · 5d ago

    The specific failure mode worth naming is speculative generality: building the flexibility for a change that never arrives.

    It is expensive in a way that is easy to miss, because the cost is not the day you write it. It is every subsequent reader tracing through three layers to find where the work happens, every debugging session that lands in an abstract base class, and — the sharpest one — the fact that when the change finally does come, it is usually not the change you prepared for. So you pay for the flexibility, and then you refactor anyway.

    My own test, since you asked how to distinguish it from tedium: can I name the second case? Not "we might need other payment providers one day" but "we are adding this specific one next quarter". If I cannot name it concretely, the abstraction is a guess and I write the direct version, which is easier to change later than an abstraction pointing the wrong way.

    26
    Share
    Reply

    Answering anonymously — a moderator will review it first.

    Report
  • @api_dilan · 5d ago

    Worth pushing back slightly on the framing though, because the counterexample hunt can go too far in the other direction.

    Most of these principles have a cheap version and an expensive version, and the cheap version is nearly always worth it. Keeping a function focused on one job costs nothing. Not making a subclass that violates its parent's contract costs nothing. Not forcing callers to depend on methods they never use costs nothing.

    What is expensive is the ceremonial version: an interface per class, a factory per interface, a container wiring it together. That is where the real cost lives, and it tends to be the version people mean when they say SOLID.

    So I would separate them rather than accepting or rejecting the set. Single responsibility and interface segregation are close to free. Dependency inversion is the one to apply deliberately, at boundaries you have identified, and not everywhere.

    21
    Share
    Reply

    Answering anonymously — a moderator will review it first.

    Report
  • @entropy_elif · 5d ago

    One more context where they genuinely conflict with the goal: performance-critical code.

    Indirection has a runtime cost — virtual dispatch, allocation, cache behaviour. Usually irrelevant. In an inner loop, or in constrained embedded work, it is the difference between meeting a deadline and not.

    That is a narrow exemption and it gets claimed far more often than it applies. But it is real, and in those places the readable design and the fast design genuinely diverge, which no amount of principle will resolve for you.

    15
    Share
    Reply

    Answering anonymously — a moderator will review it first.

    Report