top of page

AI Coding Assistants in Practice

  • ShiftQuality Contributor
  • Mar 3
  • 7 min read

AI coding assistants are everywhere now. Copilot, Cursor, Cody, Claude — every IDE has an AI sidebar, every terminal has a chat interface, and every tech blog has a hot take about whether developers are about to be replaced.

They are not about to be replaced. But the tools are real, they are useful, and most people are using them wrong. Not wrong in a moral sense. Wrong in a practical sense — in ways that cost more time than they save and degrade skills that still matter.

This post is not a review of specific products. Products change fast and reviews go stale faster. This is about the category: what these tools are structurally good at, where they structurally fail, and how to build a workflow that makes you faster without making you dependent.

What They Are Actually Good At

AI coding assistants excel at a specific class of tasks, and once you understand the class, you stop being disappointed by what they cannot do.

Boilerplate and ceremony. Every language and framework has code that is necessary but not interesting. Interface implementations, data transfer objects, serialization logic, test scaffolding, CRUD endpoints, migration files. This is code where the pattern is well-established and the variation is minimal. AI assistants generate this code faster than you can type it, and they get it right most of the time because the pattern has appeared thousands of times in their training data.

Translation between known formats. Converting a JSON schema to a TypeScript interface. Turning a SQL query into an ORM expression. Translating a Python function to C#. These are mechanical transformations where the mapping between source and target is well-defined. The assistant handles them reliably because there is a clear right answer.

Explaining unfamiliar code. Pasting a block of code you did not write and asking "what does this do" is one of the highest-value uses of these tools. The assistant reads the code, describes the logic in plain language, identifies patterns, and flags potential issues. For reading legacy codebases or learning a new framework, this is genuinely transformative.

Generating test cases. Given a function signature and a description of the behavior, assistants are good at generating a range of test cases — including edge cases you might not think of. The tests need review, but they provide a starting point that is faster than writing each case by hand.

Regex, shell commands, and syntax you look up every time. There are patterns that experienced developers have written a hundred times and still google. Date formatting strings. Complex regex patterns. Bash one-liners for file manipulation. awk and sed syntax. The assistant generates these on demand and saves you a trip to Stack Overflow.

The common thread: all of these are tasks where the assistant is operating on well-established patterns with clear correctness criteria. The code it generates can be verified quickly by reading it.

Where They Will Mislead You

The failure modes are as consistent as the strengths, and they are more dangerous because they look like success.

Confident nonsense. AI assistants do not know what they do not know. When they generate code that is wrong, they generate it with the same fluency and confidence as code that is right. There is no hesitation, no caveat, no "I'm not sure about this part." The hallucinated API call looks identical to the real one. The subtly incorrect algorithm reads like clean, professional code.

This means the verification burden is on you, every time. Not just for code that looks wrong — code that looks right can be wrong in ways that only surface at runtime, under load, or with edge case inputs. If you cannot read the generated code and evaluate its correctness, you should not ship it. This is the fundamental constraint that does not go away as the tools improve.

Plausible but outdated patterns. Training data has a cutoff. Libraries change their APIs. Frameworks deprecate patterns. The assistant generates code using the syntax from two versions ago because that is what appeared most frequently in its training data. The code compiles, the tests pass on the happy path, and the deprecation warning shows up six months later when you upgrade.

This is especially dangerous with fast-moving ecosystems — JavaScript frameworks, cloud provider SDKs, security libraries. The assistant does not know what version you are using unless you tell it, and even then it may not have training data for the latest version.

Subtly wrong domain logic. Ask an assistant to implement a tax calculation, a scheduling algorithm, or a financial formula, and it will produce something that looks correct. It may even be correct for the common case. But domain logic requires understanding the domain, and the assistant does not understand your domain. It pattern-matches against similar code it has seen before.

A tax calculation that works for most cases but handles international exemptions wrong. A scheduling algorithm that looks right but does not account for timezone edge cases across daylight saving transitions. A financial calculation that rounds incorrectly for your regulatory jurisdiction. These are bugs that pass code review if the reviewer trusts the tool.

Architecture that sounds reasonable. Ask the assistant how to structure a project and it will give you an answer. The answer will sound coherent. It may even be a reasonable architecture for some project. But it is not an architecture derived from understanding your specific constraints, your team size, your deployment environment, your performance requirements, or your domain.

Architecture decisions require judgment. The assistant can enumerate patterns. It cannot tell you which one fits your situation. Treating its architectural suggestions as expert advice rather than a starting point for your own thinking is where teams get into trouble.

The Skill Atrophy Problem

This is the risk that gets the least attention and matters the most over a career.

When you type code character by character, you are thinking through each decision. Variable names, data structures, control flow, error handling — each choice is a micro-decision that exercises your understanding of the problem and the language. When you accept a multi-line completion from an assistant, you skip those decisions. The code appears, you read it, it looks right, you press Tab.

Over weeks and months, this changes how you work. The first thing you notice is that you are faster. The second thing you notice — if you are honest with yourself — is that you reach for the tool before you think. A function you could write in three minutes, you prompt instead. Not because it is faster, but because it is easier. The thinking step gets skipped.

For boilerplate, this is fine. You were not learning anything by typing the forty-seventh CRUD endpoint of your career. But for logic — business logic, algorithmic thinking, system design — the thinking is the skill. Skip the thinking often enough and the skill degrades, the same way a muscle atrophies when you stop using it.

The practical test: if the assistant disappeared tomorrow, could you still build what you are building at roughly the same quality, just slower? If the answer is yes, you are using the tool well. If the answer is no — if there are parts of your codebase you could not recreate or debug without the tool — that is a dependency, not a workflow.

A Workflow That Works

Here is how to use these tools without the downsides.

Think first, generate second. Before prompting the assistant, spend sixty seconds thinking about what the code should do. What are the inputs? What are the outputs? What are the edge cases? What should happen when something goes wrong? Once you have a mental model, use the assistant to generate an implementation. Then compare what it produced against your mental model. This takes more time than "prompt and accept" and produces better code with fewer bugs.

Use generation for the boring parts. Boilerplate, serialization, test scaffolding, type definitions, migration files — let the tool handle these. This is where the time savings are real and the risk of skill atrophy is zero. Nobody's career was built on their ability to write data transfer objects from memory.

Read everything you accept. Every line. Not skim — read. If you cannot explain what a line does, do not accept it. This is not paranoia. It is the same standard you would apply to code from a junior developer on your team. The assistant is a fast, confident junior developer who never asks clarifying questions. Treat its output accordingly.

Write the hard parts yourself. Business logic, security-sensitive code, data integrity constraints, complex state machines — write these by hand. Use the assistant as a sounding board if you want ("here's my approach, what am I missing?"), but do the implementation yourself. These are the parts where your understanding of the domain determines whether the code is correct, and that understanding only comes from doing the work.

Verify with specifics, not vibes. When the assistant generates code, do not ask yourself "does this look right?" Ask yourself specific questions: Does this handle null inputs? Does this handle the empty collection case? Does this close the resource if an exception is thrown? What happens if this is called concurrently? Specific questions catch specific bugs. Vibes catch nothing.

The Information Problem

This is where the ShiftQuality thesis applies directly. AI coding assistants are tools. Like every tool, the value they provide depends entirely on how you use the information they produce.

A developer who uses the assistant as a typing accelerator — generating the code they already know how to write, faster — gets genuine productivity gains. A developer who uses the assistant as a thinking replacement — accepting code they do not understand for problems they have not analyzed — gets code that works until it doesn't, and a diminished ability to fix it when it breaks.

The tool is not the problem. How you use the information is the problem.

The Takeaway

AI coding assistants are the most useful new tool in software development in a decade. They are also the easiest tool to misuse, because misuse looks like productivity. The code appears faster. The features ship sooner. The problems surface later.

Use them for what they are good at: boilerplate, translation, explanation, and exploration. Verify everything they produce. Write the hard parts yourself. Maintain the skills that make you a developer and not an operator of a code generation tool.

The developers who will thrive with these tools are not the ones who generate the most code. They are the ones who think the most clearly about what the code should do — and use the tool to get there faster without skipping the thinking.

Next in the "Tools That Work" learning path: We'll cover how to evaluate any new tool — AI or otherwise — with a framework that separates real productivity gains from shiny object syndrome.

Comments


bottom of page