Subjects·10 topics·201 terms
Design patterns
Objects, SOLID, the Gang of Four catalogue, persistence and domain modelling, functional idioms and the named anti-patterns.
Start with these 58, in order
Objects, SOLID, the Gang of Four catalogue, persistence and domain modelling, and the named ways all of it goes wrong.
Read in order · tick what you already know
- 01
one class is four thousand lines and every feature branch touches it.
God objectArchitecture
- 02
there is a 3 in the middle of the expression and nobody left a note saying which three that is.
Magic number
- 03
two tests passed on their own and failed together, because the thing they both reached for kept state between them.
Singleton
- 04
there is an interface with one implementation and a config flag that has never been anything but its default.
Premature abstraction
- 05
adding one field meant small edits in eleven files, and the review caught the two you missed.
Shotgun surgery
- 06
understanding one method meant opening five files up and down the hierarchy, and then going back up again.
Yo-yo problem
- 07
someone described a solution in four words and everyone in the room pictured roughly the same code.
Design pattern
- 08
somebody says a pattern is 'GoF' and means it came from the 1994 book rather than from a framework.
Gang of Four
- 09
another team reached into the field directly, and now you cannot rename it without breaking them.
EncapsulationArchitecture
- 10
the same call site does three different things depending on what was passed in, and there is no branch anywhere.
Polymorphism
- 11
you got twenty methods you never asked for along with the one you wanted, and you cannot give any of them back.
Inheritance
- 12
you said it out loud — a Stack is a List — and it sounded fine right up until someone called insert in the middle of it.
Is-a vs has-a
- 13
the subclass needed one method overridden and inherited four others it never wanted and cannot remove.
Composition over inheritanceArchitecture
- 14
the method body is one line that calls the same method on a field, and that is the whole class's job for that method.
Delegation
- 15
someone rejected the pull request citing a five-letter acronym, and only two of the five letters were actually about the problem.
SOLID
- 16
two teams keep editing the same class for two entirely unrelated reasons and keep colliding.
Single responsibilityArchitecture
- 17
adding the fourth payment method meant editing the same switch statement for the fourth time.
Open–closed principle
- 18
the subclass threw on a method the parent promised, and every caller written against the parent was suddenly wrong.
Liskov substitution principle
- 19
you implemented an eleven-method interface to get at one of them and threw not-implemented from the other ten.
Interface segregation principle
- 20
the business rules import the Postgres driver, so testing a discount calculation needs a database.
Dependency inversionArchitecture
- 21
you wrote order.getCustomer().getAddress().getPostcode() and a change three objects away broke your line.
Law of DemeterArchitecture
- 22
the class asks for what it needs in its constructor and never goes looking, so a test can hand it anything.
Dependency injection
- 23
you stopped writing the loop and started writing the thing the framework calls, and you no longer decide when.
Inversion of control
- 24
the class asks a global object for what it needs mid-method, so its dependencies are invisible until it runs.
Service locator
- 25
the base class does the work and calls a method for the object it needs, and each subclass answers that with a different class.
Factory method
- 26
you swap one object at startup and the whole family of things it creates changes together, consistently.
Abstract factory
- 27
you set five things by name across five lines and call build, and the object does not exist until the last one.
Builder pattern
- 28
the object holds another object and forwards most calls to it, and which pattern that is depends entirely on why.
Wrapper
- 29
the library's method was called differently and returned the wrong shape, so you wrote a class that speaks both.
Adapter pattern
- 30
you replaced eleven calls across four classes with one method, and callers stopped needing to know the order.
Facade pattern
- 31
you wrapped the same interface in retries, then logging, then caching, and the caller still sees one thing.
Decorator pattern
- 32
the object looks and behaves exactly like the real one, and its whole job is deciding whether the call gets through.
Proxy pattern
- 33
the class takes the algorithm as a constructor argument, and choosing a different one is a different argument.
Strategy pattern
- 34
the object's behaviour changed after a call and nothing branched — it had swapped the object it was delegating to.
State pattern
- 35
the base class runs the five steps in order and leaves two of them abstract for you to write.
Template method
- 36
you changed one field and four other things updated, and finding out which four meant reading a subscription list.
Observer pattern
- 37
the request became an object with an execute method, so you could put it in a queue, log it and undo it.
Command pattern
- 38
you walked the collection without knowing whether it was an array, a tree or a paged remote call.
Iterator pattern
- 39
you added a new operation over the whole tree by writing one class, and did not touch any of the node types.
Visitor pattern
- 40
instead of returning null you returned something that implements the interface and does nothing, and the null checks disappeared.
Null object
- 41
the invalid cases return in the first four lines, and the rest of the method is not indented at all.
Guard clause
- 42
two of them with the same contents are interchangeable, so you never update one — you replace it.
Value object
- 43
two of them with identical fields are still different things, because the thing that makes them the same is the id.
Entity
- 44
you can change these five objects together in one transaction, and anything outside them has to wait its turn.
Aggregate
- 45
the objects have only fields and accessors, and every rule about them lives in a class ending in Service.
Anaemic domain model
- 46
the code asks for the customer as if from an in-memory collection, and where it actually came from is somewhere else.
Repository pattern
- 47
the object has a save method on it, so the thing that models an order also knows the table it lives in.
Active record
- 48
the domain object has no idea a database exists, and a separate class knows which column each field came from.
Data mapper
- 49
the browser posted to a controller, which changed the model and picked a view, and the view read the model itself.
Model-view-controller
- 50
the same use case runs from an HTTP handler, a message consumer and a test, and none of them is the primary one.
Hexagonal architecture
- 51
entities, then use cases, then adapters, then frameworks — and nothing in an inner circle names anything outside it.
Clean architecture
- 52
you called it twice with the same arguments, got the same answer, and nothing anywhere else changed.
Pure function
- 53
nothing that was handed out can be changed, so you stopped copying defensively and stopped worrying about who else holds it.
Immutability
- 54
the function's argument is another function, and what it actually does depends entirely on what you passed.
Higher-order function
- 55
the test passed alone and failed in the suite, and the difference was something another test had left behind.
Global mutable state
- 56
two modules import each other, and which one is initialised first decides whether it works.
Circular dependency
- 57
money is a decimal, the email is a string, and the validation for both is repeated in nine call sites.
Primitive obsession
- 58
the method calls five getters on another object and one on itself, so it belongs on that other object.
Feature envy
All of design patterns
Every term in this subject, 201 of them, grouped into 10 topics. Each topic is a track of its own.
Objects, messages and the principles
01 · 32 termsBefore any pattern there is a smaller question: what is one object allowed to know about another. Almost every named pattern is an answer to it, and almost every argument in a code review is really about it.
- Abstraction
- Programming to an interface
- Abstract class
- Polymorphism
- Dynamic dispatch
- Method overriding
- Method overloading
- Inheritance
- Is-a vs has-a
- Aggregation vs composition
- Delegation
- Fragile base class
- Subclass explosion
- Mixin
- Diamond problem
- Duck typing
- Nominal vs structural typing
- Covariance and contravariance
- SOLID
- Open–closed principle
- Liskov substitution principle
- Interface segregation principle
- Design by contract
- Class invariant
- Information hiding
- Getters and setters
- Tell, don't ask
- Object equality
- Reference vs value semantics
- Defensive copy
- Connascence
- Deep module
Making things
02 · 16 termsConstruction looks like the boring half until the constructor has nine arguments, the object is half-built for a moment, or two tests fight over the one instance. These are the patterns for deciding what gets built, by whom, and when.
Wiring: injection, containers and lifetimes
03 · 17 termsSomewhere a decision gets made about which concrete thing your code actually gets, and the whole testability of a codebase turns on where that somewhere is. This is the vocabulary of moving it out of the class and into one place.
- Hard-coded dependency
- Inversion of control
- Hollywood principle
- Dependency injection
- Constructor injection
- Setter injection
- Composition root
- Object graph
- Pure dependency injection
- Dependency injection container
- Autowiring
- Convention over configuration
- Lifetime scope
- Captive dependency
- Service locator
- Ambient context
- Late binding
Wrapping and composing
04 · 14 termsFour of these patterns are the same shape — an object that holds another object and forwards to it — and they are the four people mix up most. The difference is never the diagram; it is why the wrapper exists.
Who calls whom, and when
05 · 19 termsThese are the patterns about the flow of control rather than the shape of the objects: swapping an algorithm, reacting to a change, turning a request into a thing you can queue, undo or log.
- Strategy pattern
- Template method
- State pattern
- State machine
- Replace conditional with polymorphism
- Guard clause
- Null object
- Observer pattern
- Callback
- Mediator pattern
- Command pattern
- Memento pattern
- Chain of responsibility
- Iterator pattern
- Internal vs external iterator
- Generator
- Visitor pattern
- Double dispatch
- Interpreter pattern
Objects and the database between them
06 · 16 termsObjects have identity, references and behaviour; rows have keys, foreign keys and no behaviour at all. Every pattern here is a different position on how much of that gap to hide, and what each choice costs you later.
Modelling the domain
07 · 16 termsThe words a team uses when it stops arguing about frameworks and starts arguing about what an order actually is. These are the pieces a domain model is built from and the failure it decays into.
The shape of the whole application
08 · 19 termsZoomed all the way out, an application is a small number of regions and a rule about which way the arrows between them may point. These are the named shapes, and the differences between the ones people use interchangeably.
- Tier vs layer
- Model-view-controller
- Front controller
- Model-view-presenter
- Humble object
- Presentation model
- Model-view-viewmodel
- Two-way data binding
- Hexagonal architecture
- Dependency rule
- Onion architecture
- Clean architecture
- Use case interactor
- Package by feature
- Screaming architecture
- Plugin architecture
- Microkernel architecture
- Pipes and filters
- Blackboard pattern
Functional ideas that went mainstream
09 · 25 termsMost of these arrived in ordinary object-oriented codebases without the theory attached, and they are now said in reviews by people who have never written a line of Haskell. This is what they mean when they are.
- Pure function
- Side effect
- Referential transparency
- Functional core, imperative shell
- Immutability
- Copy-on-write
- Persistent data structure
- Structural sharing
- First-class function
- Higher-order function
- Map, filter, reduce
- Function composition
- Currying
- Partial application
- Lazy evaluation
- Tail call optimisation
- Algebraic data type
- Pattern matching
- Exhaustiveness checking
- Option type
- Result type
- Railway-oriented programming
- Monad
- Middleware
- Declarative vs imperative
The named ways it goes wrong
10 · 27 termsA pattern gives a good arrangement a name so it can be asked for. An anti-pattern gives a bad one a name so it can be pointed at without the argument starting from scratch, which is most of what these are for.
- Anti-pattern
- Spaghetti code
- Arrow anti-pattern
- Copy-paste programming
- Magic number
- Stringly typed
- Primitive obsession
- Boolean trap
- Long parameter list
- Feature envy
- Message chain
- Pass-through method
- Poltergeist
- Divergent change
- Shotgun surgery
- Refused bequest
- Yo-yo problem
- Global mutable state
- Hidden dependency
- Circular dependency
- Premature abstraction
- Cargo cult programming
- Inner-platform effect
- Dead code
- Lava flow
- Boat anchor
- Broken window