Your first design idea is unlikely to be the best. But you'll never know unless you force yourself to consider alternatives. "Design It Twice" — from John Ousterhout's A Philosophy of Software Design — means generating at least two radically different approaches before committing to one.
Claude Code makes this practical: you can spin up parallel sub-agents that each explore a different design constraint, then compare the results side by side.
This technique is informed by Matt Pocock's design-an-interface skill.
The prompt
I need to design the interface for [describe your module/component/API].
## Requirements
- [What problem does it solve?]
- [Who are the callers? Other modules, external users, tests?]
- [What are the key operations?]
- [Any constraints? Performance, compatibility, existing patterns?]
## Process
Generate 3 radically different designs. Each must take a fundamentally different approach — not minor variations. To force divergence, apply these constraints:
- **Design A**: Minimize the interface. Aim for 1-3 methods/props max. Hide everything else.
- **Design B**: Maximize flexibility. Support the most use cases possible.
- **Design C**: Optimize for the most common case. Make the 80% path trivial, even if the 20% is harder.
For each design, show:
1. **Interface** — the types, methods, props, or API surface
2. **Usage example** — how a caller actually uses it
3. **What it hides** — complexity kept internal
4. **Trade-offs** — what you gain and what you give up
After showing all three, compare them on:
- Interface simplicity (fewer methods, simpler params)
- Depth (small interface hiding significant complexity = good)
- Ease of correct use vs ease of misuse
- How well it fits existing patterns in this codebase
Recommend one, but explain what you'd steal from the others.
The deep module principle
The best interfaces are deep: small surface area hiding significant complexity.
Deep module (good): Shallow module (avoid):
┌──────────────┐ ┌────────────────────────────┐
│ Small API │ │ Large API │
├──────────────┤ ├────────────────────────────┤
│ │ │ Thin implementation │
│ Complex │ └────────────────────────────┘
│ internals │
│ │
└──────────────┘
When comparing designs, ask: which one hides the most complexity behind the simplest interface?
When to use it
- Before building a new module, component, or API
- When you're about to write a function with 6+ parameters (there's a simpler interface hiding in there)
- When two team members disagree on an approach (generate both, plus a third, then compare)
- During architecture reviews
When NOT to use it
- For trivial helpers or one-off utilities (just write it)
- When the interface is already dictated by a framework or spec
- When you're prototyping and speed matters more than design
Tips
- The value is in the comparison, not any single design. Even if you pick Design A, insights from B and C will improve it.
- "Radically different" means different in structure, not just naming. If all three designs have the same methods with different names, you haven't diverged enough.
- The best final design often combines elements from multiple options. "Design A's interface with Design C's defaults" is a valid outcome.