Back to Blog

Two Years of AI-Assisted Coding: What Cursor and Copilot Changed on My Team

Two Years of AI-Assisted Coding: What Cursor and Copilot Changed on My Team cover image

The most useful metric I have on AI coding tools is not lines of code or story points. It is this: our pull requests got about 40% larger, and our review time went up, not down.

That sounds like a failure. It was actually the moment I understood what these tools do. They removed the friction from producing code, and production was never the bottleneck. Review, comprehension and correctness were. Once the team could generate a working implementation in ten minutes, we discovered how much of our process quietly relied on writing code being slow.

Two years in, with Copilot and Cursor in daily use across the team, here is what actually changed — the good, the awkward, and the habits we had to build.

What Got Genuinely Faster

Some of the gains are unambiguous and I would not give them back.

Boilerplate has stopped being a task. DTOs, mappers, repository methods, test scaffolding, migration files, the fifteenth CRUD controller that looks like the previous fourteen. This work was never hard, it was just time. Now it is a tab completion, and the developer's attention goes to the part that is actually specific to the feature.

Unfamiliar territory is much less expensive. A backend developer who needs to touch a React component, or a Node engineer who has to read a Python service, gets to a working understanding far faster. The model is an excellent translator between ecosystems you half-know. I have watched juniors on my team pick up parts of the stack in days that would previously have taken weeks of nervous copy-pasting.

Tests get written that previously would not have been. Not great tests, necessarily. But a developer who would have shipped with zero tests because it was late now ships with six, and three of them are meaningful. That is a real improvement in the codebase even if it is an uncomfortable thing to admit.

The blank page is gone. Starting is often the hardest part of a task. Having something on the screen to react to — even something wrong — gets people moving. A surprising amount of the productivity gain is psychological rather than mechanical.

What Got Worse Before It Got Better

Review became the constraint. When a pull request contains 600 lines that the author did not type, the reviewer is the first human to read most of it carefully. That is a genuine shift in where the effort sits, and if you do not adjust, quality drops in a way that is invisible for about two months and then very visible.

Plausible-but-wrong code is the new failure mode. A junior developer's mistakes usually look like mistakes. Generated code looks like something a competent engineer wrote — correct naming, sensible structure, idiomatic style — and is subtly wrong in the middle. It handles the happy path and silently mishandles the empty array. Reviewers who have learned to skim for the smell of inexperience have no signal to work with.

Duplication crept in. The model does not know your codebase has a utility for that. So it writes a new one. Do that across four developers for three months and you have five date formatters, three retry helpers and two subtly different validation approaches. This is now something we explicitly look for in review.

Dependency choices got sloppier. Suggested code sometimes imports a package nobody evaluated. Once, a library that had not been updated in four years. It went in because it worked.

The Rules We Landed On

None of this is revolutionary. It is the ordinary discipline you would apply to a fast but overconfident new hire.

The author owns the code, full stop. "The AI wrote it" is not a defence in review, in an incident, or anywhere else. If you cannot explain a line in your pull request, delete it and write one you can explain. This single rule fixed more than any tooling change.

Small pull requests, enforced. We had guidance about PR size before; now it is close to a rule. If the tool makes it easy to produce 600 lines, split them into three reviewable pieces. Reviewers get worse linearly with diff size and then fall off a cliff.

Write the interface yourself, generate the body. The design decisions — the shape of the type, the boundary of the module, what the function promises — stay human. Filling in the implementation is where the tool is strongest and the risk is lowest.

Give the tool the project's rules in writing. Both Cursor and Copilot support repository-level instruction files, and they help more than people expect. Ours is short and specific.

# Project conventions

- NestJS modules; one feature per module. No logic in controllers.
- Validate all input with Zod at the boundary. Never trust req.body.
- Errors: throw typed domain errors, translate to HTTP in the filter.
- DB access only through repository classes. No raw queries in services.
- Use the existing helpers in src/common/utils before writing a new one.
- Tests: Jest, arrange-act-assert, one behaviour per test.

Six lines of context cut the "that is not how we do it here" comments noticeably. It is the cheapest quality intervention available and most teams have not written one.

Never paste secrets or client data into a prompt. Obvious, routinely violated. We put it in the onboarding doc and check the tool's data settings at the organisation level rather than trusting individual configuration.

The Part That Worries Me

I supervise juniors, so I think about this more than the productivity numbers.

Struggling with a problem for two hours is how you learn to debug. If the tool resolves the struggle at minute three, the ticket closes faster and the learning does not happen. I have seen developers who can produce working features but cannot explain why their code works, which makes them helpless the moment something breaks in a way the model does not immediately fix.

What we do about it is not sophisticated: juniors are asked to attempt the problem before opening the assistant, and in review I ask "why this approach?" rather than "does this work?". If the answer is vague, we work through it together. It costs time. It is the same time we always spent training people, just spent deliberately instead of accidentally.

I am also unconvinced by the framing that AI will replace developers. What I have observed is narrower and more interesting: it compresses the gap between knowing what you want and having it exist, which raises the value of knowing what you want. Architecture, judgement about trade-offs, understanding the business problem, deciding what not to build — none of that got easier. The typing got easier.

If You Are Rolling This Out

Set the review expectations before the tools arrive, not after the first bad incident. Write the conventions file on day one. Watch pull request size and review latency as your early warning signals, because those move before quality does. And be explicit with your junior developers about when to use it and when to sit with the problem.

The teams I see struggling with AI-assisted development are not struggling with the technology. They are struggling because they added a fast code generator to a process that assumed code was slow, and then wondered why the bottleneck moved.

Related Posts