Skip to main content

Command Palette

Search for a command to run...

Design Patterns Are Not a Developer Thing

Updated
5 min read
A

Platform Engineer + CNCF Ambassador, AWS community builder. I design scalable cloud-native platforms and love making teams faster and safer.

Design Patterns Are Not a Developer Thing

At some point, most platform engineers end up in a conversation with a senior dev or a software architect where you're trying to explain how your infrastructure works.

And somewhere in the middle of that conversation, something clicks. You're both describing the same problems. You're reaching for the same solutions. The only difference is the vocabulary — they say "Facade", you say "developer abstraction layer". They say "Observer pattern", you say "controller loop". They say "Command", you say "GitOps".

Same architecture. Different words.

What I've found is that design patterns aren't really a software thing. They're a complexity thing. And if there's one domain that deals with complexity at scale every single day, it's platform engineering.

This post is the first in a series that explores exactly that.


The problem with how design patterns are taught

Design patterns come from a book called Design Patterns, published in 1994 by four authors the industry nicknamed the "Gang of Four" (GoF). The book is genuinely great. It's also full of examples like "imagine you have a WordDocument class and you need a PDFDocument class..."

If your day-to-day doesn't involve classes and inheritance, that framing is just noise.

But the patterns themselves aren't really about code. They're about how to deal with complexity as a system grows. And platforms have exactly those problems — just at a different scale and with different tools.

The thesis of this series is pretty straightforward: the design patterns developers learned in school or from a book? You're already applying them in your platform. Nobody just introduced them by name.


Three quick examples to make the case

The Facade: why platform teams exist in the first place

The Facade pattern says that when a system gets too complex, you build a simplified interface on top. Consumers talk to the facade, not to the guts of the system.

That's exactly what an Internal Developer Platform does. Your developers shouldn't need to know whether a secret comes from Vault, AWS Secrets Manager, or a ConfigMap. They shouldn't need to care which CNI the cluster runs, or how the ingress controller works under the hood. The platform is the facade. You're the one designing it.

When your team debates whether to expose Kubernetes directly to developers or abstract it behind a Backstage template — that's a conversation about how much facade to build. That's design work, not ops work.

The Observer: the controller loop you already know

The Observer pattern says that when an object's state changes, everything that depends on it gets notified automatically.

The Kubernetes controller loop is exactly that, implemented at cluster scale. There's a desired state (what's in etcd), an actual state (what's running), and controllers that watch the gap and act on it. Argo Rollouts watches Prometheus metrics to decide whether a canary should keep going or roll back. External Secrets Operator watches Vault for changes and syncs secrets accordingly.

Every operator you write or adopt is an implementation of the Observer pattern. Knowing that helps you decide when writing one actually makes sense — and when it's just adding complexity for fun.

The Command: why GitOps makes sense from first principles

The Command pattern says that instead of executing an action directly, you wrap it in an object that can be stored, passed around, undone, or audited.

A commit in your GitOps repo is exactly that. It's not just a text change. It's a persisted command — with an author, a timestamp, and the ability to be reversed with a git revert. ArgoCD or Flux is the executor that takes that command and applies it to the cluster.

The question "why GitOps instead of pipelines that just run kubectl apply?" has a deeper answer than "because it's best practice." It has an architectural answer: because separating the command from its execution gives you properties — auditability, reversibility, a single source of truth — that you'd otherwise have to build from scratch.


Where this is going

This is just the hook. The rest of the series goes pattern by pattern, connecting each one to real platform decisions:

  • Factory and Builder → how an IDP thinks when it provisions environments
  • Facade → the cost of cognitive load and the Golden Path
  • Observer → when to write an operator and when to step back
  • Command → GitOps explained from first principles
  • Adapter → why the Kubernetes ecosystem is basically a catalog of adapters, and why that's a feature
  • Strategy → why hardcoding your deployment strategy into the pipeline is an antipattern

The goal isn't for you to finish this series knowing more pattern trivia. The goal is that next time you make a platform decision, you have better vocabulary to explain it, defend it, or challenge it.

There's a practical side to this that I find underrated: patterns also help you diagnose problems. If your pipelines are slow and tightly coupled, that's not just a pipeline problem — that's a symptom of missing separation of concerns, which maps directly to specific patterns that exist precisely to solve it. Once you can name what's wrong architecturally, the solution space gets a lot clearer. You stop googling "how to speed up my CI pipeline" and start asking "what's the right pattern for decoupling this."

Because the difference between a team that operates infrastructure and one that designs a platform isn't the tool stack. It's whether they're making architectural decisions on purpose — or just stumbling into them.


If this resonates, the next posts go deeper on each pattern. You can follow along or reply directly at blog@parraletz.dev — I read everything.

More from this blog

Alejandro Parra's Blog

16 posts