Welcome to the first lesson of this course, "Foundations of Spec-Driven Development."
In the current landscape of "vibe coding"—where we can describe a rough idea and let AI agents iterate until the result looks right—it's tempting to think that formal specifications are a relic of the past. You might be wondering: if an AI agent can see what it's implemented and adjust based on your feedback, why bother with a formal spec?
As an experienced engineer working with AI tools, you've probably experienced this workflow:
- Prompt AI: "Create a login endpoint"
- Review generated code, give feedback: "Add rate limiting"
- Review again, give feedback: "Use JWT instead of sessions"
- Review again, give feedback: "Add account lockout"
- Review again, notice it broke something from step 2
- Repeat...
Yes, AI maintains context. But this approach has real costs for you, right now. Let's examine why specifications still matter.
-
Problem 1: You Don't Know When You're Done
Without a specification, how do you validate the implementation is complete? You discover missing requirements by reviewing code, then add them iteratively. A spec defines "done" upfront.
-
Problem 2: Iteration Is Expensive
Vibe coding feels fast, but each iteration costs time and tokens. A 10-minute conversation to refine code could have been a 2-minute spec review + one generation.
-
Problem 3: No Reference for Validation
Six months later, a bug appears. Without a spec, how do you know if it's a bug or intentional behavior? You have to reverse-engineer the code (or dig through AI conversation history).
-
Problem 4: Cross-Session Inconsistency
You need to continue yesterday's work. Do you:
- Re-read all the code to remember the details? (Time-consuming)
- Continue yesterday's AI conversation? (Lost context, different session)
- Start fresh and hope AI remembers the patterns? (Inconsistent implementation)
- Reference a specification? (Instant context recovery)
-
Problem 5: Unclear Edge Cases
Without thinking through a spec first, you discover edge cases while reviewing generated code. Each discovery means another iteration cycle. A spec forces you to think through edge cases upfront, when it's cheapest to address them.
-
Problem 6: Muddled Requirements
You start with a vague idea, AI implements something, you realize that's not quite what you wanted, iterate, realize there's another aspect, iterate again. A spec forces you to clarify your own thinking before generating code.
Specifications aren't about whether AI can iterate — they're about making your own work more efficient:
- Clarify your thinking before implementation (save iteration cycles)
- Define "done" before writing code (know when to stop)
- Create your own validation reference (verify correctness)
- Recover context across sessions (resume work instantly)
- Think through edge cases upfront (when they're cheapest to address)
- Serve as your documentation (remember decisions later)
Think of it this way: you could navigate a city by making wrong turns and correcting course, or you could use a map. Both work, but one is far more efficient.
In AI-accelerated development, the specification is your map. It doesn't prevent you from using AI's iterative capabilities — it makes AI dramatically more effective by giving it a clear target upfront.
Everything above applies even when you work alone. But specifications provide additional benefits when working with teams:
- Cross-Developer Consistency: When multiple people implement related features, specs ensure compatible implementations
- Integration Success: When you build one part and a colleague builds another, specs ensure they connect correctly
- Parallel Development: Multiple developers can work simultaneously without stepping on each other's toes
But these are bonus benefits. The core value is making your work more efficient.
Not every change requires a formal specification. Here's how to decide:
Skip specifications when:
- ✅ Change is simple and obvious (CSS color update, button text)
- ✅ Quick to verify visually (< 5 minutes)
- ✅ Low risk if wrong
- ✅ Implementation is shorter than writing the spec
- ✅ You're completely clear on all requirements and edge cases
Write specifications when:
- 🔴 You need to think through the approach (writing the spec helps clarify your thinking)
- 🔴 Requirements have edge cases that need consideration
- 🔴 Work happens across multiple sessions (you'll forget the details)
- 🔴 Future maintenance likely (you'll need to understand it later)
- 🔴 You need to verify "done" against clear criteria
- 🔴 Complex enough that clarifying upfront saves rework
- 🔴 Integration points exist that need to match expectations
The key questions:
- "If I implemented this tomorrow in a fresh AI session, would I need to remember specific decisions I made today?"
- "Am I clear on all the edge cases and error conditions?"
- "Would writing down my requirements first save me iteration cycles?"
If the answer to any of these is no, you need a specification.
Let's look at the core problems specifications prevent in your own work:
Problem: Ambiguous Requirements
You tell AI "users can add tags" without thinking it through:
- First generation: One tag at a time
- You realize you wanted multiple: "Actually, let me add multiple tags"
- You realize you want validation: "Add tag validation"
- You realize you want deduplication: "Prevent duplicate tags"
Each realization means another iteration. A spec forces you to think through these upfront.
Problem: Missing Edge Cases
"Allow file uploads" seems simple until AI generates code and you realize:
- What file types? (Add validation)
- What size limits? (Add size checking)
- What happens on duplicate names? (Add conflict handling)
- Who can upload? (Add permissions)
- What validation? (Add input sanitization)
Without a spec, you discover these by reviewing code. With a spec, you address them before generating code.
Problem: Inconsistent Patterns
Without specs, your own code becomes inconsistent:
- Monday's endpoint returns
{"error": "Invalid input"} - Wednesday's endpoint returns
{"message": "Bad request", "code": 400} - Friday's endpoint returns
"Error: validation failed"
You create different patterns because you're thinking through each implementation in isolation. Specs establish consistent patterns.
Problem: Lost Context
You implement authentication today, need to add password reset tomorrow:
- Without spec: Re-read authentication code, reverse-engineer decisions
- With spec: Read spec, see the session handling approach, implement consistently
The question isn't "can I afford to write specs?" but "can I afford NOT to?"
Here's the calculation:
Without specs:
- 5-10 iteration cycles per feature (30-60 minutes)
- Re-reading code to understand past decisions (15-30 minutes)
- Inconsistent patterns that create maintenance headaches (ongoing cost)
With specs:
- 10-15 minutes to write spec
- 1-2 generation cycles (5-10 minutes)
- Clear reference for future work
- Consistent patterns across your codebase
Specs save YOU time on every feature.
In this lesson, you learned:
- Why iteration alone isn't enough — it's expensive, has no "done" signal, and lacks validation reference
- Why specs help YOU work faster — clarify thinking, define done, recover context, address edge cases upfront
- Bonus team benefits — consistency and integration when working with others
- When to write specs — when you need to think through the approach or work spans multiple sessions
- What problems specs solve — ambiguity, missing edge cases, inconsistent patterns, lost context
- The ROI calculation — specs save more time than they cost
Coming up: You'll practice identifying when specifications would have prevented iteration cycles, recognizing conversation patterns that signal "time to write a spec," and spotting ambiguous requirements that need clarification upfront.
In the practice exercises, you'll start evaluating when specifications add value and when they're unnecessary overhead.
