Hossein Ghodrati
esc

Spec-Driven Development

What It Actually Looks Like to Build Software Without Writing Code

9 min read ai engineering craft

I build software full-time and almost never write code anymore.

I know how that sounds. It sounds like every AI hype post you’ve scrolled past this year. But this isn’t a story about prompting ChatGPT and declaring myself a 10X engineer. It’s about something I genuinely didn’t expect to find.

After a decade working in tech, leading engineering organizations from Silicon Valley startups to publicly traded firms, and most recently serving as CTO of a VC-backed startup where I was always hands-on and shipping features myself, I started building new products to solve problems I’d experienced firsthand as a tech leader. I set one constraint: go all-in on AI-assisted development. No half-measures, no fallback to the old way.

What I found wasn’t what I expected. Going all-in didn’t turn me into a prompt engineer. It shifted me toward being more of a product strategist / designer. My time moved almost entirely to problem discovery, solution design, and architectural reasoning. The actual coding happens, but I’m rarely the one doing it.

The process that emerged is what’s increasingly called spec-driven development in AI engineering circles. I spend my time producing detailed planning documents, a hybrid of product requirements and technical specifications. AI implements against those specs.

In my Fragmentation Thesis series, I argued that the real productivity gain for experienced engineers isn’t coding speed. It’s the ability to shift almost entirely into planning and specification. This article is the inside view of what that shift actually looks like. The receipts.

And at the deepest level, this is Abundance Engineering applied to the craft of building software: AI compresses the implementation effort so that human time can expand into the work that matters most.

The foundation most people skip

The most common frustration with AI-assisted coding is that the output is “close but not quite right.” Inconsistent patterns. Code that works in isolation but doesn’t fit the system. Architectural choices that no experienced engineer on your team would make.

When I first went all-in, this was exactly my experience. The results were inconsistent, sometimes impressive, often wrong in subtle ways that took longer to fix than writing the code myself would have.

What changed the results wasn’t better prompting. It was building a foundation that gives AI the context it needs.

Three layers made the difference.

An opinionated application scaffold. Not a generic boilerplate, but deliberate architectural choices that constrain the solution space. When every model inherits from the same base class, every service function follows the same structure, every view handles the same concerns in the same order, AI has a clear pattern to follow. The scaffold I use now carries forward architectural choices from my time as CTO, where I rebuilt a production stack around Django, Python, and HTMX and started pushing toward an AI-native operating model. It wasn’t built from scratch in isolation. It reflects lessons from years of leading engineering teams and building production systems.

Codified architectural guidelines. Most engineering teams carry their conventions as tribal knowledge. “That’s just how we do it here.” The patterns live in people’s heads, absorbed through code review and osmosis. Making those conventions explicit is what lets AI participate as if it understood the team’s norms. I’m talking about naming conventions, structural patterns, interaction models, error handling approaches, all written down as prescriptive documentation. Not a description of what exists, but a specification of how things should be built. My architectural guidelines cover everything from model patterns and service layer conventions to frontend interaction patterns and URL structures.

Exemplar implementations. Features I built myself first, which serve as concrete examples for AI to pattern-match against. AI doesn’t have to invent how things are done here. It can see a working implementation that follows all the patterns and conventions, and replicate the approach for new features. This is arguably the most powerful of the three layers, because it bridges the gap between written guidelines (which can be ambiguous) and actual working code (which is unambiguous).

The key insight: this foundation is non-trivial to build. It took weeks of deliberate investment before the productivity gains materialized. It requires the kind of experienced engineering judgment that you can’t shortcut. But once it exists, it compounds. Every subsequent feature benefits from it. Every new pattern AI follows correctly reinforces the system’s consistency.

Most people skip this step. They go straight to prompting AI to write code, get inconsistent results, and conclude that AI coding tools are overhyped. The tools aren’t the problem. The missing foundation is.

Where your time actually goes

Once the foundation is in place, the actual workflow is structured around three activities, in sequence.

Problem discovery and requirements. What do users actually need? What are the measurable outcomes? What’s a must-have versus a nice-to-have? Where are the edge cases that will bite you later? This is product thinking, and it’s where experienced judgment matters most. Getting this wrong means building the wrong thing faster, which is worse than building the wrong thing slowly because you’ll get further down the wrong path before noticing.

Interaction and experience design. When the feature has a user-facing component: how will people interact with it? Information architecture, layout structure, interaction patterns. Not pixel-perfect mockups, but the structural decisions that shape the user experience. What are the three most important things on this screen? What’s the user’s mental model? How does the information flow?

Technical architecture. Design decisions with explicit rationale. Data models, service boundaries, API contracts, phased implementation plans. Specific enough that someone (or something) could build it without further clarification. This means actual function signatures, data model sketches, file structures, and delivery phases.

The output of this process is a single planning document. Not a vague brief or a handful of bullet points, but a detailed hybrid of product requirements and technical specification. My planning template runs to fourteen major sections, from overview and goals through data models, service architecture, implementation phases, and success metrics. Each section has an owner: the product thinking comes first, then the interaction design (when relevant), then the technical architecture. The document accumulates as the feature takes shape.

Two things worth noting.

First, each step is a structured conversation. I work with AI as a thinking partner during planning, not just as an executor after planning. AI helps me think through edge cases, challenge assumptions, explore alternatives. But the judgment, the priorities, the trade-offs, those remain my decisions. AI is a collaborator in the thinking process, not a replacement for it.

Second, not every feature needs all three steps. Backend-only work skips interaction design. Simple features might go from requirements straight to implementation. The process scales to the complexity of the problem. Treating every feature as a three-step ceremony would defeat the purpose.

The spec isn’t documentation you write after figuring things out. The spec is the figuring-things-out. Writing it is the creative, high-judgment work.

What I learned

I expected spec-driven development to make me faster. It did. Features that would have taken weeks take days. But the more interesting changes were the ones I didn’t anticipate.

I spend more time on problem discovery than ever before. When implementation isn’t the bottleneck, understanding the problem correctly becomes the rate-limiting step. And that’s where it should be. I used to move quickly from a rough idea to writing code. Now most of my time goes to discovery and design before any code exists. The quality of what gets built is noticeably better because the thinking that precedes it is more thorough.

The spec forces clarity. Writing a detailed planning document surfaces assumptions and gaps that would normally emerge much later, often during implementation or testing. When you have to articulate every design decision with explicit rationale, you catch problems at the cheapest possible moment: before any code exists. I’ve become a more rigorous thinker about software design, not because I set out to, but because the process demands it.

The planning documents became valuable on their own. Not throwaway specs, but living artifacts that capture the reasoning behind decisions. Useful for revisiting why something was built a certain way, for onboarding, for avoiding the “nobody remembers why we did this” problem that plagues every growing codebase. The documents outlast the code in terms of capturing intent.

And the honest parts.

Not every feature benefits equally. Highly novel work with no existing patterns to follow still requires significant hands-on engineering. The foundation needs ongoing maintenance as the codebase evolves. And there’s a real skill to writing specs at the right level of detail. Too vague and AI fills gaps with assumptions that are often wrong. Too prescriptive and you’re basically writing the code in English, which defeats the purpose. Finding that balance took practice, and I’m still refining it.

None of this is a silver bullet. But the net effect is that I’m building better software, not just faster software.

What this means

The engineering profession has always evolved through shifts like this. Assembly to C, C to Java, manual deployment to CI/CD. Each time, what engineers spend their time on changed. Each time, the work became more valuable, not less. AI-assisted development is the next shift.

The engineers who will thrive are the ones who recognize that their most valuable contribution was always the judgment: understanding the problem, designing the system, making the trade-offs. The code was the expression of that thinking. When AI handles the expression, the thinking becomes the whole job.

For individual engineers: start small. Pick one feature, invest the time to write a thorough spec before any code, and observe what happens. You don’t need the full foundation on day one. Start with the mental model shift. Your spec is the product. The code is the output.

For engineering teams and companies: this transition isn’t about buying AI coding tools and hoping for productivity gains. It’s about rethinking how your experienced engineers spend their time, and building the foundations that make AI-assisted implementation reliable. That’s a deeper change than adopting a new tool. It’s a change in where you expect your best people to create value.

I’ve been having interesting conversations with engineering leaders thinking through this transition. How to build the foundations, how to adapt the workflow, what to expect. If any of this resonates with your situation, I always enjoy exchanging ideas.

This is what Abundance Engineering looks like applied to the craft of building software. AI compression of implementation effort, human expansion into the work that matters.

What’s next

The process I’ve described here isn’t static. It’s still evolving.

I’m currently exploring how to formalize parts of this workflow further using Claude Code’s skills and hooks system, which would codify more of the structured conversation patterns into reusable, shareable tooling. The shift from a personal process to something more portable and reproducible is an interesting problem in its own right, and I’ll be writing about it separately.

If you found this useful, that’s where things are heading next.