AI Coding Assistants Made Me Faster But Dumber — Here’s the Honest Breakdown

The Problem I Actually Hit: Shipping Faster While Understanding Less

Six months of daily Copilot use, and I caught myself doing something embarrassing: I was debugging a validation bug, traced it to a regex in my own codebase, and had absolutely no memory of writing it. I hadn’t written it. I’d accepted a suggestion three weeks earlier, it looked right, tests passed, I moved on. The regex was /^(?=.*[A-Z])(?=.*\d)(?=.*[\W_]).{8,}$/ — a password validator — and I couldn’t explain the lookahead order or why [\W_] was being used instead of just \W. I understood regexes fine. I just hadn’t engaged with this one at all.

That’s the trade-off nobody puts in the blog post announcing their 2x productivity gains: throughput goes up, retention goes down. When you’re accepting 15-20 suggestions per coding session, you’re making micro-decisions constantly — accept, reject, modify — but most of them happen at the surface level. You’re pattern-matching on “does this look reasonable” rather than building a mental model of what the code actually does. I’ve seen this described as “vibes-based code review” and that framing stuck with me. You get more code written per hour. You understand a smaller percentage of your own codebase as a result. Both statements can be true simultaneously.

This piece is for three groups. First, junior developers who are genuinely worried about the dependency — you’ve had that uneasy feeling where you’re not sure if you’re learning or just shipping, and you want an honest answer. Second, senior engineers and tech leads who are evaluating whether to roll out AI tools across the team and want to think about the skill development implications, not just the velocity metrics. Third, anyone who has stared at a chunk of AI-generated code, run the tests, watched them pass, and thought “I guess that works” — then committed it anyway. That experience is more universal than people admit publicly.

I’m not writing this to tell you to stop using AI tools. I use Copilot, I use Claude for architecture discussions, I use Cursor on some projects. The productivity is real and I’m not going back. But I want to be honest about what you’re trading away if you use these tools passively rather than deliberately. For a broader look at tooling decisions across your full workflow, check out the Ultimate Productivity Guide: Automate Your Workflow in 2026. The skill atrophy question is specific enough that it deserves its own treatment — which is what the rest of this article is.

My Setup: What I’m Actually Running Day-to-Day

My current default is Cursor 0.40+ with claude-3-5-sonnet backing the chat panel, and Copilot++ completions running in parallel. That combination means I get two different AI surfaces: the completion layer that autocompletes as I type, and the chat layer where I can ask “why is this TypeScript type error happening” and get a reasoned explanation rather than a Stack Overflow link. The thing that caught me off guard when I first switched was how differently those two surfaces affect your thinking. Completions are fast but passive — you barely notice them until you turn them off. The chat layer actively changes how you structure problems, and not always in a good way.

For work projects where Cursor isn’t on the approved vendor list (this is more common than you’d expect at companies with strict data residency requirements), I fall back to GitHub Copilot inside VS Code. The completions quality is comparable — honestly hard to tell apart for boilerplate — but the chat experience is weaker than Cursor’s. Copilot Chat in VS Code as of early 2025 feels like it has less context awareness about your whole project. Cursor’s @codebase indexing makes a real difference when you’re asking questions about code spread across ten files.

The baseline I compare everything against is plain VS Code with ESLint, Prettier, and the language server for whatever I’m working in — TypeScript’s tsserver, rust-analyzer, or pylsp. No AI completions, no chat. This isn’t a theoretical baseline; it’s what I actively switch back to. The language server gives you go-to-definition, inline type errors, and rename refactors. That’s not nothing. The honest comparison question is whether AI tooling adds to that meaningfully, or whether you’re mostly getting faster boilerplate generation that atrophies your ability to write it from scratch.

Toggling AI off deliberately is the most important part of my setup, and it’s a single workspace-level config entry:

// .vscode/settings.json — drop this in any project folder
// to kill Copilot for deliberate practice without touching your global config
{
  "github.copilot.enable": {
    "*": false
  }
}

I keep this file checked into a practice/ directory I maintain locally. When I’m working through a new algorithm, learning a library I haven’t used before, or debugging something I want to actually understand rather than just fix, I drop this in. Cursor has a similar toggle — you can disable Copilot++ in settings and set the chat model to “off” — but the VS Code workspace setting is the cleanest zero-friction way I’ve found. The psychological effect of explicitly toggling it off matters more than the mechanism. If the AI is technically available but you’re just “trying not to use it,” you’ll reach for it every time you slow down.

What ‘Traditional Methods’ Actually Means Here (Not a Strawman)

The framing I see most often in these comparisons is lazy. “Traditional methods” gets defined as banging away in vim with no autocomplete, fighting the compiler with nothing but grit. That’s not a fair comparison — it’s a strawman that makes AI tools look better than they are. The actual traditional workflow in 2024 is Language Server Protocol + a decent linter + a debugger + Stack Overflow + official docs. That’s the baseline. VS Code with Pylance, ESLint, the built-in Chrome debugger, and a few dozen open browser tabs. Not primitive — actually quite good.

The real workflow looks like this, and I mean this concretely:

  1. Write code that feels right
  2. Hit a runtime error or type mismatch
  3. Read the actual error message (not skim — read)
  4. Search for it with enough context to get useful results
  5. Read the Stack Overflow answer, the MDN page, or the GitHub issue thread
  6. Understand why the fix works, not just what it is
  7. Apply it, observe what changed

That loop is annoying. It can take 20 minutes for something that should take 2. But every single step in it is a learning moment with compounding returns. When you read the TypeScript error Type 'string | undefined' is not assignable to type 'string' for the fifth time, you stop making that mistake. When you actually dig through a Postgres EXPLAIN ANALYZE output to figure out why your query is slow, you build a mental model of indexes that no amount of autocomplete can give you.

Here’s the thing about what AI coding tools actually do to this loop — they don’t just speed it up, they short-circuit the middle section entirely. The feedback cycle with traditional methods looks like: error → diagnosis → understanding → fix. With Copilot or Claude generating the patch, it collapses to: error → fix. The diagnosis and understanding steps just disappear. You get the correct code faster, but you never touched the part of the loop that builds the mental model. A junior dev who has used AI to patch 200 bugs has seen 200 fixes. A junior dev who debugged those same 200 bugs the traditional way has built 200 causal chains in their head about why code breaks.

This isn’t an argument against AI tools — I use them daily. But it’s worth being precise about the mechanism. The traditional workflow’s slowness isn’t a bug to be optimized away entirely. The friction is doing actual work. The linter yelling at you about an unused import, the debugger showing you that your variable is undefined three frames before the crash, the Stack Overflow answer with 14 comments arguing about edge cases — all of that is information transfer that happens to feel unpleasant. Skipping it has a real cost, and that cost doesn’t show up immediately. It shows up six months later when you’re staring at a production incident and you have no intuition for where to even start looking.

Where AI Tools Genuinely Win (And I Don’t Say This Lightly)

I’ve been skeptical of most AI coding hype, so when I say these tools earned their place in my workflow, I mean it. The clearest win is mechanical boilerplate — not the architecture decisions, not the tricky logic, but the stuff where you already know exactly what the output should look like and you’re just annoyed at typing it. Generating a TypeScript interface from a JSON payload that has 23 keys? Scaffolding five Express routes with the same error-handling shape? Writing test stubs for a class you just defined? That’s not thinking — it’s transcription. AI handles all of it faster than I can, and I’ve stopped feeling bad about letting it.

// You paste this JSON into Copilot or Cursor chat
{
  "userId": "abc123",
  "email": "[email protected]",
  "preferences": { "theme": "dark", "notifications": true },
  "createdAt": "2024-01-15T10:30:00Z"
}

// You get back something usable immediately
interface UserProfile {
  userId: string;
  email: string;
  preferences: {
    theme: 'dark' | 'light'; // AI inferred the union from context
    notifications: boolean;
  };
  createdAt: string; // you'll want to change this to Date, but it's a 2-second fix
}

The context-switching recovery use case surprised me more than anything else. Two weeks away from a codebase and you’re staring at a 400-line orderProcessor.ts trying to remember why there’s a separate retry queue. Before, I’d spend 20 minutes re-reading the file, checking git blame, tracing imports. Now I ask Cursor: “What does this file do, what calls it, and what does it call?” and I get a usable mental map in 10 seconds. That’s not the AI doing programming — that’s the AI doing the indexing work that human short-term memory is terrible at. I use it specifically when coming back from vacation or switching between three different projects in the same week.

Unfamiliar library territory is the other real win. The pattern I’ve settled into: I read the library’s README and core concepts once, then use AI suggestions as a live reference while I’m actually writing code. Last month I was wiring up zod schema composition for the first time. Instead of alt-tabbing to docs every 90 seconds, I’d just start typing and let Cursor show me the method signatures. This is strictly better than IntelliSense for libraries with complex chaining APIs. The thing that matters here is that you understand what you’re asking for — the AI is filling in syntax you haven’t memorized, not making architectural decisions for you.

The Jest-to-Vitest migration is the most concrete example I can give. My config looked like this before:

// jest.config.js (old)
module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'node',
  moduleNameMapper: {
    '^@/(.*)$': '/src/$1'
  },
  setupFilesAfterFramework: ['./src/test/setup.ts'],
  collectCoverageFrom: ['src/**/*.ts', '!src/**/*.d.ts']
};

Copilot converted it to Vitest config syntax, updated the imports in my test files from import { describe, it, expect } from '@jest/globals' to the Vitest equivalents, and flagged that jest.mock() calls need to move to vi.mock(). It got maybe 80% there. What it missed: my custom serializer for snapshot tests, a jest-environment-jsdom quirk in one specific test file, and the fact that Vitest’s coverage config nests differently under test.coverage not at the root. I fixed those in maybe 10 minutes. Total time: 25 minutes instead of an estimated 65 minutes of reading migration guides. The remaining 20% was exactly the kind of edge-case reasoning that required actual understanding — which is the honest version of how these tools work in practice.

  • Boilerplate that has a known shape: interfaces, route stubs, test scaffolding — AI is faster, full stop
  • Re-orienting after context switches: ask for a file summary + dependency map before you start reading
  • New library syntax: read the concepts once, use AI for method signatures during actual coding
  • Mechanical migrations: expect 70-85% automation, budget time for the edge cases that require understanding

Where AI Tools Actively Hurt Your Skills

The regression sneaks up on you. You don’t notice it happening because productivity stays high — your output looks fine, PRs are merging, features ship. The skill erosion is invisible until you sit down for a whiteboard interview or try to debug something without a network connection.

Tab-completion brain is the first thing to go. After a few months of Copilot, I caught myself hitting Tab on suggestions I hadn’t fully read — and the code was wrong. Not catastrophically wrong, just subtly wrong in a way that would bite me later. The muscle memory of accepting suggestions gets trained faster than the habit of reading them. You have to actively fight this by forcing yourself to read every suggestion before accepting, which sounds obvious until you realize you’ve been doing the opposite for six weeks. I now use a deliberate pause — hands off keyboard, read the full suggestion — before I hit Tab on anything non-trivial. It’s annoying. It’s worth it.

Debugging atrophy is worse, because it compounds. Every time you paste a stack trace into Claude and ask “what’s wrong,” you skip the process of forming a hypothesis and testing it. That process — reading the trace, guessing the cause, being wrong, reading again — is how you build a mental map of your runtime. After months of offloading this, I noticed I was slower at debugging without AI than I was two years earlier. Not because I forgot syntax, but because I hadn’t practiced the reasoning loop. The fix is deliberately ugly: force yourself to spend 10 minutes forming a hypothesis before you ask anything. Most of the time you’ll find it yourself. When you don’t, you’ll at least know what question to ask.

I ran an honest self-test after six months of heavy AI use. I closed my laptop, grabbed a whiteboard, and tried to write a BFS from scratch. Not a complex variant — just a basic level-order traversal. I blanked on the queue initialization order, second-guessed myself on the visited set placement, and produced something that would’ve failed on a disconnected graph. This is a thing I had written dozens of times before AI tools. The skill hadn’t completely vanished, but it had degraded noticeably. If you want to keep your fundamentals sharp, you have to practice them without assistance on a schedule — not just “when you feel like it.”

Over-abstraction from AI-generated code is the trap that hurts junior developers most specifically. Ask an AI to write a function that processes a list of users and it’ll hand you something like this:

// AI-generated: technically works, but teaches bad habits
const processUsers = <T extends UserBase>(
  users: T[],
  pipeline: Array<(user: T) => T>,
  options: ProcessingOptions = defaultOptions
): ProcessingResult<T> => {
  return users
    .filter(createUserValidator(options))
    .map(user => pipeline.reduce((u, fn) => fn(u), user))
    .reduce(aggregateResults, emptyResult<T>());
};

That’s three higher-order abstractions for what is, in most real codebases, just a loop with an if statement. The code isn’t wrong. But a junior reading it assumes this is how you’re supposed to write TypeScript — generic, pipeline-heavy, abstractly composed. They spend the next month writing everything this way, and now your codebase has a maintainability problem. AI code optimizes for looking clever, not for being readable to the next developer. Whenever an AI gives you code that’s significantly more complex than your mental model of the problem, that’s a signal to ask why each abstraction exists — and whether you’d actually need it.

The Comparison That Actually Matters: Skill Outcomes by Task Type

The debate usually gets framed as “AI vs no AI” but that framing misses the point entirely. The real question is: which specific task are you doing, and what do you actually want to get out of it? I’ve seen senior devs use Copilot as a productivity multiplier and junior devs use the exact same tool to actively hollow out their own skill set. Same tool, opposite outcomes, different tasks.

Here’s how the outcomes actually break down across the tasks that matter most day-to-day:

Task Type AI Method Outcome Traditional Method Outcome Verdict
Writing CRUD endpoints Fast. Like, absurdly fast. Copilot or Claude can scaffold a full REST handler with validation in under a minute. Slower, but you manually handle the edge cases and build the muscle memory for your framework’s patterns. AI wins on speed, neutral on skill impact. This is rote work. Using AI here doesn’t cost you anything developmentally.
Debugging a race condition AI gives you a plausible-sounding fix. You apply it. The symptom disappears. You have no idea why, and the next race condition takes just as long. You learn to read thread dumps, add strategic logging, reproduce the condition under load. That knowledge compounds. Traditional wins hard. AI gives you answers without understanding. The second bug costs you the same as the first.
Learning a new language You can write working Rust or Go on day one without reading a single docs page. But you’re writing it in your old language’s mental model with AI as the translator. Painful first week. You actually hit the borrow checker errors, read the error messages, understand ownership. Traditional wins. AI lets you avoid ever internalizing the syntax rules and idioms that make the language what it is.
Writing tests AI generates broad coverage fast — happy path, basic error cases, parameter variations. Your coverage numbers look great. Writing tests manually forces you to think about failure modes, which makes you write better code in the first place. AI wins on coverage breadth, but you miss edge case thinking. The tests AI writes are often structurally correct but miss the weird state transitions that actually bite you in prod.
System design and architecture AI suggests textbook patterns. Microservices when a monolith would do. Event sourcing because it sounds sophisticated. The suggestions are generic and often wrong for your constraints. You’re forced to think about your actual data access patterns, team size, operational burden. You make tradeoffs consciously. Traditional wins. This is the one place AI is most confidently wrong. It doesn’t know your traffic shape, your team, or your ops maturity.

The race condition row is the one I feel most strongly about. I’ve watched engineers paste a goroutine deadlock into Claude, get a sync.Mutex suggestion back, apply it, and move on. Three months later they hit a different concurrency bug and go through the exact same process. The AI didn’t teach them to think about shared state — it just patched the symptom. Compare that to spending two hours with go race detector output and actually reading what the tool is telling you. You come out the other side with a mental model that applies to every future bug in that category.

The testing situation is subtler and more insidious. AI-generated tests give you the illusion of thorough coverage. But the most valuable tests I’ve ever written came from asking “what weird sequence of operations could make this fail?” — that question is the skill. When you let AI generate tests, you skip the question entirely and just get the answer. Your coverage.xml looks great; your intuition about what can go wrong stays undeveloped.

One practical note on budgeting for these tools: GitHub Copilot, Cursor, and Anthropic all change their pricing tiers fairly often — rate limits, seat costs, and what’s included in free tiers have all shifted in the past year. Check their pricing pages directly before committing budget. What I’d caution against is treating the free tiers as a reliable baseline for team planning — they exist to get you hooked, and the limits are deliberately designed to push you toward paid plans once you’re dependent on the workflow.

The Junior Developer Problem Is Real and Specific

The failure mode I keep seeing isn’t “AI wrote bad code.” The failure mode is “AI wrote correct code that the person who submitted it has no mental model for.” That’s a fundamentally different problem, and it’s much harder to catch because your linter passes, your tests pass, and the PR looks clean. The gap only surfaces when someone asks a question.

I had this exact situation on my team last quarter. A junior dev shipped auth middleware — JWT validation, token expiry checks, the whole thing. It worked. I approved the first pass until I noticed something odd in the expiry logic and asked him to walk me through it on a call. He couldn’t. He knew what it did (validates tokens) but not why the exp claim needed to be compared against Date.now() / 1000 instead of Date.now(), or why nbf existed at all. He’d accepted a Copilot suggestion, run the tests, and shipped. The code was correct for the happy path. It would have silently accepted tokens in certain edge cases we hadn’t tested.

// What he shipped — worked fine in tests
const isValid = decoded.exp > Date.now(); // BUG: exp is in seconds, Date.now() is ms

// What it should have been — and why:
// JWT spec (RFC 7519) stores exp as NumericDate = seconds since epoch
// Date.now() returns milliseconds, so divide by 1000
const isValid = decoded.exp > Math.floor(Date.now() / 1000);

The bug wasn’t obvious to someone who didn’t know the JWT spec. And he didn’t know it — because he never had to. The AI filled in the gap and he trusted it. This is the pattern: AI assistance is compressing the feedback loop that teaches you why, not just what. For seniors, that’s fine — we already have the why. For juniors, the why is the whole point of the first two years.

Hiring teams are adapting faster than I expected. I’ve talked to engineering leads at three different companies now who’ve added “no-AI debugging” rounds to their interview process specifically because of this pattern. One team gives candidates a broken Express.js auth flow and watches them reason through it live — no autocomplete, no suggestions. They’re not trying to be cruel; they’re trying to verify that the person can actually model what the code is doing. Candidates who’ve relied heavily on AI during their learning phase visibly struggle with this, not because they lack intelligence, but because they’ve never built the habit of asking “what is this actually doing at runtime?”

The guardrail I’ve started enforcing for junior devs on my team is what I call the “explain it back” rule: before you accept any AI suggestion, you must be able to write one sentence in the PR description explaining why that line exists — not what it does, why. “Sets the expiry header” is what. “Sets the expiry header to 15 minutes because our refresh token rotation strategy requires short-lived access tokens” is why. If you can’t write the why, you don’t accept the suggestion yet — you go read until you can. It’s a small friction point, but it’s the difference between AI as a shortcut and AI as a learning accelerator. The code you can explain is code you own. The code you can’t explain is a liability you’ve committed to the repo.

How I Use AI Tools Without Losing My Skills: The Actual Rules I Follow

The thing that actually surprised me wasn’t how much faster AI tools made me — it was how quickly I stopped recognizing when I was wrong. Six months into heavy Copilot and Cursor usage, I found myself accepting suggestions I couldn’t fully explain, and when those suggestions broke, I had no mental model to debug them with. That’s when I wrote down explicit rules for myself. Not as a philosophy, but as behavioral guardrails with teeth.

Rule 1: One Problem Per Week, No AI, No Stack Overflow

Every Thursday I pick something from my actual backlog — not a toy problem — and solve it with just the language docs and a debugger. No autocomplete. No chat. Last week it was implementing a consistent-hashing ring for a small routing layer. The week before, parsing a binary protocol without reaching for a library first. The discomfort is the point. When you work without autocomplete, you notice exactly which primitives you’ve stopped remembering. That gap tells you what to study next. I treat these sessions like deliberate practice — same way a musician runs scales even when they’re performing Beethoven on stage.

Rule 2: The 5-Line Read Rule

Copilot and Cursor will happily generate 30-line completions. I used to Tab through them like a slot machine. Now: if a suggestion is longer than 5 lines, I stop and read every single line before accepting. Not skim — read. This isn’t just about catching bugs, though it does catch them. It’s about keeping the code’s authorship in my head. The moment you accept a block you don’t fully understand, you’ve created a knowledge debt that compounds. Reviewers will ask questions. Incidents will happen at 2am. You need to own every line with your name on it. The 5-line threshold is arbitrary but it works — it forces a cognitive mode switch from “accepting” to “reviewing.”

Rule 3: AI Drafts, Human Finals — Especially for Algorithms and Auth

I’ll ask Claude or GPT-4 to draft a first pass at something algorithmic or security-related, then I treat that draft the same way I’d treat a junior engineer’s PR: it gets read critically, not trusted. AI-generated crypto code especially terrifies me. I’ve seen completions that use Math.random() for token generation, that skip constant-time comparison for HMAC verification, that roll their own padding schemes. None of those were obviously wrong at first glance. On anything touching auth, session management, cryptography, or data validation, I use AI output as a starting point for my own thinking — a scaffold to tear apart, not a solution to ship. For a sorting function, sure, I’ll accept more quickly. For a JWT verification middleware, I’m rewriting it from the draft up.

Rule 4: Hypothesis First, Chat Window Second

This is the hardest rule to follow because opening a chat window feels productive. When something breaks, I now force myself to write down — literally, in a scratch file — what I think is wrong before I open any AI tool. Even one sentence: “I think the race condition is in the goroutine that writes to the shared map before the mutex is acquired.” Being wrong about the hypothesis is fine. The act of forming it keeps your debugging muscle from atrophying. Without this rule, I was using AI chat as a substitute for thinking, and the dependency was invisible because it looked like productivity.

Config Tip: Kill the Reflex in Cursor

One small change that reinforced Rule 4 for me — I turned off the automatic chat panel in Cursor. By default it’s ready to open the second you feel friction:

// settings.json in Cursor
{
  "cursor.chat.openOnStartup": false,
  // also worth setting this to avoid inline suggestions mid-thought
  "editor.inlineSuggest.enabled": false  // toggle this per-project
}

Removing that default open behavior adds just enough friction that I actually think before opening it. Friction is underrated as a behavioral tool. The goal isn’t to avoid AI — it’s to make sure you’re choosing to use it rather than reflexively reaching for it. These rules aren’t anti-AI; they’re how I stay dangerous without the tools, so that I’m genuinely adding value when I use them.

When to Pick AI-Assisted vs. Going Traditional: Specific Scenarios

The Decision Isn’t Binary — But the Stakes Are Different Depending on Which Way You Default

I’ve watched developers treat this as a religious debate when it’s actually just a routing problem. The question isn’t “AI or not?” — it’s “what’s the cost of not understanding this deeply?” Once you frame it that way, the decisions get obvious fast.

Where AI-Assisted Genuinely Wins

Deadline-driven features on a stack you already know well? Use the tool. If you’ve written Django REST APIs for three years, having Copilot or Claude scaffold a CRUD endpoint isn’t rotting your skills — you’re just reclaiming time you already spent earning that knowledge. Same for test generation. Writing 40 parameterized pytest cases for existing business logic is tedious, not educational. I get more value reviewing AI-generated tests for coverage gaps than I do typing them from scratch.

  • Migration scripts: Generating a Postgres 16 column rename migration from a schema diff is exactly the kind of repetitive, verifiable output AI is good at. You still review and run EXPLAIN ANALYZE after — you just didn’t waste 20 minutes on boilerplate.
  • Documentation drafts: First draft of a README or an ADR (Architecture Decision Record) — let the AI get you to 60% done. The reasoning and trade-offs you fill in yourself are where the actual value lives anyway.
  • Writing tests for legacy code: This is one of the strongest cases. You already understand the behavior; you just need coverage. AI is fast here and the output is easy to validate.

Where You Need to Go Traditional — No Exceptions

Anything you’re learning for the first time should be done by hand, at least initially. If you’re picking up Rust’s ownership model, or trying to understand how a B-tree index works, using AI to generate the code is borrowing understanding you don’t have yet. You’ll end up with working code that breaks in ways you can’t explain, which is worse than broken code because it ships.

Production incident debugging is the scenario I feel most strongly about. When something is on fire at 2am, you need to trace through the actual call stack, read the actual logs, form a hypothesis and test it. I’ve seen engineers paste error traces into ChatGPT and accept the first plausible-sounding answer — only to spend two more hours because they treated a symptom instead of finding the root cause. AI will confidently give you a wrong answer to a Kafka consumer lag issue if the real cause is a rare lock contention pattern it hasn’t seen contextualized properly.

  • Security-sensitive code: Auth flows, token validation, permission checks, anything touching PII. AI-generated code here has subtle bugs that pass code review because reviewers anchor on the AI’s confident framing. Write it yourself, read OWASP, get a second human pair of eyes.
  • Performance optimization: Profiling a hot path in a Go service isn’t something you can hand off. You need to understand why an allocation is happening, not just accept a suggested rewrite. The insight is the work.

Your Career Stage Changes the Risk Profile

A senior with 10 years of production experience using AI to generate a Redis caching layer has a built-in error-detection system in their head. They’ll notice the generated code doesn’t handle cache stampede, or that the TTL logic is wrong for their invalidation pattern. A junior dev using the same tool on the same task doesn’t have that filter yet — they’ll ship the stampede bug because nothing in their experience flags it as wrong. This isn’t about intelligence, it’s about pattern libraries. You build those by doing things the slow way first.

The team context point cuts deeper than most people admit. If you’re a lead or a staff engineer, the people around you are calibrating what “good engineering” looks like based on how you work. If you reach for AI on everything including the learning moments, you’re implicitly signaling that the output matters more than understanding how it got there. That compounds across a team fast. Going traditional on the hard problems — and being visible about it — is part of the job at that level, not just a personal preference.

Practical Setup for Skill-Preserving AI Use

The thing that woke me up was checking my Copilot activity dashboard and seeing a 91% accept rate over two weeks. That number sounds like productivity until you realize it means I was basically rubber-stamping suggestions without actually engaging with them. A healthy accept rate looks more like 60-70% — you’re accepting what’s genuinely faster, rejecting what doesn’t fit, and rewriting enough to prove you understood the problem.

The VS Code workspace config is the most underused lever here. You can scope Copilot per language per project, which lets you be intentional instead of just toggling it globally off and on:

{
  "github.copilot.enable": {
    "*": false,
    "javascript": true,
    "typescript": false
  }
}

Drop that in your .vscode/settings.json and commit it. What I do is disable it for whatever language I’m actively trying to get sharper at. Right now I’m working on my TypeScript type-fu, so TS is off while JS (where I’m already fluent enough that Copilot genuinely saves boilerplate time) stays on. This forces you to think through type inference problems yourself instead of watching Copilot infer them and clicking Tab.

Cursor’s .cursorignore file is something I wish they’d advertised louder — it follows the same syntax as .gitignore. I use it to wall off files I want to genuinely understand:

# .cursorignore
src/core/query-planner.ts
src/auth/token-validation.ts
lib/compression/

Anything in there becomes invisible to Cursor’s AI context. The practical effect is that when you’re debugging in those files, you can’t lean on “explain this” or autocomplete — you have to read the code. I put my most architecturally important files in there because those are exactly the ones where shallow comprehension causes production incidents six months later.

The separate browser profile for practice is a small habit that pays outsized dividends. I have a “study” Chrome profile where the Copilot extension is uninstalled (not just disabled — uninstalled), Grammarly is off, and I’m logged into exercism.io and LeetCode. The friction of switching profiles is actually the point: it makes “practice mode” feel distinct from “build mode.” I do exercism tracks because the exercise sets have real mentorship feedback and incrementally harder problems within a single language. LeetCode medium-tier problems in a language you’re learning hit different when there’s no autocomplete ghost-writing the solution three characters into your function name.

Concretely, here’s how I audit my own AI dependence monthly. Copilot’s dashboard is at https://github.com/settings/copilot under “Copilot usage” — it shows accepted vs. dismissed over the last 30 days by editor and language. I export the data and run a quick check:

# rough calculation — paste your numbers in
accepted=340
dismissed=42
total=$((accepted + dismissed))
echo "Accept rate: $(echo "scale=1; $accepted * 100 / $total" | bc)%"
# anything above ~80% is worth investigating

If a specific language is consistently high, that’s the one I add to the disabled list for the next sprint. The goal isn’t to use AI less — it’s to make sure you’re capable of working without it. The moment you can’t read an unfamiliar codebase without asking an LLM what it does, you’ve traded long-term capability for short-term output. Keeping that accept rate honest is the cheapest early warning system I’ve found.

My Actual Verdict After Daily Use

After watching this play out across my team for the better part of two years, here’s where I’ve landed: refusing AI coding tools entirely is career self-sabotage at this point. The productivity gap between someone using Copilot or Claude Code intelligently and someone who isn’t is too wide to ignore. I’ve seen developers who opt out fall behind on ticket velocity, struggle to keep up with code review throughput, and spend time on boilerplate that their AI-augmented colleagues finish before the first coffee. That’s not a future trend — it’s already the present state on any team shipping at a serious pace.

But here’s the thing I wish someone had told the junior devs on my team before they got too comfortable: passive use is a slow poison. The pattern I’ve watched happen, more than once, goes like this. Developer starts using AI to generate logic they’d normally have to think through. They accept suggestions, the tests pass, the PR gets merged. Three months in, they’ve shipped a lot. Twelve months in, they can’t debug a gnarly async race condition without reaching for the AI first — and when the AI gives them a plausible-sounding but wrong answer, they can’t tell. The debugging instinct atrophies because it stopped getting exercised. I’m not speculating about this — I’ve had the uncomfortable one-on-ones where I’ve had to say “you can’t explain what this function is actually doing.”

The developers I’ve watched come out ahead use AI differently. They use it to accelerate things they already understand. A senior dev who has written a dozen authentication flows uses Copilot to skip the boring parts of writing the thirteenth — they can read the output critically, spot what’s wrong, and move on. That same workflow handed to someone who’s never thought through token expiry, refresh race conditions, or session invalidation is a liability. The tool doesn’t know what you don’t know. It’ll generate confident, compilable code that has the exact class of bug you would have caught if you’d had to write it yourself.

The framing I keep coming back to: use AI as an accelerator, not a teacher. Documentation, Stack Overflow, and reading other people’s code are slow — but they build a mental model. AI tools give you answers fast, but the answer skips straight to the output without building the reasoning path in your head. I use Claude for things like “generate the boilerplate for this gRPC service definition” or “write the first draft of this regex.” I don’t use it to explain why a distributed transaction is failing, because the act of working through that myself is the whole point — that’s where the durable skill gets built.

The uncomfortable truth worth sitting with: if an AI tool can fully replace your contribution on a specific task, that’s actually useful signal. Not as a reason to panic, but as a prompt. If you’re writing CRUD endpoints and the AI does it just as well, that’s the cue to go deeper — understand the query planner behind those endpoints, learn how connection pooling actually works, figure out what happens when your ORM generates a cartesian join and your DBA starts screaming. The developers who stay ahead won’t be the ones who avoid AI or the ones who outsource their thinking to it. They’ll be the ones who use it to move faster on the known stuff, freeing up cognitive budget to go deeper on the hard stuff that AI still consistently gets wrong.


Disclaimer: This article is for informational purposes only. The views and opinions expressed are those of the author(s) and do not necessarily reflect the official policy or position of Sonic Rocket or its affiliates. Always consult with a certified professional before making any financial or technical decisions based on this content.


Eric Woo

Written by Eric Woo

Lead AI Engineer & SaaS Strategist

Eric is a seasoned software architect specializing in LLM orchestration and autonomous agent systems. With over 15 years in Silicon Valley, he now focuses on scaling AI-first applications.

Leave a Comment