Two years ago, I thought AI coding tools were fancy autocomplete. I used Copilot like a better IntelliSense — accepting completions, occasionally generating a function body. A marginal productivity bump.
Then I shipped a working product in 10 days using Claude Code as the primary builder. Not a prototype. A real product with auth, a database, a payment flow, and a CI pipeline. I wrote maybe 20% of the code by hand.
That experience broke my mental model of what software development actually is.
The Model Shift: From Author to Architect
For 15 years, being a good engineer meant writing good code. Reading, writing, reviewing — the value was in your ability to produce and evaluate the artifact.
That’s changing. The artifact is becoming cheap. What’s becoming valuable is the intent behind the artifact — knowing what to build, why, how it should behave at the edges, what tradeoffs are acceptable.
Before: Engineer → writes code → ships features
After: Engineer → articulates intent → AI writes code → Engineer reviews and steers
This isn’t “AI is replacing engineers.” It’s more precise: AI is commoditizing the translation from intent to implementation. The engineers who thrive will be the ones who are excellent at intent — clear thinking, rigorous specification, adversarial review.
What Changed in My Workflow
1. Blueprints Before Anything
I used to open a file and start typing. Now I write a brief specification before giving anything to AI.
Not a 20-page PRD. A focused document that answers: what does this do, who uses it, what are the inputs and outputs, what are the edge cases, what are the constraints?
# Feature: Notification Preferences
## What it does
Users configure which notification channels are active per event type.
## Users
Logged-in users on the settings page. Power users and regular users both.
## Data model
user_notification_prefs: user_id, email_enabled, push_enabled, in_app_enabled, updated_at
## Constraints
- Optimistic UI — changes feel instant
- Save debounced 500ms after last change
- New users: all enabled by default
## Edge cases
- Unauthenticated: redirect to login
- DB failure: revert UI, show toast
- Network loss during save: queue and retry
With this spec, the AI has a target. Without it, the AI guesses — and guesses wrong in ways that are expensive to undo.
My old pattern: see error → fix error. The debugging loop was about eliminating red.
My new pattern: see error → paste into AI with full context → ask it to diagnose before fixing. “What is this telling us about the system state?”
This is counterintuitive but it consistently finds deeper issues. A null pointer isn’t the bug — it’s evidence of a missing invariant. An authentication error isn’t the bug — it’s evidence that a state transition wasn’t handled.
When you paste an error into Claude Code, don’t say “fix this.” Say: “explain what system state would cause this, then fix the root cause.”
3. Context Is the Leverage Point
The quality of AI output scales linearly with the quality of context you give it.
I’ve run the same feature request against the same model with two different context setups:
-
Bare context: “Add pagination to the user list.” → Mediocre output. Standard but doesn’t match my patterns, wrong naming conventions, tests in the wrong framework.
-
Rich context: Same request, plus a reference to an existing similar implementation, the CLAUDE.md with project conventions, and a pointer to the design system. → Output that looks like it belongs in the codebase.
The model didn’t get smarter. The context made it feel smarter.
4. Monorepo Everything
This is a technical choice that pays off specifically because of AI. When everything — UI, API, types, infra, docs — lives in one repository, the AI can see all of it simultaneously.
Split your frontend and backend into separate repos and you’ve cut the AI’s working memory in half. It can’t see how a server action maps to a component. It can’t trace a type from the database schema through to the UI prop. It can’t verify that an API contract change is reflected everywhere.
Monorepo is a prerequisite for getting the most out of an AI coding agent.
5. Treat Models Like a Squad, Not a Monolith
Different models have different strengths. I stopped treating LLMs as interchangeable:
| Task | My choice | Why |
|---|
| Complex multi-file refactors | Claude Code (Sonnet) | Best at following large-context instructions |
| Architecture discussion | Claude Opus | Deeper reasoning for hard tradeoffs |
| Quick questions, syntax | Cursor (fast model) | Speed matters, depth doesn’t |
| Infrastructure / DevOps | GPT-4o | Broader training on infra tooling |
| Code review | Claude Sonnet | Nuanced, catches subtle issues |
Using the right model for the right task is like using the right tool from a toolbox. The hammer is great — it’s not great for every nail.
6. Review Like It’s a Junior’s PR
This is the discipline most people skip. Every line of AI output should be reviewed as if a competent but inexperienced developer submitted it.
Things I look for:
- Happy path only? AI handles the 200 case. It often misses the 401, the 429, the 504.
- Over-engineered? AI loves factory patterns and abstract base classes. If a simple function works, delete the abstraction.
- Security gaps? AI doesn’t think adversarially. Check for XSS, injection, auth bypass, insecure direct object references.
- N+1 queries? AI generates clean-looking code that has O(n) database calls hidden inside loops.
- Pattern consistency? Does this match how the rest of the codebase works, or did it invent a new convention?
The 15 minutes I spend reviewing a Claude Code session has caught more bugs than my review of most human PRs.
The Three-Month Wall
There’s a pattern I’ve watched in teams adopting AI coding tools: they’re very productive for 6-8 weeks, then suddenly everything slows down. Bugs compound. Features start conflicting. The codebase feels harder to change, not easier.
I call this the three-month wall. It happens because vibe coding — conversational, iterative, no documentation — accumulates intent debt. The code was written but the reasons behind it were never recorded. The AI made choices nobody reviewed. Workarounds became load-bearing structures.
The escape from the wall is the same as the prevention: write specs before you build. Put them in the repo. Make them version-controlled. Treat them as first-class artifacts, not documents that get discarded after the PR is merged.
The spec-first approach costs you velocity in week one. It buys you velocity in months two, three, and beyond.
What I’ve Stopped Worrying About
Writing boilerplate. CRUD endpoints, migration files, test scaffolding, CI configs — I describe what I need and let AI generate it. If it’s boilerplate, my time is too valuable to write it by hand.
Remembering API syntax. “What’s the Drizzle ORM syntax for an upsert with a conflict on user_id?” is a question I ask Claude Code instead of the docs. It answers in the context of my codebase, not in the abstract.
Naming things. AI is good at consistent, idiomatic naming within a codebase. I describe what something does and let it propose a name. I veto if it’s wrong.
What I’ve Started Worrying More About
Correctness. AI code looks right more often than it is right. The confidence of the output doesn’t track the accuracy of the output. I review more carefully now, not less.
Security. AI doesn’t default to secure implementations. It defaults to working implementations. Input validation, output encoding, authentication checks — I treat these as my responsibility to verify, not AI’s to handle.
Architecture. The decisions that compound — data models, API contracts, module boundaries — I make myself. AI is excellent at implementing an architecture. It’s unreliable at choosing one.
Testing as understanding. When I write tests myself, I have to understand the behavior deeply enough to describe its edges. When AI writes tests, I lose that forcing function. I now write test descriptions and review AI implementations against them.
The Real Shift
AI tools haven’t made me faster at writing code. They’ve made me faster at shipping software — which turns out to be a very different thing.
The bottleneck in software development has never been typing speed. It’s been clarity of intent, quality of decisions, and cost of iteration. AI compresses the cost of iteration to near zero. What matters now is whether you have clear enough intent to direct the iteration effectively.
The developers who will thrive in this environment are the ones who can think precisely about what they’re building, specify it unambiguously, and review the output with skepticism. That’s not a lesser form of engineering. It’s the highest form of it.