Vibe Coding vs Specification-Driven Development: Why Senior Engineers Are Making the Switch
Learn the fundamental difference between vibe coding and SDD. Why senior engineers are switching to specification-driven development with Claude Code for their Golang projects.
Vibe Coding vs SDD: Why Senior Engineers Are Making the Switch
We’ve all been there. Open the terminal, type claude, then write: “Create a REST API for order management using Golang, PostgreSQL, clean architecture.” Claude immediately generates hundreds of lines of code. Copy-paste, run — it works. It feels like magic.
Two weeks later, when adding a payment gateway feature, things change. The folder structure is slightly different. Naming conventions shift. Patterns are inconsistent with older code. And most painfully: we can’t explain to the AI why the previous code was written that way — because we don’t know either. The AI wrote it, not us.
This is the core problem of vibe coding — and Specification-Driven Development (SDD) is the answer. In this first article of the series, we dissect the difference between vibe coding vs specification driven development thoroughly, from real-world experience with both.
01.1 What Is Vibe Coding and Why It Feels Great at First
The term vibe coding was popularized by Andrej Karpathy in early 2025. The concept is simple: describe what you want to the AI in natural language, the AI executes, you briefly review, continue. The short dialog below captures the entire loop in three lines.
1You: "Create a POST /orders endpoint that accepts JSON, validates it,
2 saves to DB, then sends an event to Kafka"
3AI: [writes 200 lines of code]
4You: [copy-paste, run, works, commit]Notice there is no verification step in that loop — you accept the output because it runs, not because you checked it against anything. This feels revolutionary — and it is for certain use cases. Rapid prototyping, exploring new technology, PoCs for demos? Vibe coding is perfect. The problem emerges when the same approach is used to build systems that live in production for years.
Three reasons vibe coding feels great at first:
Instant feedback. You get working code in seconds. The dopamine hit is real and undeniable.
Dramatically lower barrier to entry. A junior developer can produce code that looks senior-level. No need to memorize every API or pattern.
Exploration without burden. Want to try a new library? Ask the AI. Want to see a pattern implemented? Ask while having coffee.
All of this is real and valuable. The problem is when vibe coding stops being exploration and becomes the primary way of building production systems.
01.2 Where Vibe Coding Starts to Break Down
Vibe coding has systematic failure points — not by accident, but as a logical consequence of how it works.
Ambiguity Accumulates Silently
When you say “create an order management feature,” the AI doesn’t know:
- Can an order be cancelled after confirmation?
- Who can cancel — only the user or also admins?
- What happens to stock when an order is cancelled?
- Price format: integer cents or float decimal?
- Is there a cancellation time limit?
The AI will guess. Sometimes the guess is good. Sometimes not. The more complex the system, the more often the guess misses.
Context Evaporates as Sessions Continue
In long sessions, the AI starts “forgetting” architectural decisions made at the beginning. Compare the same handler written early and late in a session — the code below shows how the layer boundary erodes over time.
1// Session 1: AI correctly follows clean architecture
2func (h *OrderHandler) Create(c echo.Context) error {
3 return h.useCase.Create(c.Request().Context(), req)
4}
5
6// Session 3: AI starts mixing up layers
7func (h *OrderHandler) Cancel(c echo.Context) error {
8 // business logic leaking into handler — code works but architecture is broken
9 order, _ := h.db.QueryRow("SELECT * FROM orders WHERE id = $1", id)
10 if order.Status != "PENDING" {
11 return c.JSON(400, "cannot cancel")
12 }
13}The Cancel handler still runs, but the architecture is breaking down silently — a direct DB call now lives where only delegation should. This is the kind of decay you don’t notice until technical debt has already piled up.
No Objective Verification Checkpoint
How do you know the AI-generated code is correct? In vibe coding, the answer is: “it looks right.” There’s no spec to use as a checklist, no acceptance criteria to verify against. Just feeling.
01.3 Operational Definition of SDD
Specification-Driven Development (SDD) is an approach where written specifications exist before code, serving as the single source of truth that explicitly defines system behavior.
There are three mandatory components. The first is the User Story — who needs what and why — captured in a single sentence like the one below.
1As a Santekno Shop customer, I want to create an order from items in my cart
2so that the items are ordered and shipped to my address.That sentence anchors every decision that follows: it names the actor, the action, and the value. Next come the Acceptance Criteria (AC) — the concrete conditions that must be met for the feature to be considered complete.
1AC1: System accepts POST /orders with cart_id and shipping_address_id
2AC2: System validates all cart items are still available (stock > 0)
3AC3: System creates order record with PENDING status
4AC4: System atomically decrements product stock
5AC5: System publishes ORDER_CREATED event to Kafka topic "orders"
6AC6: System returns order_id and total_amount_centsEach AC is verifiable — you can turn every line into a test. Finally, the Edge Cases capture the boundary conditions that are most often missed.
1EC1: If any item runs out of stock at checkout, reject the entire order
2EC2: If user has no shipping address, return 422
3EC3: Concurrent checkout for last stock item — only one succeedsWith these three components in place, every implementation decision has a clear basis. The AI no longer needs to guess.
01.4 Direct Comparison: Real Scenario at Santekno Shop
Let’s see the concrete difference with the same scenario in both styles: implementing “add product to cart.”
Vibe Coding Approach
With vibe coding we hand the AI a one-line prompt and let it fill in the unknowns. The list below shows exactly what remains undefined at generation time.
1Prompt: "Create a POST /cart/items endpoint to add a product to cart"
2
3[AI generates code without knowing:]
4- Can the same product be added multiple times (qty += 1) or create new entry?
5- What's the maximum items per cart?
6- What happens if the product is inactive?
7- Can non-logged-in users have a cart (guest cart)?
8- Response format after adding — just cart_item_id or entire cart?The result might work, but its behavior is undefined. Two months later, when there’s a bug where users can add inactive products, nobody knows if that’s a bug or intentional design.
SDD Approach
In SDD we write the spec first at specs/cart/add-to-cart.md. The markdown below turns every one of those open questions into an explicit, testable statement.
1### User Story
2As a customer, I want to add products to my cart
3so I can purchase them later in one transaction.
4
5### Acceptance Criteria
6- AC1: POST /cart/items accepts { product_id, quantity }
7- AC2: If product already in cart, increment quantity (qty += input.quantity)
8- AC3: If product not in cart, create new cart_item
9- AC4: Maximum 50 unique items per cart — reject with 422 if exceeded
10- AC5: INACTIVE products cannot be added — 422
11- AC6: Stock not decremented here, only at checkout
12- AC7: Response: cart_item { id, product_id, product_name, quantity, price_cents }
13
14### Edge Cases
15- EC1: quantity input <= 0 → 400 Bad Request
16- EC2: quantity input > available stock → 422 "insufficient stock"
17- EC3: product_id doesn't exist → 404
18- EC4: User not logged in → 401 (no guest cart for now)Now the prompt to Claude Code simply points at that spec and the pattern to follow, as shown below.
1Based on the spec at specs/cart/add-to-cart.md, implement POST /cart/items.
2Stack: Echo v4, pgx/v5, Clean Architecture.
3Reference pattern: internal/usecase/product/add_product.goThe result is code that traces back to every AC. There’s no ambiguity left for the AI — or for the next engineer reading it — to resolve.
01.5 Why Senior Engineers Are More Productive with SDD
Counter-intuitive but true: senior engineers who are already experts are more enthusiastic about adopting SDD than juniors new to AI. Why?
They know the cost of ambiguity. Senior engineers have experienced production bugs that happened not because code was wrong, but because assumed behavior differed between teams. Spec eliminates this entire class of bugs.
They think in systems, not functions. SDD forces thinking about how components interact before implementation details — exactly how senior engineers naturally think.
They value reviewability. “Does this code match the spec?” is far more objective than “is this what we want?” SDD makes code review faster and less political.
They’ve already paid technical debt. 10 minutes writing a spec now saves 2 days of debugging later. The math is undeniable.
They know AI needs context. After months using AI coding assistants, experienced engineers know AI output quality depends heavily on the clarity of context provided. Spec is the most efficient way to provide that context.
01.6 Comprehensive Comparison Table
To make the trade-offs concrete, the table below lines up both approaches across the dimensions that matter for a real engineering team.
| Dimension | Vibe Coding | Specification-Driven Development |
|---|---|---|
| Starting Point | Direct prompt to AI | Write spec first, then prompt |
| AI Context | Depends on session memory | Always in spec files |
| Verification | “Looks right” | Measurable AC checklist |
| Edge Cases | Often missed | Explicitly defined |
| Debugging | No “correct behavior” baseline | Compare against spec |
| Team Onboarding | Read code, guess intent | Read spec, intent immediately clear |
| Refactoring | Dangerous without tests | Safe — spec is the safety net |
| Code Review | Subjective and political | Objective — vs spec |
| Scalability | Difficult in large teams | Designed for teams |
| Best for | Prototyping, exploration | Production systems |
| Learning curve | Low | Medium (worth it) |
Read the table top to bottom and a pattern emerges: vibe coding optimizes for the first five minutes, while SDD optimizes for every week after that. That single trade-off explains most of the migration senior engineers are making.
01.7 When Vibe Coding Still Makes Sense
SDD isn’t the right solution for every situation. There are contexts where vibe coding is still the better fit:
Prototyping in 2-4 hours. When you just want to validate whether a technical idea is feasible, the spec can wait.
One-time scripts. One-time data migrations, internal utilities with a one-day lifespan — no formal spec needed.
Exploring new libraries. Vibe coding to learn, SDD to build.
Solo projects that won’t go to production. Personal experimental side projects — free to choose any approach.
The practical rule: If the code will be touched by more than one person, or will run in production for more than one month, use SDD.
01.8 Map of This Series: 20 Articles We’ll Cover
Topic 1 consists of 20 articles in four parts:
- Part 1 — Mindset Shift (Articles 01–04): Why SDD, spec as source of truth, 2025 tools landscape, CLAUDE.md setup.
- Part 2 — Writing Effective Specs (Articles 05–09): Spec anatomy, prompt engineering, clarification techniques, OpenAPI contract-first, non-functional specs.
- Part 3 — From Spec to Go Code (Articles 10–15): Plan Mode, task breakdown, iterative code generation, TDD from spec, code review, safe refactoring.
- Part 4 — SDD at Team Scale (Articles 16–20): Microservice contracts, spec drift, SDD in teams, end-to-end case study, bridge to next topic.
The project we build throughout the series is Santekno Shop — an e-commerce platform using Go 1.22+, pgx/v5, Echo v4, and Kafka.
01.9 The Mindset Shift Required
Adopting SDD isn’t just a workflow change — it’s a change in how you think about what it means to “start” a feature.
Before SDD: “A feature starts when the first line of code is written.” After SDD: “A feature starts when the first spec is clarified.”
The two timelines below make the difference visible: where the time actually goes in each approach.
1Vibe Coding Timeline:
2[Prompt] → [Code] → [Test] → [Bug] → [Fix] → [More Bugs] → [Prod]
3 5m 5m 30m 2h 4h 2h ???
4
5SDD Timeline:
6[Spec] → [Review] → [Plan] → [Code] → [Test vs Spec] → [Prod] ✓
7 20m 15m 10m 30m 30mNotice SDD carries more upfront investment but eliminates the repeated bug cycle — the tail of question marks in the first timeline is exactly what the spec removes. The net result is faster time to production with higher quality.
The second key shift is just as important: AI is an executor, not a decision-maker. In vibe coding, AI decides how features work. In SDD, you decide (via spec), AI executes. This difference is fundamental — and determines who is actually “in control.”
01.10 Starting SDD Without Overhauling Your Entire Workflow
You don’t need a grand transformation to start. There’s one simple habit: before writing any prompt to the AI, write these three things:
- One user story sentence (who, what, why)
- Minimum three acceptance criteria (AC1, AC2, AC3)
- Minimum one edge case
That’s it — even without special tools, just text in a notepad, 10 minutes before coding. The minimal spec below is all it takes to make the AI’s output dramatically more accurate.
1# Feature: Update user profile
2
3User story: As a registered user, I want to update my name and profile photo
4so that my account information stays current.
5
6AC1: PUT /users/me accepts { name?, avatar_url? } — both optional
7AC2: name cannot be empty if provided (min 2, max 100 chars)
8AC3: After update, return the latest profile with all fields
9
10EC1: avatar_url must be a valid URL — 422 with clear message if notMinimal, but enough to remove all guessing about validation rules and response format. This one habit is the smallest possible on-ramp to SDD.
01.11 Santekno Shop: The Project We’ll Build Together
Throughout these 20 articles, we build Santekno Shop, a simple e-commerce platform with a microservice architecture. The stack summary below is the toolset we’ll assume in every code sample.
1Language: Go 1.22+
2Framework: Echo v4
3Database: PostgreSQL (pgx/v5), Redis
4Messaging: Apache Kafka
5Auth: JWT (golang-jwt/jwt/v5)
6Testing: testify/suite, gomock
7ID: github.com/google/uuidKeep that stack in mind — it’s the shared vocabulary for the whole series. The two core domain models below are the entities every later feature builds on.
1// product domain
2type Product struct {
3 ID uuid.UUID
4 Name string
5 SKU string
6 PriceCents int64
7 Stock int
8 CategoryID uuid.UUID
9 Status ProductStatus
10 CreatedBy uuid.UUID
11 CreatedAt time.Time
12 UpdatedAt time.Time
13}
14
15// order domain
16type Order struct {
17 ID uuid.UUID
18 UserID uuid.UUID
19 Status OrderStatus
20 TotalAmountCents int64
21 Items []OrderItem
22 CreatedAt time.Time
23 UpdatedAt time.Time
24}Notice PriceCents and TotalAmountCents are int64, not floats — a deliberate money-handling decision that a good spec makes explicit. Every feature we build in the series will come from a clear specification, exactly as you’d do in a real project.
01.12 SDD and Speed: Myth vs Reality
The most common objection is: “Writing spec first is slow, vibe coding is faster.” Let’s measure it honestly with the “cancel order” feature. The breakdown below tallies the real cost of the vibe-coding path.
1Vibe Coding for "cancel order":
2Prompt + AI generate: 5 min
3Revision for wrong behavior: 30 min
4Bug found by QA: 2 hr debug
5Production edge case bug: 4 hr + rollback + hotfix
6Total: ~7 hoursAlmost all of that time is spent after the code “worked” — in rework and firefighting. Now compare the SDD path for the same feature.
1SDD for "cancel order":
2Write spec + review: 20 min
3Prompt to AI with spec: 5 min
4Review code vs spec: 15 min
5Test from spec: 20 min
6Total: ~1 hourThese aren’t theoretical numbers — they reflect real experience from teams that adopted SDD. The upfront investment in the spec always costs less than the downstream bug remediation it prevents.
01.13 SDD in High-Traffic System Context
At an Indonesian e-commerce company with millions of daily transactions, SDD isn’t a luxury — it’s a necessity. Consider what happens without a spec in a high-traffic system:
- Checkout deployed without a spec about concurrent order handling
- Flash sale: 10,000 concurrent requests in 10 seconds
- Two requests “buy” the last stock item due to missing pessimistic locking
- Result: oversell, manual refunds, damaged reputation, emergency rollback
With SDD, the concurrent-checkout edge case must be in the spec before coding. The spec fragment below pins down exactly how the race is resolved.
1- EC3: Concurrent checkout for last stock item
2 → Use SELECT ... FOR UPDATE inside transaction
3 → Behavior: only one request succeeds, others get 409 Conflict
4 → Error message: "product {name} is now out of stock"Once this edge case lives in the spec, the developer knows exactly what to implement — no assumption that “it’ll handle itself.” That single line is the difference between a controlled 409 and a production oversell incident.
01.14 Integrating SDD with Existing Workflows
SDD doesn’t need to replace your entire workflow. You can integrate it incrementally:
- Sprint Planning: Add “spec review” to the Definition of Done — tickets can’t enter a sprint without a reviewed spec.
- Code Review: Add spec compliance to the PR template.
- Standup: Report progress in terms of ACs implemented, not just “working on X.”
- Retrospective: Track how many bugs came from “unclear spec” versus “wrong implementation.”
These changes are incremental and non-disruptive. Within 2-3 sprints, the team starts feeling the difference.
01.15 SDD’s Relationship with TDD and BDD
SDD is complementary to both TDD and BDD, not a replacement. With SDD + TDD, each AC becomes a test function and each EC becomes a test scenario — so TDD becomes more focused because you know exactly what to test. The test skeletons below are generated directly from the spec’s ACs and ECs.
1// From AC2: "if product already in cart, increment quantity"
2func TestAddToCart_ExistingProduct_IncrementQuantity(t *testing.T) { ... }
3
4// From EC1: "quantity input <= 0 → 400 Bad Request"
5func TestAddToCart_ZeroQuantity_Returns400(t *testing.T) { ... }Notice each test name maps back to a specific line in the spec — the spec effectively becomes your test plan. In this series we use a pragmatic approach: specs as Markdown with clear, explicit ACs. No full BDD frameworks are required, but the concepts mutually reinforce each other.
01.16 Tooling: What You Need to Get Started
The minimum tooling for SDD is almost zero. The directory tree below is genuinely all you need to begin.
1├── specs/ ← this folder alone is enough to start
2│ └── domain/
3│ └── cart/
4│ └── add-to-cart.md
5├── CLAUDE.md ← AI guidance file (Article 04)
6└── [your code]Everything in that tree already lives in your filesystem and editor. Not required: dedicated spec management tools, Jira plugins, BDD frameworks, or code generators. SDD is an approach, not a tool.
01.17 Common Mistakes to Avoid
Two of the most damaging mistakes are about how you write ACs, and both are easy to spot once you compare a bad line with a good one. The pairs below contrast an over-specified AC with a right-sized one.
1Mistake 1 — Spec too detailed about implementation:
2❌ "Use SELECT FOR UPDATE with SERIALIZABLE isolation"
3✅ "Concurrent checkout for last stock — only one succeeds"
4
5Mistake 2 — AC that isn't measurable:
6❌ "System must be fast"
7✅ "Response time < 500ms at p95 under 100 RPS load"The rule embedded in both examples: describe what must be true, in terms you can verify. The remaining pitfalls are just as common:
Mistake 3: Not updating spec after implementation changes — a stale spec is more dangerous than no spec.
Mistake 4: Writing specs that are too long — target a 5-10 minute read time.
Mistake 5: Skipping spec for “small” features — no feature is too small for ACs.
01.18 Tips & Gotchas
💡 Tip 1: Start from edge cases, not the happy path — that’s where production bugs live.
💡 Tip 2: Use specific numbers in ACs — “< 200ms at p95,” not “fast response.”
💡 Tip 3: One PR, one spec — it makes code review and rollback dramatically easier.
💡 Tip 4: Review specs with non-technical people — if they can’t understand it, it’s too technical.
💡 Tip 5: Make spec review a team ritual, not an afterthought — block 15-30 minutes at sprint start.
⚠️ Gotcha 1: A spec isn’t a communication replacement — it’s the output of discussion, not a substitute for it.
⚠️ Gotcha 2: AI can misinterpret even clear specs — always manually review AI output against the spec for critical ACs.
⚠️ Gotcha 3: Spec debt is as dangerous as technical debt — budget time to maintain it.
⚠️ Gotcha 4: Don’t let the AI write spec content from ambiguous descriptions — you make the business decisions, the AI helps with format.
01.19 SDD for Engineers with a Laravel/PHP Background
Many Santekno readers come from Laravel, and a few analogies make the transition easier. In Laravel, a FormRequest defines what is valid via rules(); in SDD, an AC expresses the same intent but more explicitly. The rule below is a typical Laravel validation line.
1// Laravel rules()
2'quantity' => 'required|integer|min:1'That single validation rule becomes an AC plus its failure behavior, spelled out below.
1// SDD AC equivalent
2// AC1: quantity must be a positive integer, minimum 1
3// EC1: quantity <= 0 → 400 with message "quantity must be greater than 0"The SDD version is more verbose, but that verbosity is exactly what removes ambiguity. The same mapping applies to authorization — a Laravel Policy::authorize() becomes an explicit AC, as shown next.
1// SDD equivalent of Policy::authorize()
2AC: Only users with ADMIN or PRODUCT_MANAGER role can change product status.
3 Other roles → 403 Forbidden.The key difference: Laravel has strong conventions that often replace explicit specs, while Go is far more minimal on conventions — which makes explicit specs more important for team consistency. Transition advice: for old Laravel projects being ported to Go, make the existing behavior your starting spec — “How does Laravel currently handle this?” becomes the first AC.
01.20 Summary
In this opening article, we’ve built the foundation for understanding SDD:
Vibe coding is effective for exploration but dangerous for production — because ambiguity accumulates, AI context evaporates, and there’s no objective verification baseline.
SDD reverses the order: spec first, code second. Its three mandatory components — User Story, Acceptance Criteria, and Edge Cases — turn the AI into a focused executor rather than a guessing decision-maker.
Senior engineers adopt SDD not because they want to slow down, but because they’ve felt the cost of ambiguity in production. A 20-minute spec investment saves hours of debugging and hotfixes.
Start now with the simplest habit: before any AI prompt, write 1 user story + 3 ACs + 1 EC. No special tools, no workflow overhaul — just a small habit with a big impact.
In the next article, we’ll deepen the concept of specification as source of truth — what it means operationally, why it matters in fast-moving teams, and how to build a spec governance system that doesn’t slow you down.