Tech Insights

Software Design Patterns

Design patterns are a shared vocabulary and a set of proven moves - not a checklist of "good code." Here is how to use them like a senior engineer.

Diagram of common software design patterns

TL;DR

Design patterns are a shared vocabulary and a set of proven moves, not a checklist of good code. The Gang of Four catalog groups them into creational, structural and behavioral patterns. Senior engineers refactor toward patterns when the code calls for them, never force them in early, and know modern languages often offer lighter tools.

On this page

The word is the pattern

The first time you watch two experienced engineers design something on a whiteboard, what strikes you is the shorthand. “We’ll Adapter the vendor SDK.” “Make pricing a Strategy.” “That’s basically Observer.” A decade of accumulated design wisdom flows in three-word sentences. That is the real gift of the Gang of Four catalog: not the 23 class diagrams, but a shared vocabulary that lets a team reason about structure at speed.

It helps to remember where patterns came from. The four authors of the 1994 book did not invent these solutions; they mined them from real C++ and Smalltalk systems, noticing that good designers kept reaching the same shapes for the same problems. A pattern is a discovery, written down. That origin tells you exactly how to treat it: as evidence of what tends to work, not as a rule you must obey.

Three buckets, one idea

The catalog splits into creational (how objects are made), structural (how they are composed), and behavioral (how they collaborate). But underneath the taxonomy sits a single recurring idea, and it is worth more than any individual pattern: depend on abstractions, and prefer composition over inheritance.

Almost every pattern is a variation on that theme. Factory Method moves the decision of which class to instantiate out of the caller. Strategy moves the algorithm out of the caller. Decorator stacks behaviour by wrapping rather than subclassing. Adapter lets two incompatible interfaces collaborate without either knowing about the other. Observer lets a subject broadcast change without naming a single listener. In each case, a hard-wired dependency becomes a pluggable seam. If you internalize only that - put a seam where change is likely, and inject behaviour instead of hard-coding it - you have absorbed eighty percent of the value of the entire catalog.

The trap on the far side of learning

There is a predictable arc to learning patterns. First you cannot see them; your code is a thicket of nested conditionals. Then you learn them and - this is the dangerous phase - you see them everywhere. Every constructor becomes a Factory, every class grows an interface with one implementation, every function sprouts a Strategy with a single strategy. This is pattern-itis, and it produces code that is harder to read than the mess it replaced. The indirection is real; the flexibility it supposedly buys is imaginary.

The cure is a principle borrowed from agile practice: YAGNI - You Aren’t Gonna Need It. A pattern is a cost paid in indirection, and it only earns that cost when it relieves current, demonstrated pain. Speculative flexibility - “we might need to swap databases someday” - is a benefit you usually never collect, paid for with complexity you carry forever. Pair YAGNI with the Rule of Three: do not abstract until you have seen the same thing three times. Two examples are a coincidence; three are a pattern worth naming.

Refactor toward them, never at them

So how do you use patterns correctly? You do not choose one at the start. You let it emerge. Martin Fowler’s enduring lesson is that you refactor toward a pattern: begin with working code, notice a smell, and take small, safe, behaviour-preserving steps that happen to land on a known shape.

A large switch on a type code is not “a place to put Strategy.” It is a smell. You respond by giving each branch its own home - a function or a polymorphic method - and that is what turns out to be Strategy. The pattern is the destination you reach because the code asked for it, not a decision you made before you understood the problem. This is why smells matter more than the catalog: the smell tells you something is wrong now, with evidence, and the pattern is merely one possible response. Sometimes the right response is just “extract a function.” Not every smell deserves a name from a book.

Lighter tools for a newer era

It is worth saying plainly that many GoF patterns are partly historical artifacts. They were workarounds for the rigidity of 1990s C++ and early Java, languages without first-class functions or rich standard libraries. In modern Python, JavaScript, or any functional-leaning language, the heavyweight machinery often dissolves. A Strategy is a function you pass as an argument. A Command is a closure. An Observer is a list of callbacks. An Iterator is a built-in protocol you never implement by hand. A Singleton is a module - or, better, a single instance you create at the edge of your program and inject where it is needed, instead of baking globalness into a class and wrecking your tests.

The patterns are not obsolete, but their implementations should be as light as your language permits. The intent - vary this algorithm, react to that change, hide this complexity - is timeless. The class hierarchy is not.

The senior engineer’s stance

Pull it together and a working philosophy emerges. Learn the principles first; SOLID describes the qualities of a design that bends instead of breaking, and every pattern is a concrete way to honour one of them. Treat the catalog as a vocabulary and a toolbox, not a blueprint. Reach for a pattern to relieve pain you can point to, express it in the lightest form your language offers, and keep the nerve to remove a pattern when it stops paying for itself - because deleting an abstraction that no longer earns its keep is as much a craft as adding one.

Good design has never been the code with the most patterns in it. It is the simplest code that gracefully absorbs the changes you actually face. The patterns are how you get there when the simple version stops being enough - and knowing when it has is the whole job.

Key takeaways 5

  1. Patterns give teams a shared vocabulary for design.
  2. The Gang of Four grouped them into creational, structural and behavioral.
  3. Overusing patterns creates needless complexity.
  4. Refactor toward a pattern when the code calls for it.
  5. Modern language features often replace heavyweight patterns.

Watch & learn

10 Design Patterns Explained in 10 MinutesFireship · YouTube

Frequently asked questions

What are software design patterns?

Design patterns are reusable solutions to common design problems, described by name, intent and structure, such as Strategy, Observer, Adapter and Factory.

What is the Gang of Four?

The Gang of Four are Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides, authors of the 1994 book Design Patterns: Elements of Reusable Object-Oriented Software, which catalogued 23 patterns.

Should I use design patterns everywhere?

No. Use them when they solve a real problem in your code. Applying patterns prematurely adds abstraction and makes code harder to understand.

Tech InsightsProjects & Practice#Design Patterns#Software Architecture#SOLID#Refactoring#Object-Oriented Design

Comments

No comments yet. Start the conversation.

Comments are reviewed before they appear. Be kind; one link max.

Go deeper with the free masterclass

Workshop, PDF handbook and curated resources for “Software Design Patterns”.

Open AL Academy ↗
Keep reading

Related articles