Evolving a Software Design as Requirements Grow
How to think in stages: from clean v1 to extensible v3 without painting yourself into a corner
☰ Jump to section
A design that looks elegant for today’s three classes can become a liability when the product adds multi-tenant rules, new regions, and audit requirements. Senior LLD conversations are less about “draw the perfect Parking Lot” and more about how your choices age.
This article teaches stage-based design thinking: what to optimize in v1, what to postpone, and how to evolve without a full rewrite every quarter.
01Why Single-Shot Designs Mis-train You
- You never feel the cost of an early concrete dependency.
- You never choose between paying debt now vs shipping a feature.
- You optimize for completeness instead of optionality.
Multi-stage prompts fix that: stage 1 is a simple booking flow; stage 2 adds providers; stage 3 adds compliance logging and rate limits. Your stage-1 shortcuts become visible.
02A Three-Stage Story: Notifications
| Stage | Requirement | Healthy move | Trap |
|---|---|---|---|
| v1 | Email only | EmailNotifier behind a small interface if product hinted at channels | Hard-code SMTP calls inside OrderService |
| v2 | Add SMS + push | New implementations + selector | Copy-paste send logic into OrderService branches |
| v3 | Per-user preferences + audit | Preference policy + decorator/wrapper for audit | Stuff preferences into every notifier class |
Notice the theme: each stage extends seams instead of rewriting OrderService. That is evolution aligned with OCP, stretched across time.
03Decision Points You Should Narrate
- What do we intentionally leave concrete in v1? (YAGNI with eyes open.)
- Where do we place a seam now because the prompt already foreshadows change?
- When debt becomes expensive, what is the smallest structural payment?
- What must remain backward compatible for existing callers?
Evolution on LLDCanvas walks multi-stage growth — scaling demands, debt accumulation, and trade-off checkpoints — so you practice long-term thinking, not one-off diagrams.
04Extensibility Without Gold-Plating
- Abstract volatilities named in the problem; leave boring value objects simple.
- Prefer a single interface with two impls over a framework fantasy.
- Document the deferred decision: “No event bus in v1; revisit if fan-out > N.”
- When constraints tighten (time, headcount), evolution meets budget thinking — see design trade-offs under constraints.
05Structural Debt Ledger (Keep One While You Evolve)
| Debt item | Why we accepted it | Revisit trigger |
|---|---|---|
| Concrete SMTP client in OrderService | v1 email-only, one sprint | Second channel requested |
| Single DB table for all notification types | Speed | Query patterns diverge / indexes fight |
| No retry wrapper | Provider SLA looked fine | Error budget burned twice in a week |
Writing the ledger during practice trains the same muscle as narrating trade-offs in a senior round. Debt without a trigger is just hope.
06Practice Prompt
Stage 1: single-warehouse inventory reservation. Stage 2: multi-warehouse with transfer. Stage 3: soft reservations that expire. Sketch each stage for fifteen minutes, carrying types forward. Where did stage 1 force a painful rewrite?
07Key Takeaways
- Designs should be judged across stages, not only at t=0.
- Early concrete shortcuts have compound interest — positive or negative.
- Pay structural debt when a stage makes the cost obvious.
- Extensibility is selective, not universal abstraction.
Train multi-stage growth in Evolution, and keep single-twist OCP sharp with Change One Thing.
Frequently Asked Questions
AYou start with an early design and must change it across stages as requirements grow. Each stage constrains the next — testing long-term design judgment, not a single static diagram.
LLDCanvas Team
Engineering at LLDCanvas
Ready to practice?
Turn reading into results
110+ LLD interview questions, a live canvas, and timed Interview Mode.
Reader’s Notes (0)
Sign in to join the discussion
Sign inLoading notes…