Skip to main content

Chapter 1: The End of Code-Centric Development


Learning Objectives

By the end of this chapter, you will be able to:

  • Explain why traditional code-centric development is reaching its limits
  • Identify the four systemic problems that emerge when code is the source of truth
  • Demonstrate how vague prompts produce broken AI-generated software
  • Articulate why the specification — not the code — must become the primary artifact
  • Conduct a "vibe coding vs. spec coding" comparison exercise with your AI assistant

The World We Built

For fifty years, software development has followed a single organizing principle:

Code is the primary artifact.

Everything else — requirements documents, design diagrams, architecture notes, meeting minutes — exists in service of the code. These supporting artifacts are created, consulted briefly, and then gradually abandoned as the codebase evolves. Within weeks of a project's start, the only reliable description of what the system does lives in the source files themselves.

This worked. For decades, it worked well enough. Humans wrote the code, humans read the code, and humans maintained the code. The code was both the blueprint and the building — the specification and the implementation fused into a single artifact.

But this fusion carried hidden costs. Costs that accumulated quietly over years. Costs that are now, in the age of AI-assisted development, becoming impossible to ignore.


The Four Problems of Code-Centric Development

Problem 1: Requirement Drift

In code-centric development, specifications are written once and rarely updated. The initial requirements document captures the team's understanding at a single point in time. Then development begins, and reality intervenes.

A feature turns out to be harder than expected. A stakeholder changes their mind. A third-party API behaves differently than documented. A performance bottleneck forces an architectural change.

Each of these events changes what the system does. But the requirements document doesn't change. Within months, the gap between "what the spec says" and "what the code does" becomes a chasm.

The real-world cost: New team members read the requirements and form incorrect mental models. They make changes based on outdated assumptions. Bugs multiply. Onboarding takes months instead of weeks.

Timeline of Requirement Drift:

Week 1: Spec ←→ Code (aligned)
Week 4: Spec ←--→ Code (minor gaps)
Week 12: Spec ←------→ Code (significant divergence)
Week 24: Spec Code (no relationship)

Problem 2: Hidden Business Logic

When code is the source of truth, business rules exist only inside functions, conditionals, and database queries. There is no separate, readable document that says "customers with more than three failed payments get automatically suspended" — that rule lives in a nested if statement inside a payment processing module.

The real-world cost: Understanding the system requires reading thousands of lines of code. Business stakeholders cannot verify that the system does what they intended. Auditors struggle to confirm compliance. And critically, AI agents cannot discover these implicit rules when asked to modify or extend the system.

# The business rule is invisible to anyone not reading this file
def process_payment(customer, amount):
failed = get_failed_payments(customer.id, days=30)
if len(failed) >= 3:
customer.status = "suspended" # Business rule hidden in code
notify_collections(customer)
return PaymentResult.DECLINED
# ... 200 more lines of payment logic

Problem 3: Knowledge Silos

Code-centric development concentrates system knowledge in the minds of the people who wrote the code. When those people leave — and they always leave — the knowledge leaves with them.

Documentation exists, but it's stale. Comments exist, but they describe how, not why. Architecture Decision Records exist in theory, but in practice they capture only a fraction of the decisions that shaped the system.

The real-world cost: Organizations become dependent on specific individuals. "Ask Sarah, she wrote the auth module" becomes a load-bearing organizational structure. When Sarah leaves, the auth module becomes a black box that everyone is afraid to modify.

Problem 4: AI Guessing Intent

This is the problem that makes the other three urgent.

When a human developer encounters unclear requirements, they ask questions. They attend meetings. They read Slack threads. They build context through social interaction and gradually converge on a shared understanding of what the system should do.

AI agents do none of this. When you give an AI agent a vague instruction, it doesn't ask for clarification — it guesses. And it guesses based on the most common patterns in its training data, not on your specific business context.

Human prompt:  "Build me a login system"

AI interprets: "Generate a basic username/password authentication
with a login form, using the most common patterns
I've seen in my training data"

What you actually needed:
- SSO integration with your company's identity provider
- Multi-factor authentication for admin users
- Session timeout after 15 minutes of inactivity
- Audit logging for compliance
- Rate limiting on failed attempts
- Account lockout after 5 failures

The AI's guess isn't wrong — it's incomplete. And in production systems, incomplete is often worse than wrong, because incomplete code appears to work until it encounters real-world conditions.

Expert Insight: The gap between "works in demo" and "works in production" is almost entirely a gap in specification. The code itself is often correct for the spec it was given. The spec was just too vague to capture production requirements.


The Vibe Coding Trap

The term "vibe coding" describes a development pattern that has become endemic with AI assistants:

  1. You describe a feature loosely: "Add a chat feature to my app"
  2. AI generates code that looks right
  3. You run it, discover missing pieces
  4. You patch: "Add message history"
  5. AI patches — but introduces inconsistencies with the original code
  6. You patch again: "Handle offline users"
  7. The patchwork accumulates technical debt with every iteration

Each individual prompt is reasonable. The AI's response to each prompt is competent. But the aggregate — the system produced by dozens of loosely connected prompts — is fragile, inconsistent, and unmaintainable.

This is because each prompt creates a new local context for the AI. The AI doesn't carry forward a coherent system design across prompts. It responds to each one independently, making decisions that may contradict earlier decisions.

The Hidden Cost: Implicit Decisions

Every time you give a vague prompt, the AI makes dozens of decisions without telling you:

Your PromptDecisions AI Makes Silently
"Add user authentication"Password hashing algorithm, session storage mechanism, token format, expiration policy, error message wording, redirect behavior
"Create a product catalog"Database schema, pagination strategy, image storage approach, search algorithm, caching policy, URL structure
"Build a checkout flow"Payment provider integration, tax calculation method, inventory reservation strategy, order state machine, email notification triggers

These aren't optional decisions. They're the architectural foundation of your system. And when AI makes them implicitly, you have no way to review, approve, or maintain consistency across them.


Tutorial: Experiencing the Problem

Let's make this concrete. In this exercise, you'll give your AI assistant the same feature request twice — once as a vague prompt (vibe coding) and once as a structured specification — and compare the results.

Step 1: The Vague Prompt

Open your AI assistant and type:

Build me a task management app where users can create, view, and delete tasks.

Examine the generated code. Note:

  • How many files did the AI create?
  • What database did it choose? Why?
  • How does it handle concurrent users?
  • What happens when two users delete the same task simultaneously?
  • Is there any authentication?
  • What are the API response codes?

Step 2: The Structured Specification

Now give the same AI assistant this specification:

# Task Management API

## Purpose
REST API for managing personal tasks with multi-user support.

## User Stories
- As a registered user, I can create a task with a title (required,
1-200 chars) and optional description (max 2000 chars)
- As a registered user, I can view all my tasks, paginated (20 per page)
- As a registered user, I can delete my own tasks (soft delete,
recoverable for 30 days)
- As a registered user, I cannot see or modify other users' tasks

## Technical Constraints
- Database: PostgreSQL with UUID primary keys
- Authentication: JWT tokens with 24-hour expiration
- API format: JSON, following REST conventions
- Error responses: RFC 7807 Problem Details format
- Soft deletes: `deleted_at` timestamp column, not physical deletion

## Acceptance Criteria
- Creating a task returns 201 with the task object including `id`
and `created_at`
- Viewing tasks returns 200 with paginated results including `total`,
`page`, and `items`
- Deleting a task returns 204 No Content
- Attempting to access another user's task returns 403 Forbidden
- All endpoints require a valid JWT in the Authorization header
- Invalid requests return 400 with a Problem Details body

## Non-Functional Requirements
- API response time < 200ms at p95
- Support 100 concurrent users
- All inputs sanitized against SQL injection and XSS

Step 3: Compare Results

Create a comparison table:

AspectVague Prompt ResultSpecification Result
Database choice?PostgreSQL (as specified)
Authentication?JWT with 24h expiration
Multi-user isolation?User-scoped queries, 403 on cross-access
Deletion strategy?Soft delete with 30-day retention
Error handling?RFC 7807 Problem Details
Input validation?Title 1-200 chars, description max 2000
Pagination?20 per page with total/page metadata

The specification version will be more complete, more consistent, and more production-ready — not because the AI is smarter, but because you were more precise.


Try With AI

Prompt 1: Diagnose a Vibe-Coded Project

"I'm going to describe a feature the way many developers do when using AI — loosely and informally. I want you to first implement it from my vague description, then list every implicit decision you had to make. Here's the feature: 'Build a notification system for my web app.' After implementing, show me every assumption you made and explain what could go wrong if any assumption was wrong."

Prompt 2: Experience Requirement Drift

"Let's simulate requirement drift. I'll give you an initial feature description, then I'll make five changes — each small and reasonable on its own. After all five changes, analyze the resulting code and identify any inconsistencies or architectural problems caused by the accumulation of changes. Start with: 'Build a user profile page with name, email, and avatar.'"

Prompt 3: Discover Hidden Business Logic

"Here's a code snippet from a payment processing module. Without any external documentation, identify every business rule embedded in the code. For each rule, explain: (1) what the rule does, (2) why someone might not discover it by reading the function signature alone, and (3) how you would express it as a specification."

def process_order(order, user):
if user.created_at > datetime.now() - timedelta(days=7):
if order.total > 500:
return hold_for_review(order, "new_user_high_value")
if order.shipping_country != user.billing_country:
order.requires_additional_verification = True
if len(user.orders.filter(status="completed")) == 0:
apply_discount(order, "WELCOME10", 0.10)
if order.total > 1000:
order.split_payment_available = True
process_payment(order)

Prompt 4: The Specification Challenge

"I want to practice writing precise specifications. Give me a common web feature (you choose), then challenge me to write a specification for it. After I write mine, critique it: what did I miss? What's ambiguous? What would you need clarification on before implementing? Score my specification from 1-10 on completeness."


Practice Exercises

Exercise 1: The Implicit Decisions Audit

Take a recent project (or a sample AI-generated project) and pick any single feature. List every technical decision that was made during implementation. Categorize each decision as:

  • Explicit: Documented in a specification, README, or architectural decision record
  • Implicit: Exists only in the code, discoverable only by reading the implementation

Count the ratio. In code-centric projects, you'll typically find 80-90% implicit decisions.

Expected outcome: A table of 15-30 decisions with their categorization, demonstrating that most system behavior is undocumented.

Exercise 2: The Onboarding Simulation

Imagine a new developer joins your team tomorrow. Write down the minimum information they would need to safely make a change to your most critical feature. Now check: how much of that information exists in written form outside the code?

Expected outcome: A gap analysis showing what documentation exists vs. what new developers actually need, highlighting the knowledge silo problem.

Exercise 3: The AI Interpretation Test

Write three one-sentence feature descriptions (e.g., "Add search to the product page"). Give each to your AI assistant. For each response, document:

  1. How the AI interpreted the request
  2. What it assumed
  3. What it got wrong relative to what a real project would need

Expected outcome: Three documented cases showing the gap between casual descriptions and production requirements.


Key Takeaways

  1. Code-centric development fuses specification and implementation, making the system's intent invisible except through code reading.

  2. Four systemic problems — requirement drift, hidden business logic, knowledge silos, and AI guessing intent — compound over time and make systems increasingly fragile.

  3. Vibe coding feels productive but produces patchwork systems because each AI prompt creates a disconnected local context with dozens of implicit decisions.

  4. AI agents are literal interpreters, not intuitive collaborators. They implement exactly what you specify — making specification precision the primary determinant of code quality.

  5. The specification, not the code, must become the primary artifact — this is the foundational insight of Spec-Driven Development.


Chapter Quiz

  1. What is "requirement drift" and why does it accelerate in code-centric development?

  2. A developer tells the AI: "Add caching to the API." List five decisions the AI must make implicitly.

  3. Why is hidden business logic particularly dangerous when using AI coding agents?

  4. What is "vibe coding" and what structural problem does it create over many iterations?

  5. In the tutorial exercise, why did the specification-driven version produce better results than the vague prompt — even though the same AI was used for both?

  6. True or false: "The problem with AI coding agents is that they write bad code." Explain your answer.

  7. How does the knowledge silo problem differ from the hidden business logic problem?

  8. A team's codebase has 50,000 lines of code but only 500 lines of specification. What prediction can you make about the ratio of implicit to explicit decisions?