Software Fundamentals Matter More Than Ever
Matt Pocock argues that as AI coding tools become ubiquitous, the software engineering fundamentals that many developers thought were obsolete — TDD, DDD, refactoring, vertical slicing — are now more important than ever. He presents a framework of five failure modes and the classical discipline that solves each one, showing that AI amplifies both good and bad engineering practices.
The Specs-to-Code Movement — And Why It Fails
Matt opens by addressing the hype around "specs-to-code" tools — platforms that promise to turn a high-level specification into a working application. He argues this is essentially vibe coding dressed up in business language. You write a spec, the AI generates code, you iterate on the spec — but each round produces progressively worse output.
He shares his own experience trying this approach: the first iteration looks impressive, but by the third or fourth cycle the codebase has accumulated so much incidental complexity that the AI starts contradicting its own earlier decisions. The fundamental problem isn't the AI — it's the absence of engineering discipline in the workflow.
"Specs-to-code is just vibe coding wearing a suit. You're still outsourcing all design decisions to a stochastic process."
Software Entropy & Complexity
Matt draws on two seminal books — John Ousterhout's A Philosophy of Software Design and Hunt & Thomas's The Pragmatic Programmer — to ground his argument in the concept of software entropy. Every change to a codebase either increases or decreases disorder. In the AI era, this effect is amplified.
Bad code has never been more expensive than it is right now, because AI agents perform dramatically differently depending on code quality:
- Good codebases: AI can follow clear patterns, understand naming conventions, and produce consistent output that matches the existing architecture.
- Bad codebases: AI hallucinates patterns, creates inconsistent abstractions, and accelerates the entropy spiral. Each AI-generated change makes the next one worse.
- The multiplier effect: AI amplifies whatever state your codebase is in — clean code gets cleaner contributions, messy code gets messier ones.
"A good codebase is now a competitive advantage, not just a nice-to-have. It directly determines how much leverage you get from AI."
Failure Mode 1: "AI Didn't Do What I Wanted" → Grill Me
The first failure mode Matt identifies is when the AI produces something that technically works but doesn't match what the developer actually wanted. He references Frederick Brooks' The Design of Design and the concept of a design tree — every design decision branches into further decisions, and if the AI takes a wrong branch early on, everything downstream diverges.
The solution is the "Grill Me" technique: before writing any code, you instruct the AI to interview you about requirements. The AI asks probing questions — edge cases, trade-offs, constraints — forcing you to articulate decisions you might have left implicit.
- Builds shared understanding between developer and AI before any code is written
- Surfaces hidden assumptions and unstated requirements early
- Reduces expensive rework by aligning on the design tree's root decisions
- Creates a written record of design intent that persists across sessions
Failure Mode 2: "My Codebase Got Worse" → Vertical Slicing
The second failure mode is entropy accumulation — each AI interaction leaves the codebase slightly worse than before. Matt's prescription is vertical slicing: breaking work into thin, end-to-end slices rather than horizontal layers.
Each vertical slice represents one complete feature that touches all layers of the stack — from UI to database. This constrains the blast radius of each AI-generated change and provides natural points for human review.
- Each slice is small enough for a human to fully review
- Prevents the AI from making sweeping cross-cutting changes
- Creates natural commit boundaries that can be reverted independently
- Keeps each AI task focused on one coherent goal, reducing confusion
"If your AI task touches more than one feature, you've sliced too thick. Thin vertical slices are the unit of safe AI collaboration."
Failure Mode 3: "I Can't Trust the Code" → TDD
When developers can't trust what the AI produced, the answer is Test-Driven Development. Matt argues TDD has found its perfect use case in AI-assisted development: write the tests first (ideally yourself), then let the AI implement the code to make them pass.
Tests serve as a safety net for non-deterministic agents. Because AI output varies between runs, you need an automated way to verify that each generation meets your requirements. Tests provide that deterministic contract.
- Tests define the "what" — the AI figures out the "how"
- Failing tests provide immediate, concrete feedback for the AI to iterate on
- Passing tests give confidence that the generated code actually works
- TDD naturally constrains the AI's solution space to correct implementations
- Tests written by humans encode domain knowledge the AI might miss
Failure Mode 4: "It Works But It's Messy" → Refactoring
The fourth failure mode addresses code that passes all tests but is internally messy — poor naming, tangled dependencies, duplicated logic. Matt points to Martin Fowler's Refactoring as the definitive guide and argues that continuous refactoring is essential in AI-assisted workflows.
AI-generated code tends toward expedient solutions rather than clean architecture. Left unchecked, this compounds into a codebase that becomes increasingly hostile to both human and AI comprehension. Regular refactoring sessions — cleaning up after AI contributions — prevent this decay.
- Refactoring after each AI-generated feature preserves code quality
- Clean architecture enables better AI output in subsequent iterations
- AI itself can be an effective refactoring tool when given clear patterns to follow
- The refactoring step is where human judgment adds the most value
"Think of refactoring as the cleanup crew after the AI party. The party is fun, but someone has to restore order."
Failure Mode 5: "It Doesn't Match Our Patterns" → Ubiquitous Language
The final failure mode is when AI-generated code uses different terminology, patterns, or abstractions than the rest of the codebase. Matt draws on Eric Evans' Domain-Driven Design concept of Ubiquitous Language — a shared vocabulary used consistently across code, documentation, and conversation.
The practical implementation is a context.md file (or similar project-level document) that defines the team's vocabulary, patterns, and conventions. This file becomes the AI's style guide, ensuring generated code matches the existing codebase's idioms.
- Define domain terms explicitly: what is a "workspace", a "project", a "member"?
- Document architectural patterns: how does data flow? What's the component hierarchy?
- Specify naming conventions: file names, function names, variable patterns
- Include anti-patterns: what the AI should explicitly avoid
- Keep context.md in the repo root so every AI tool picks it up automatically
"Your context.md is the most important file in an AI-assisted codebase. It's the Rosetta Stone between your team's intent and the AI's output."
The Framework: Six Principles for AI Development
Matt ties everything together into a cohesive framework. The five failure modes map to five classical software engineering disciplines, and together they form a complete methodology for AI-assisted development:
- Grill Me → Shared understanding before coding (Design of Design)
- Vertical Slicing → Thin, reviewable units of work (Agile fundamentals)
- TDD → Tests as contracts for non-deterministic agents (Kent Beck)
- Refactoring → Continuous cleanup after AI contributions (Martin Fowler)
- Ubiquitous Language → Shared vocabulary via context.md (Eric Evans / DDD)
The overarching message: software fundamentals + AI skills = effective development. Neither alone is sufficient. Developers who master AI tools without engineering discipline will produce fast garbage. Developers with strong fundamentals who learn to leverage AI will achieve unprecedented productivity.
"The developers who will thrive aren't the ones who are best at prompting. They're the ones who combine prompting with the engineering skills that have always mattered."