I read the Gang of Four book in my second year as a developer. All of it, cover to cover, over about three weeks of train rides. I could have told you that there are 23 patterns split into creational, structural and behavioral. A month later someone in a code review asked why I hadn't used a Strategy instead of a giant switch, and I just stared at the screen. I knew the word. I had no idea when it applied.
That's the usual way design patterns go wrong. People learn the names and the UML diagrams, and then can't spot the problem a pattern solves when it's sitting in front of them. Or worse, they spot patterns everywhere and wrap a three-line function in a Factory, an Interface and a Builder.
Here's how I'd learn them if I started over.
Learn the problem before the pattern
Every pattern is an answer to a specific kind of pain. If you memorize the answer without the pain, there's nothing to trigger the memory later.
So for each pattern, write down one sentence about the situation that hurts. Something like:
- Strategy: "I have a
switchon a type, and every new type means editing this function again." - Observer: "Five different parts of the app need to know when this one thing changes, and I'm calling them all by hand."
- Adapter: "This library's interface doesn't match what the rest of my code expects."
- Decorator: "I want to add logging or caching around something without touching it."
That sentence is the thing you're really trying to remember. The class diagram is secondary. When you meet that situation at work, the sentence fires, and the pattern name comes with it.
Start with five, not twenty-three
Most of the original 23 you'll rarely write yourself. Some are baked into your language already. Iterator is a for loop in nearly everything now, and in JavaScript a lot of Observer is just event listeners and callbacks.
The ones I see in real codebases week after week are Strategy, Observer, Factory, Adapter and Decorator. Learn those properly first. Builder and Singleton are worth knowing mostly so you recognize them (and so you can argue about Singleton in code reviews, which seems to be a rite of passage).
Once those five feel natural, the rest are much easier, because most of them are variations on "put an interface in the middle and swap what's behind it."
Write a bad version first
This is the step that actually made it click for me.
Pick a small problem and solve it the naive way. A shipping cost calculator works well: standard, express and international shipping, each with its own rules. Write it as one function with an if/else chain. Then add a fourth shipping option and notice how annoying it is. You edit the same function again, the tests for the old options run again, and the function gets longer.
Now refactor it into Strategy. Each shipping type becomes its own small class or function with the same signature, and the calculator just calls whichever one it's given. Add a fifth option and feel how little you had to touch.
That feeling is the lesson. You can't get it from a diagram. Doing the before-and-after once per pattern, in your main language, takes maybe an hour each and beats rereading a chapter five times.
Find them in code you already use
Patterns are much easier to remember when you've seen them in the wild. A few places to look:
- Express and Koa middleware are a chain of responsibility, and wrapping a handler with logging is basically a decorator.
- React's context and most state libraries lean on observer-style subscriptions.
- Java's
InputStreamwrappers (BufferedInputStreamaround aFileInputStream) are the textbook Decorator. - Any "driver" or "provider" layer, like database clients that talk to Postgres or MySQL behind one interface, is usually an Adapter or a Strategy.
When you notice one, write it down next to your problem sentence. "Strategy: payment providers in our checkout service." Real examples from your own work are the stickiest memory hooks there are.
Then come back to them before they fade
This is where I failed the first time. I learned patterns in a burst, then didn't touch most of them for months. Observer stayed because I used it constantly. Visitor and Memento were gone by the end of the quarter.
The fix is reviewing on a schedule. Keep your list of patterns with their problem sentences and examples. Look at it again the next day, then a few days later, then a week or two after that. Each time, cover the pattern name, read only the problem sentence, and try to name the pattern and sketch it from memory. If you get it, push it further out. If you don't, bring it back sooner. That's spaced repetition, and it works just as well for "which pattern fits here" as it does for vocabulary.
I build Recl, and this is the kind of learning I made it for. A lot of what I know about patterns came from conference talks on YouTube and long blog posts, the "Refactoring a 500-line switch statement" kind. I'd watch one, think "that's clever," and lose it within a week. Now I save the talk or article from the Chrome extension or my phone's share menu. Recl writes a summary with the key takeaways, files it under a topic like "Design patterns," and later sends me a recall question about it, so I get tested before it slips.
A plain notes file and a calendar reminder do the same job if you'd rather not use an app. What matters is seeing each pattern again a few times, spaced out, instead of rereading the whole book when an interview comes up.
Know when not to use one
Last thing. Part of knowing a pattern is knowing when it's overkill. If there's only one shipping method and there will only ever be one, a Strategy is just extra files. A good rule I picked up from a senior dev: wait until you've felt the pain twice, then reach for the pattern on the third time.
Start with Strategy this week. Find one switch in your codebase that keeps growing, and refactor it.
I build Recl, an AI learning app that saves the videos, reels and articles you learn from, summarizes them, sorts them into topics, and uses spaced repetition so you actually remember them.


Top comments (0)