
Design Patterns – A comprehensible guide - kamranahmed_se
https://github.com/kamranahmedse/design-patterns-for-humans/blob/master/README.md
======
js8
In a galaxy far far away, there was a kingdom where people didn't know
structured programming. Their programming languages only had (conditial)
branches, jumps, or GOTOs (as they were colloquially called). And they had a
very influential programming book, called "GOTO design patterns". Here's a few
examples of design patterns from the book:

\- "IF pattern" \- If you need to execute code only if some condition is true,
you write a conditional GOTO that lands after the code that is to be executed
conditionally.

\- "IF-ELSE pattern" \- If you need to execute code only if some condition is
true, and some other code if the condition is false, you use IF-ELSE pattern.
It's similar to IF pattern, but at the end of the code in the IF pattern, you
add another unconditional GOTO that branches after the code that is to be
executed if the condition is false.

\- "WHILE pattern" \- If you need to repeatedly execute code and check some
condition after each execution, you add a conditional GOTO at the end of the
code that goes _back_ to the beginning of the code you want to repeatedly
execute.

\- "BREAK pattern" \- This is a pattern to use with the WHILE or UNTIL
patterns. If you need to, on some condition, stop repeated execution of the
code in the middle of the code, you add a conditional GOTO into the middle of
the code that just branches _after_ the repeatedly executed code block.

Everyone was happy with the book. No more messy spaghetti code full of random
GOTOs (as was common before the book appeared), because young apprentices
memorized all the patterns in the book, and they just applied them rigorously.
Also, understanding code became easier, because everybody instantly recognized
those patterns in the well written code, and they had a common vocabulary to
talk about these things.

One day, a traveler from another world came into this kingdom. He looked at
the book and wondered: "Why don't you just add these patterns into your
computer language as abstractions? Wouldn't that aid comprehension even more?"
Unfortunately, he was executed for the heresy.

~~~
thom
This is, and always has been, a poor criticism of design patterns, by people
who think they're just a library of code that idiots are supposed to cut and
paste to be better programmers.

A common example from the GoF book is the Strategy pattern - most functional
programming snarks will jump in and say you don't need this! We have first
class functions you can pass around! And it's entirely true that an
implementation of this pattern (a good, simple one even) is just accepting
functions as arguments - cool, you probably get it! But the _design_ principle
is about making strategies _explicit_ - allowing decisions to be made or
policies to be enforced in ways you don't anticipate. I still see _tons_ of
libraries written by smart people in functional languages that will still
accept an enum of some kind to tell them what do in certain situations (e.g. a
lot of HTTP libraries' extremely limited retry logic). That's an explicit
design decision - to limit options instead of opening them up. Having a
language to talk about the _design decisions_ at a higher level, instead of
conflating them with language features, is the whole point. Everybody knows
you can pass functions around as arguments, that doesn't necessarily prompt
you or make it easier to discuss implementing a Strategy.

Design patterns aren't a static, finite set of code snippets, and I actually
think things like the linked post that mostly treat them that way aren't
helpful. They give you a way of naming and talking about components of a
design, possibly at a higher granularity than your programming language (and
sure, different languages have different granularities).

We've been hearing this same exact criticism for literally 20 years and it's
boring at this point. I get that most people don't bother creating new design
patterns in public these days (because they've internalised that modern
languages have 'design patterns' built in), but if you look at something like
React and think it's just JavaScript and there are no design decisions in
there worthy of reifying, I think that's sad and unproductive.

~~~
js8
My main point (just to make sure we are on the same page) was that whatever
patterns are, we should also tell computers "look, here I use this pattern",
and not rely just on humans to see it. Unfortunately, computers are idiot
savants, so this very well might require those to be formally defined.

Anyway, I think we have an ontological disagreement here. I don't believe the
"design patterns" which cannot be formally defined are useful, or even that
they exist. I consider them to be just phantoms, which when you attempt to
formally define them, you either understand them much better (to the point
where you can see how they are related), or they disappear as something that
was misconceived in the first place. You seem to think that there is something
real.. fine.

Possibly, why I see it that way is my mathematical training. In mathematics,
this battle was fought more than a century ago and the formalism camp won.
That doesn't mean that intuition is completely useless.. just that people
mostly keep their intuitions (and inspirations and analogies) for themselves,
and when they communicate, they strive to be formal.

To your React example - it's not a pattern, it's a piece of concrete reusable
code. We don't need "React pattern", but we need React. Just like
mathematicians, we should communicate "patterns" via reusable code.

~~~
thom
But you don't _talk_ exclusively in formalisms to other mathemeticians, do
you? You don't immediately jump into a specific form of calculus upon first
hearing of a concrete real world problem?

And I'm not saying React itself is a pattern. I'm saying if you wanted to
create your own React-like framework, or to communicate the design decisions
and mechanisms that make it different from other frameworks, there is value in
extracting and naming those concepts. This way, people can appreciate,
understand, compare and contrast them _outside_ the context of one piece of
concrete reusable code. As an entirely throwaway and unthought-out example,
you might say 'Differential Rendering' is philosophically different to a
'Mutable Document'.

But if you think all things in the design of software are reducable to
reusable pieces of code, more power to you.

~~~
js8
> But you don't _talk_ exclusively in formalisms to other mathemeticians, do
> you?

In informal setting (like lecture or workshop), maybe not. But when
publishing, you always talk in concepts that are defined formally. That
doesn't mean that you use formal language all the time, but every time you
introduce some definition or term, it is understood (obvious) that you could
provide completely formal definition. Also, having a formal definition doesn't
preclude using motivational examples.

So no, I don't think a book like "Design Patterns" could happen in
professional mathematics today. Mathematicians simply don't introduce shared
vocabulary of informal definitions. But it wasn't always like this - Euler
used words like "curve" without having a completely formal definition (and
without worrying about it). But eventually we learned this was a problem, and
I think we will learn the same about programming patterns (and that's why
people IMHO largely stopped trying to name new patterns).

> And I'm not saying React itself is a pattern.

Yeah, I understand, I was just taking a rhetorical shortcut. What I am saying
you should be able to point at a set of functions of React and say "these
embody one of the ideas behind React" (although there can be technical reasons
that prevent doing exactly that on the current React codebase). Then the
"pattern" you have in mind is well-defined by these functions.

> But if you think all things in the design of software are reducable to
> reusable pieces of code, more power to you.

I think it must be, because the "pieces of code" is the ultimate end goal. So
there must be a point where the informal definition of pattern gets translated
into formal code. And to do this translation reliably, you need to be able to
enumerate (or parametrize) the choice of formal options that stem from the
informal concept, and this process is actually the formalization of said
concept.

I would say the software design patterns are rather special case, because they
involve code readable by computer. In contrast, the original design patterns
in architecture don't need to relate to computer code (there is no code
reuse), so they are perfectly fine with not being formally defined.

~~~
thom
I guess I just don't inhabit this world where there is nothing more to
software design than reading and writing code. I write comments, I read
readmes and documentation, and I find shared, human descriptions of larger
granularity design abstractions useful. ¯\\_(ツ)_/¯

~~~
js8
> I write comments, I read readmes and documentation, and I find shared, human
> descriptions of larger granularity design abstractions useful.

Oh, I have nothing against that, except the word "shared". I just don't think
that "design patterns" (from the GoF book) helpfully contribute to that. In
practice, it really depends what you want or don't want to gloss over as a
technical detail, and just saying "there is this pattern" doesn't give you
enough flexibility to do it.

What I am saying there is a trade off - if you decide to name something, you
should define it well enough not to be misunderstood. If you can't or don't
want to define it well enough, better not name it at all (except maybe
temporarily), just describe your intuitions/feelings about it. The authors of
"design patterns" seem to be oblivious to this trade off (although I think it
wasn't really their fault that the names for patterns got so popular, I think
they just wanted to have fancy chapter titles).

It's interesting though. When I describe how something works or should work, I
use terms like "client", "server", "memory", "unique random number", "sort
by", "find maximum", "queue", "remote call", "common API" etc. But I never
found a compelling reason to describe things in names of (standard) design
patterns. Why are not these terms considered to be design patterns? In my
opinion, it is because the design patterns tend to be overly specific in some
ways (talking about class/interface relations) without adding enough substance
to be meaningful on their own.

So I don't find them useful to describe design (overly specific), nor I find
them useful to describe code (not formal enough). They are just kind of
slippery for both use cases.

------
TillE
I appreciate the effort, but one of my pet peeves with OO / design pattern
examples is when they're completely contrived.

Once you've understood the very basics of OO, I think talking about a door
factory or a burger builder tends to obfuscate real-world usage more than it
aids comprehension. I have this problem with _most_ science/technology
analogies, to be honest.

~~~
sna1l
It would be great if there was a resource with real world examples, since I
have this exact same problem.

~~~
rezashirazian
I implemented some of the more popular design patterns using more real life
like examples. You might find them useful :

[https://shirazian.wordpress.com/2016/04/11/design-
patterns-i...](https://shirazian.wordpress.com/2016/04/11/design-patterns-in-
swift/)

------
opk
The main value of the design patterns is that they have given names to things
that were already common and fairly intuitive to a half decent programmer.

But I've come across many people trying to use them as a guide for how to
write code - and misunderstanding them. Factory in particular is often
misunderstood. It is mainly useful when you have parallel class hierarchies
not as some odd wrapper around all the constructors in the software.

~~~
dack
I'm not sure what you mean by parallel class hierarchies. I use a factory if I
have a class that needs to be able to make an instance of some other class,
but shouldn't know about how to construct it (i.e. it doesn't need to know
about the dependencies that other class might need to function).

~~~
qznc
I also do not understand "parallel class hierarchies".

Here is another use case for a factory: Building an AST data structure in a
compiler. There are nodes to represent Constants, Addition, FunctionCalls, etc
and you have to build a tree structure, which represents a program.

Now consider the case, where you build the addition of two constants ("36 +
6"). Using constructors, it could like like: new Add(new Const("36"), new
Const("6"));

Using a factory: f.newAdd(f.newConst("36"), f.newConst("6"))

The advantage of the factory is that it can optimize on the fly and return a
Const("42") node instead of an Add.

~~~
thealistra
To be a cool compiler, you don't want to optimize this in the AST building
phase. The user may be running in a mode of printing the AST only, to e.g.
implement their own autocompletion. This code obfuscates the truth by doing
this.

I remember that at some point gcc -O 0 was doing exactly that and it is pretty
irritating if you write a decompiler and want to test it. Fortunately clang
does it properly.

------
ktRolster
The reason I like Lisp is because programming in it teaches you how to
organize your code well using the most basic and important design pattern: the
function.

~~~
BuuQu9hu
Design patterns are patterns which can be used for designs. All patterns can
be used for designs; "design pattern" as a phrase merely signals that the
pattern was described in a certain book.

Functions are too simple and concrete to be patterns. A function is a mapping
from one set to another. Even category theory manages to fully generalize
functions several different ways without managing to define something as
general as a pattern.

So, you might ask, what _are_ patterns? Patterns are things which repeat
somehow. That's it. There might be more to it, but I have yet to find it.

I'm glad that you like Lisp, but it's not the beginning nor the end of
programming. For example, the Post correspondence problem is Turing-complete.
So are Wang tiles. Where's your functions now?

~~~
waynecolvin
I believe ktRolster may be refering to "Procedural Abstration". The term is
used in SICP [1] (the Wizard Book using scheme, previously freshman
programming text at MIT).

Abstration can take many forms. But can often be described as "seperating
things that change and/or repeat from those that don't", or something like
that.

The last paragraph may be a joke, or based on one of the Principles in the
O'Reilly Design Patterns [2] book.

[1] [https://mitpress.mit.edu/sicp/](https://mitpress.mit.edu/sicp/) [2]
[http://shop.oreilly.com/product/mobile/9780596007126.do](http://shop.oreilly.com/product/mobile/9780596007126.do)

------
swsieber
I think the reason that some of these patterns seem so terrible in real code
is limited static type systems / OO - I'm specifically looking at Java, and
it's terrible type erasure, and poor (but getting better) functional
programming support.

------
coleifer
Stop the for humans meme. Try-hards use it to signal that they're "in" but its
outlived any meaning beyond some meta-meaning which is no meaning at all. Just
make your project quality. Don't proclaim it, just do it.

~~~
LyndsySimon
Note: this comment should not apply to Kenneth Reitz.

------
prefect42
One can argue these topics until the cows come home, and possibly later. One
can strongly argue for/against imperative programming, functional programming,
OOP, design patterns, Design Patterns with Cool Names, Design Patterns as
Implemented in Your Favorite Language, etc... At the end of the day, the only
thing that matters is whether your team thinks your source code is structured
or not. If you're on a team of one, well then you have your future self to
contend with.

------
0x54MUR41
In my opinion, iluwatar's design pattern guide [1] provides more examples than
this. It gives not only implementation examples but also a class diagram and
use case for each design pattern. The examples were implemented in Java.

[1]: [https://github.com/iluwatar/java-design-
patterns](https://github.com/iluwatar/java-design-patterns)

------
alashley
I wish there was a resource that goes over design patterns with more abstract
concepts/classes. I found the example in GoF to be somewhat useful but at a
certain point (near the middle) I got lost in the details.

~~~
dack
You want more abstract examples? Or more abstract patterns?

~~~
alashley
More abstract examples.

------
wenbert
Thanks for this. And I just realised, examples are in PHP!

------
ilugaslifg
Object-oriented programming is a disease, and I can't wait until we're
collectively done with it.

All of these abstractions, when rarely they are actually needed to express a
program, can be naturally expressed within the type system, in a proper
functional language.

The fact that there's this encyclopedia of hundreds of discrete things with
arcane toxic names that practitioners are required to individually learn and
carry around in their heads, is a crime against our profession.

~~~
iak8god
I dislike OOP. It's my least favorite paradigm. The "objects-first" approach
to teaching programming was _such_ a bad idea.

All that said, there is a place for OOP. And while a world without OOP would
be a better place than a world without FP (if we had to choose), I think
you'll be waiting a looong time for that world to materialize.

~~~
LyndsySimon
I've spent the vast majority of my career in OO-centric projects, but between
my experience in Javascript and Clojure I've begun to see OO as FP with a
layer of syntactic sugar. Objects are just closures at the end of the day,
after all.

The mental fun was when it dawned on me that most of the benefit from the FP I
was falling in love with was coming not from FP itself, but from the liberal
use of immutability... and that OOP can be written in a way that similarly
embraces immutability.

I don't know if my OO code got better or worse from an outside perspective
once I realized that, but it certainly made it easier for me to reason about
my experimental side projects.

------
brockvond
why on github and not on like... medium?

~~~
LyndsySimon
Off the top of my head:

1\. GitHub is a broadly-adopted tool that the author probably already knew how
to use

2\. It's hard to accept PRs on Medium

3\. It allows the author to list the repository on his profile, thereby
helping them convey competency to potential employers

4\. It's easier to archive a git repo than a Medium post, and easier to rehost
elsewhere in the future if/when GitHub dies.

5\. Git allows change tracking.

6\. It uses Markdown, which can be processed through automated tools to
produce a variety of formats, from PDFs for email to EPUB to send to a
physical publisher.

~~~
brockvond
lol - that's a good list. thank you.

