Blog on SOLID Design perhaps being out of date

23 views
Skip to first unread message

David Croley

unread,
Jan 22, 2015, 2:40:06 PM1/22/15
to agileau...@googlegroups.com
Thanks for those that attended today's Dev SIG.

Here is the link I mentioned about SOLID perhaps being out of date...

http://qualityisspeed.blogspot.com/2014/08/why-i-dont-teach-solid.html

There is a related discussion on Hacker News: https://news.ycombinator.com/item?id=8929458

David Croley


Chris Edwards

unread,
Jan 22, 2015, 2:41:38 PM1/22/15
to agileau...@googlegroups.com
Thanks. I’ll check it out.
> --
> You received this message because you are subscribed to the Google Groups "Agile Austin Developer SIG" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to agileaustin-d...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
>

--
Chris Edwards

"Whatever you do, work at it with all your heart, as working for the Lord, not for men"
- Col 3:23

Sukant Hajra

unread,
Jan 22, 2015, 3:24:47 PM1/22/15
to agileau...@googlegroups.com
Excerpts from David Croley dcroley-at-agilevelocity.com's message of 2015-01-22 13:40:06 -0600:
It's kind of frustrating that we've put SOLID so high on a pedestal that we
have to knock it down as though it was a bad idea. We've taken a simple
presentation from Bob Martin, and interpreted it as some combination of
religion and/or methodology. SOLID is neither. It is merely a set of
architectural principles. As far as I can tell, they are sound, but obviously
incomplete. Bob originally had something on the order of 10 or more principles
[1], but he selected five because they cutely made a backronym of "SOLID" and
were easy to walk across various conferences.

[1] http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod

Every single sentiment of SOLID applies as generally good. It says /nothing/
about creating explicit "I" interfaces for every class. That's merely a facile
implementation of the architectural principle in class-based languages popular
in the 90's. There's /many/ other ways to accomplish modularity. And
modularity is essentially the fundamental theme.

I say this, because taking SOLID to an extreme conclusion has not at all led me
to I-interfaces, or hellish configurations with inversion-of-control containers
like Spring, Guice, or StructureMap.

Instead, aggressive application of SOLID led me to higher-kinded and
type-checked functional programming (my team at Rackspace uses Haskell and some
Scala). Our code is extremely "SOLID" because we have tons of small functions

- with a single responsibility

- that are easily composed ("open to extension") and not likely to be
edited (which is even more obvious when through parametricity my type
signature only permits a single implementation [2])

- that don't use any subtyping (the best way to avoid substitution
problems! [3])

- that adhere to small interfaces (either the type signature of the
function, or for sets of signatures I'll use small single-purpose type
classes [4])

- and pass all necessary dependencies as parameters to functions [5]

[2] "Parametricity, Types are Documentation" talks at http://talks.tmorris.net/
[3] http://okmij.org/ftp/Computation/Subtyping/
[4] http://en.wikipedia.org/wiki/Type_class
[5] http://functionaltalks.org/2013/06/17/runar-oli-bjarnason-dead-simple-dependency-injection/

I'm happy to talk to anyone that wants to learn more.

-Sukant

Janelle Klein

unread,
Jan 22, 2015, 3:52:11 PM1/22/15
to AA Dev SIG
You could make similar arguments about pretty much any design principle...

For example, following the DRY principle has certainly lead to way overly complex solutions for the benefit of removing duplication.  Duplicating code has consequences.  Removing the duplication has consequences.  We have to use our brains to evaluate the trade-offs and ultimately optimize for human factors. 

That doesn't make DRY a bad principle, it's quite useful.  Design principles are not a substitution for thought.

Janelle

Matt Roberts

unread,
Jan 22, 2015, 3:56:31 PM1/22/15
to agileau...@googlegroups.com
+1

~Matt

Eric Stewart

unread,
Jan 22, 2015, 4:33:07 PM1/22/15
to agileau...@googlegroups.com, Janelle Klein

Couldn’t say it better. Thought is key. Apply it, encourage others to use it, and don’t automate too much thought away without understanding the tradeoffs.

DRY is a good example, where teams often end up using and relying too heavily on a tool to identify code duplication and not look for duplication of knowledge.

Sukant Hajra

unread,
Jan 23, 2015, 12:25:19 PM1/23/15
to agileau...@googlegroups.com
Excerpts from Janelle Klein's message of 2015-01-22 14:52:10 -0600:
>
> You could make similar arguments about pretty much any design principle...
>
> For example, following the DRY principle has certainly lead to way overly
> complex solutions for the benefit of removing duplication. Duplicating
> code has consequences. Removing the duplication has consequences. We have
> to use our brains to evaluate the trade-offs and ultimately optimize for
> human factors.
>
> That doesn't make DRY a bad principle, it's quite useful. Design
> principles are not a substitution for thought.

I thought about this off and on. I'm definitely all for thought as the
backbone for any rigorous application. So here's my thoughts. . .

What I'd like to avoid is a sense of relativity completely subject to the whim
of context. I think we end up with this trap with "context is king" or "the
right tool for the job" arguments.

So I'd like to see if we can determine that modularity is universally good in
all contexts, which is really all the SOLID principles are advocating (through
the lens I talked about in my earlier post).

This is different from DRY, which I don't think is universally good. DRY leads
to coupling -- possibly to systems which are not modular. And coupling to
anti-modular systems is often terrible. This is incidentally why Bob
originally had principles that were sensitive to afferent and efferent
coupling. These kinds of principles seem to take the cynical stance that we
will never get modularity right. But this is why parametricity is so
interesting to me.

So I'm open to being proven wrong, or reshaping this statement. But I can't at
all justify jumbling multiple responsibilities into one module. Nor can I
justify solutions that require opening up modules by design. I certainly will
/never/ allow for someone using subtyping to break the substitution principle
-- that's a tragic flaw that betrays the very point of subtyping. Anyway, you
all probably the point.

As a small addendum, it feels very weird for me to be defending SOLID. SOLID
carries with it the weight of an OO culture, and I find it liberating to just
talk about modularity clearly without the acronym. But since I do genuinely
think there's universal value to the principles, I'm not willing to convert the
universal quantification to an existential one.

-Sukant

Janelle Klein

unread,
Jan 23, 2015, 4:56:41 PM1/23/15
to AA Dev SIG
I think the question we need to be asking ourselves is what exactly about the decision causes problems with understanding?  There seems to be a move in our industry recently toward pragmatism over best practices, and I don't think that's necessarily a bad thing.  There's a clear gap when it comes to human-oriented design principles.

Since I've been spending the last few years studying how mistakes are made, I agree with the general sentiment of being context focused, though completely dismissing the usefulness of SOLID principles seems an extreme response.  If you want to know how modularity can cause problems, you can measure it objectively in terms of:

Learning Time - effort required to understand an unfamiliar part of the system.
Modeling Mistakes - misunderstanding the conceptual model of a system.

By observing and studying these problems, I tried to come up with human-oriented design principles of conceptual modeling.  Both learning time and modeling mistakes increase in association with:

Distance - when two pieces of related information are more distant from one another, unexpected dependencies are more common, and it takes longer to find all the pieces of information we need to care about.   Modularity is one of the main reasons for increasing information distance.

Noise - when scanning the code to understand the higher level conceptual model, if we have to sift through noisy details to find the things that matter, it's easy to make bad assumptions and more time-consuming to build a mental model.  Designing for scannability reduces both the time to learn and the frequency of modeling mistakes.  

Ambiguity - when there are multiple ways to interpret the conceptual model, our mind can jump to the wrong conclusion about how a system works.  If we're fortunate enough to notice the ambiguity, it still takes additional learning time to resolve our understanding.

These principles don't run completely counter to SOLID, but they definitely do in some cases.  Information distance in particular is often sacrificed for modularity.  I find myself breaking SOLID principles when there are cross-cutting concerns and it's not that easy to break things up neatly without disrupting the ease of conceptual modeling.  Having two sets of principles that outright conflict in these cases, at least make us aware that there's a tradeoff we need to consider.  


-Sukant

Janelle Klein

unread,
Jan 23, 2015, 5:10:35 PM1/23/15
to AA Dev SIG
Not sure why my email seemed to get chopped off... (trying again)

----

I think the question we need to be asking ourselves is what exactly about the decision causes problems with understanding?  There seems to be a move in our industry recently toward pragmatism over best practices, and I don't think that's necessarily a bad thing.  There's a clear gap when it comes to human-oriented design principles.

Since I've been spending the last few years studying how mistakes are made, I agree with the general sentiment of being context focused, though completely dismissing the usefulness of SOLID principles seems an extreme response.  If you want to know how modularity can cause problems, you can measure it objectively in terms of:

Learning Time - effort required to understand an unfamiliar part of the system.
Modeling Mistakes - misunderstanding the conceptual model of a system.

By observing and studying these problems, I tried to come up with human-oriented design principles of conceptual modeling.  Both learning time and modeling mistakes increase in association with:

Distance - when two pieces of related information are more distant from one another, unexpected dependencies are more common, and it takes longer to find all the pieces of information we need to care about.   Modularity is one of the main reasons for increasing information distance.

Noise - when scanning the code to understand the higher level conceptual model, if we have to sift through noisy details to find the things that matter, it's easy to make bad assumptions and more time-consuming to build a mental model.  Designing for scannability reduces both the time to learn and the frequency of modeling mistakes.  

Ambiguity - when there are multiple ways to interpret the conceptual model, our mind can jump to the wrong conclusion about how a system works.  If we're fortunate enough to notice the ambiguity, it still takes additional learning time to resolve our understanding.

These principles don't run completely counter to SOLID, but they definitely do in some cases.  Information distance in particular is often sacrificed for modularity.  I find myself breaking SOLID principles when there are cross-cutting concerns and it's not that easy to break things up neatly without disrupting the ease of conceptual modeling.  Having two sets of principles that outright conflict in these cases, at least make us aware that there's a tradeoff we need to consider.  

Sukant Hajra

unread,
Jan 24, 2015, 1:32:58 AM1/24/15
to agileau...@googlegroups.com
Excerpts from Janelle Klein's message of 2015-01-23 15:56:40 -0600:
>
> *Learning Time*
> *Modeling Mistakes*

I was expecting some of these responses, but not all. These two, I can't
really accept as problems with modularity. We are architects, and modules are
our fundamental tool.

We have to factor out the ease of familiarity when evaluating quality. All we
end up doing is conflating mistakes with progress as we make our risk
assessments. The point of understanding modularity in the first place is to
see anti-modularity clearly as faulty in the long-term. If we then have
resource problems, we can manage them as best as we can -- but never ignoring
the problem in front of us.

Also, we can't possibly say "don't make things modular because we might make a
mistake." It's a far worse mistake to not try at all. Just don't couple to
the module until it's quality is established.

Here's another way to put it. When some luxury good says they have a quality
product -- say a fine watch or car or something. And you evaluate it, and
determine that it's actually rather unimpressive. That manufacturer doesn't
get to say, "well it's 'quality' when you consider the context that we ran out
of money and resources." The only factors that measure into a product is how
it's used -- not the context under which it's made.

This is not to say the context under which something is made should be ignored.
It's just not much to do with the resultant quality, which can/will continue to
be evaluated well after the product is made. And SOLID can only speak to the
quality we get from modularity.

> *Ambiguity*
> *Distance*
> *Noise*

Please show me code to illustrate this, because I'm sure you can imagine code
that illustrates the exact opposite, which is the point of any illustration of
refactoring.

Good modules are not at all by definition ambiguous. And in my career, I've
never seen a good application of SOLID that increases distance or noise. You
can artificially create these problems by (to name a few)

- injecting a module needlessly for no compelling value (meaning the
remaining modules sufficient, but still SOLID)

- violating SOLID, but not admitting it

- choosing misleading names (which is very orthogonal to SOLID's concerns)

- hitting a wall and not seeing a workaround

- looking only at examples in a language that doesn't reward us much
syntactically for modularity.

Regarding the last point, languages like Java without lambdas are pretty
terrible. And language /does/ matter. For an extreme example, consider
looking at JVM byte code. At a glance, all the byte code looks the same. It's
only after deep analysis (maybe decompilation) that we understand which is good
or bad.

But even in Java, I found SOLID improved my code every time. Actually, I ended
up programming with less side-effects and ADT encodings too. Also, I was not
liberal about how many interfaces I made. SOLID makes a statement of what a
good interface is, but never advocates that we have interfaces everywhere. The
conventional application of SOLID in Java is ill-advised.

If anything, I think your arguments work at asserting that as principles SOLID
isn't enough. But I would add principles monotonically to them, not swap them
out for new ones.

So yeah, I'm pretty sure we don't have convincing arguments that the quality of
modularity is a relative, non-universal concept.

-Sukant

Janelle Klein

unread,
Jan 24, 2015, 8:05:25 AM1/24/15
to AA Dev SIG
That was more my point -- SOLID principles are good principles, they are just insufficient.   


-Sukant

Reply all
Reply to author
Forward
0 new messages