AI-Assisted Development in Production: Speed Without the Technical Debt

The claim worth examining
I use Claude Code and Cursor daily on client work, and I ship roughly 30% faster with them. Both halves of that sentence need the context that the hype cycle leaves out: the speedup is real, and it is conditional on engineering discipline that AI does not replace.
What AI assistance is actually good at
On production frontend work, the consistent wins are:
- Boilerplate at the edges. Form validation wiring, test scaffolding, API adapter shapes, Storybook stories — work that is well-specified and pattern-shaped.
- Codebase archaeology. Asking an agent to trace how a value flows through an unfamiliar codebase is faster than grepping, and it does not get bored.
- First drafts of refactors. Renaming a concept across forty files, converting a class component, lifting repeated JSX into a component — mechanical transformations with clear acceptance criteria.
- Rubber-duck review. Describing intent and asking what breaks surfaces edge cases earlier than the bug tracker does.
What still requires the senior engineer
AI tools generate plausible code, and plausible is the dangerous word. The judgment calls that decide whether a codebase stays healthy are unchanged: where state lives, what the component boundaries are, which dependency is worth its weight, what the failure modes are, and whether the generated code matches conventions the team agreed on. An agent will happily produce a fourth state-management pattern in a codebase that already has three. Catching that is the job.
The workflow that works for me
My loop on client projects looks like this:
- Write the intent first — a short spec in the issue or a comment block — before prompting anything
- Let the agent draft, then review the diff with the same rigor as a junior developer's PR, because that is the quality band the output sits in
- Keep changes small and verifiable; agent-generated thousand-line diffs are unreviewable and therefore unshippable
- Run the same gates as always: types, lint, tests, manual check of the rendered UI
The 30% speedup comes from compressing the typing and searching, not from skipping the thinking or the review.
What does an AI-assisted development workflow look like in practice?
The four bullets above compress a loop worth spelling out, because the order is what makes it work.
Plan before code, always. Modern agents have a planning mode that produces an approach for review before touching files, and it is the highest-leverage step in the entire workflow. Reading a proposed plan takes ninety seconds; reading a wrong four-hundred-line diff and working out why it is wrong takes twenty minutes. Most of my corrections happen at the plan stage — "no, that state belongs in the existing slice", "use the hook we already have in shared" — where they cost a sentence rather than a revert.
Give it the conventions, not just the task. An agent cannot infer that your project puts feature code in feature folders unless something tells it. A short conventions file in the repository, read by the agent at the start of a session, removes an entire class of "technically correct, structurally wrong" output. On my own projects this single file cut the number of review comments about placement and naming to near zero.
One concern per change. I ask for the smallest coherent unit — a component, a hook, a migration — and review it before the next. Batching four features into one prompt produces a diff nobody can hold in their head, and the failure mode is not that it is wrong everywhere, it is that it is wrong in one place you skim past.
Verify at the level the change operates. Types and lint for a refactor; a rendered page for UI work; an actual request for API code. The agent's confidence is uniform regardless of correctness, so the verification has to come from the system, not from the tone of the summary.
Review as though the author were a capable stranger. Not hostile, not deferential. The output is usually competent and occasionally confidently wrong in a way that reads exactly like the competent parts — which is precisely why the review cannot be skipped when the code "looks fine".
What does AI accelerate, and what still needs a senior?
The split has been stable across a year of client work.
Genuinely faster, often dramatically:
- Mechanical refactors across many files. Renaming a domain concept through forty files, converting class components, extracting repeated JSX. Clear acceptance criteria, tedious execution — the ideal shape.
- Tests for existing behaviour. Give it a module and ask for the test file; you get the obvious cases in a minute and spend your time on the ones it missed.
- Unfamiliar-codebase navigation. "Where does the auth token get refreshed, and what reads it?" beats grepping, and it does not lose interest halfway.
- Configuration and scaffolding. Build config, CI workflows, Storybook stories, API adapter shapes.
Still requiring the engineer, with examples from real reviews:
- Architectural placement. Asked for a caching layer, an agent will happily add a fourth caching strategy to a codebase that already has three. It cannot know which one you are standardising on unless you tell it — and knowing which one you *should* standardise on is the actual job.
- Performance work that needs measurement. An agent asked to "make this faster" will apply plausible optimisations. On the hero-animation problem I described in Core Web Vitals in 2026, every plausible optimisation was irrelevant; the fix required reading field data and understanding why the LCP element was being re-registered.
- Accessibility beyond the obvious. It reliably adds
alttext and ARIA roles. It does not notice that your custom dropdown traps focus incorrectly for keyboard users, because that requires operating the thing. - Knowing what not to build. The most valuable review comment I make is still "we do not need this" — and an agent asked to build something will build it.
What should you check in AI-generated code?
The checklist I actually run, in order, because the early items catch the most:
- Does it duplicate something that already exists? The single most common issue. Agents write new helpers rather than finding yours.
- Does it match the conventions of the surrounding files — folder placement, naming, state patterns, error handling?
- Are the error and empty paths handled, or only the happy path? Generated code is optimistic by default.
- Is anything invented? API fields, library methods, config options. Confident references to things that do not exist are the signature failure mode.
- Are the dependencies justified? An agent will reach for a package where six lines would do.
- Does it handle the boundaries — null, empty array, loading state, unauthorised user?
- Are there security implications? Anything touching auth, input handling, or data access gets read line by line rather than skimmed.
- Do the comments describe intent or narrate the code? Generated comments often restate the next line; those come out.
- Has it actually run? Types, lint, tests, and the rendered result. "Looks right" is not a verification step.
Eight of those nine questions are the same ones I would ask of any pull request. That is the point — the review standard does not change, only the volume of code arriving at it.
What clients should ask about AI-assisted developers
If you are hiring a developer who advertises AI-assisted speed, the right question is not "how fast" but "what is your review process for generated code." A developer who cannot answer crisply is shipping unread code. The follow-ups that separate discipline from hype: how do you keep generated code consistent with the existing codebase, and what do you never delegate to the agent?
What went wrong: the code that passed review and lost data
The failure worth describing did not look like a failure. I asked an agent to add optimistic updates to a settings form — a small, well-specified task in a codebase it had the conventions for. The diff was clean, matched our patterns, and passed types, lint, and tests. I approved it in about four minutes.
The code merged the optimistic update like this:
// What was generated — looks correct, and is wrong.
setSettings((prev) => ({ ...prev, ...pendingChanges }));
try {
await saveSettings(pendingChanges);
} catch {
setSettings(previousSettings); // captured before the optimistic update
}The bug: previousSettings was captured once when the component rendered, not at the moment of the mutation. If a user changed two settings in quick succession and the second request failed, the rollback restored a snapshot from before *both* edits — silently discarding a change the user had successfully saved. Our tests covered the success path and a single-failure path, both of which pass.
It reached production and survived about three weeks before a client reported that a preference "kept resetting itself". Reproducing it took longer than fixing it. The fix was to capture the pre-mutation state inside the handler and roll back to exactly that:
setSettings((prev) => {
rollbackRef.current = prev; // snapshot at mutation time
return { ...prev, ...pendingChanges };
});
try {
await saveSettings(pendingChanges);
} catch {
setSettings(rollbackRef.current);
}Three things I changed afterwards. Concurrency became an explicit review question for any optimistic update or async state change — "what happens if this fires twice before the first resolves?" is now on the checklist above. Tests for generated async code must include an interleaved-failure case, because the happy path and the single-failure path both pass on code that is broken. And I stopped letting a clean diff shorten the review: the code looked like our code, which is exactly why it got four minutes instead of fifteen.
What I would do differently is generalise the lesson rather than the rule. The agent did not make a careless mistake — it made a subtle concurrency error of the kind experienced developers also make, and it made it in code that read as idiomatic. The review effort should scale with the *consequences* of the change, not with how unfamiliar the code looks.
Honest limitations
Agents still struggle with genuinely novel UI interactions, subtle accessibility requirements, and performance work that needs profiling before coding. They are also confidently wrong about API details just often enough that unverified output is a liability. None of this argues against the tools — it argues for pairing them with someone accountable for the result.
Bottom line
AI-assisted development is now simply how productive frontend work gets done, the way IDEs and CI once became defaults. The differentiator is the engineer's judgment wrapped around it. That combination — senior review discipline plus AI speed — is what I sell on retainers, and the delivery track record is in the case studies.
Muzamal Ali — Senior Frontend Engineer & Team Lead
Senior Frontend Engineer with 5+ years building production React and Next.js applications. I've led teams of 3–9 developers across healthcare, aviation, AI, and SaaS platforms. Based in Pakistan, working async with European tech teams.
Working on something similar?
I help European tech teams ship better frontends.


