Clean Code

YAGNI, You Aren't Gonna Need It, Software Development, TypeScript, Clean Code

I built a plugin system for an internal tool. Configurable pipelines. Dynamic loading. Extension points. The tool had three users and never needed a singl...

19 Apr 2024

YAGNI, You Aren't Gonna Need It, Software Development, TypeScript, Clean Code

I built a plugin system for an internal tool. Configurable pipelines. Dynamic loading. Extension points. The tool had three users and never needed a single plugin. I spent two weeks building architecture nobody asked for.

That's the YAGNI violation in its purest form.

What YAGNI means

You Aren't Gonna Need It. Don't build functionality until you actually need it. Not when you might need it. Not when it seems like a good idea for the future. When there's a real requirement sitting in front of you.

The principle comes from Extreme Programming. It's a direct response to the natural developer instinct to over-engineer.

Why we over-build

Developers are pattern matchers. We see a feature and immediately imagine the five variations that might come next. So we build the abstraction that handles all six. The problem? Four of those variations never arrive. And the two that do look nothing like we predicted.

The result: code that's more complex than it needs to be, solving problems that don't exist, while making the real problems harder to solve because of all the unnecessary abstraction in the way.

YAGNI in practice

Start minimal. Build the simplest version that solves the current requirement. No speculative error handling for cases that haven't happened. No optimization for scale you haven't reached.

Defer abstractions. Don't create a base class, interface hierarchy, or plugin system until you have concrete evidence it's needed. Two concrete implementations are usually better than one premature abstraction.

Write tests for what exists. In TDD, write tests for the current behavior. Don't write tests for hypothetical future requirements — they'll constrain your design toward an imagined future instead of the real one.

Refactor when needs emerge. When a new requirement actually arrives, refactor the code to accommodate it. This is different from building for it upfront. Refactoring is responding to real information. Over-engineering is guessing.

How to tell if you're violating YAGNI

Ask yourself: "Is there a ticket for this?" If the answer is no — if you're building for a scenario someone mentioned in a meeting, or one you imagined in the shower — stop. Build what's needed today.

Another test: "Who uses this?" If an abstraction, configuration option, or extension point has zero or one consumers, it probably shouldn't exist yet.

The trade-off

YAGNI saves you from wasted work. But taken to an extreme, it can leave you with code that's hard to extend when real requirements do arrive.

The balance: build simply, but build cleanly. Clean code is easy to extend later. You don't need to predict the future — you just need code that's easy to change when the future shows up.

YAGNI doesn't mean don't think ahead. It means don't build ahead. Plan loosely. Build tightly. Refactor when reality arrives.