Module 2 · ~10 min
🦥 The "laziest thing that works" method
You'll leave able to stop the AI from over-building — and ship the smallest version that actually works.
The problem: AI loves to over-build
Ask an AI to "build a tool to track X" and it will cheerfully hand you a database, an auth system, a job queue, three services, and a Dockerfile you can't deploy. It's not wrong — it's just eager. Left unchecked, that eagerness is exactly why your project never ships: you can't deploy or afford the thing it built.
The fix isn't a better prompt. It's a posture you hold on every request: the laziest thing that works. Lazy means efficient, not careless — the best code is the code you never had to write, because there's nothing to debug at 3am.
The ladder (stop at the first rung that holds)
Before writing anything, walk down this ladder and stop the moment a rung holds:
- Does this need to exist at all? Speculative "we might need it later" → skip it. Later can build later.
- Does the standard library / platform already do it?
<input type="date">instead of a date-picker library. CSS instead of JS. A DB constraint instead of app code. - Does something already installed solve it? Never add a new dependency for what a few lines can do.
- Can it be one line? Then it's one line.
- Only then: the minimum code that works.
Real example. An app needed a "max reps over time" chart. The AI reached for a charting library (a dependency, a bundle, config). The lazy answer was a hand-drawn SVG sparkline — a dozen lines, no dependency, renders instantly. Two rungs up the ladder, done.
How to steer Claude Code
- Turn on a lazy posture. A "be lazy / laziest solution" instruction (or a plugin that enforces it) makes the AI default to deletion over addition and flag its own over-building. Ask for the smallest version by name.
- Ask for the version and the question in one breath: "Ship the smallest thing that works, then tell me what you skipped and when I'd actually need it." Now you get a working app and a map of the deferred complexity.
- Demand one runnable check behind any non-trivial logic — a branch, a loop, a parser, anything touching money or auth. The smallest thing that fails if the logic breaks. Not a test suite; one assert.
- Push back on new dependencies. "Can we do this with what's already here?" is the highest-leverage question you can ask an AI.
Build the smallest version of <feature> that works.
Rules:
- No new dependencies unless a few lines genuinely can't do it.
- Prefer the standard library / native platform features first.
- No abstractions for a single use — no interface with one impl,
no config for a value that never changes.
Then, in three lines: what did you skip, and when would I add it back?
Ship the lazy version, question it in the same breath
You don't have to choose between "move fast" and "do it right." Ship the lazy version and name its ceiling in the same response: "Did X the simple way; it's O(n²) but n is tiny — upgrade to a map if it ever gets big." Now the shortcut is a documented decision, not a landmine. That single habit is most of what separates a fleet that ships from a folder of half-built repos.
🦥 The rule of thumb: the shortest working diff wins. If your explanation of why the code is complex is longer than the code, the complexity is the problem — delete it.
When NOT to be lazy
Laziness has hard exceptions. Never simplify away: input validation at trust boundaries, error handling that prevents data loss, security, accessibility basics, or anything the user explicitly asked for. We'll spend all of Module 5 being deliberately un-lazy about exactly one thing: money.
Your turn ✅
- Take your Module 1 idea and ask Claude Code for the smallest version that works.
- Make it list what it skipped — read that list, don't skip it.
- Kill one thing it built that you didn't actually need yet.
- Confirm there's one runnable check behind any real logic.