AI for Developers: Power, Pitfalls, and How to Use It Right

The productivity shift is real. Developers using AI assistants consistently close tasks faster, explore unfamiliar codebases more quickly, and write boilerplate that used to consume hours in minutes. The tools work. But the conversation around them has two blind spots that I think are genuinely dangerous: what happens when the AI is confidently wrong, and what happens to the engineer who stops thinking for themselves.

This article is not about whether to use AI. That ship has sailed. It's about the mental model and habits that separate engineers who get compounding gains from AI from those who accumulate invisible technical debt — and occasionally ship bugs that a junior dev with Stack Overflow would have caught.

What AI Genuinely Gets Right

Before the criticism, let's be precise about where the gains are real and significant:

Hallucinations: The Silent Trust Killer

A hallucination is when an AI produces output that is fluent, confident, and wrong. Not "maybe wrong" — stated with the same tone as correct information. This is the single most dangerous property of current LLMs for professional use, and it's dangerous precisely because the signal for "I'm making this up" looks identical to the signal for "I know this for certain".

What hallucinations look like in practice: a non-existent library method with a plausible name; a security configuration that looks correct but has a subtle flaw; a database query that returns the right shape but has an off-by-one edge case; a dependency version that was yanked two releases ago; a code pattern sourced from a deprecated API that was replaced with a breaking change.

The distribution of hallucinations is not uniform. They cluster in specific conditions:

High hallucination risk: - Specific library versions and their exact APIs - Recent changes (anything after the model's training cutoff) - Niche or less-documented frameworks - Security configurations with many valid-looking variations - Cross-library interactions (e.g. "how does X work with Y") - Numerical calculations in prose explanations Lower hallucination risk: - Well-established algorithms and data structures - Standard library usage in popular languages - General architectural patterns and trade-offs - Code transformation (refactoring, translating between languages) - Explaining code you provide as context

The operational implication: your verification effort should be proportional to risk zone, not uniform. Code the AI generates from a well-known pattern deserves a quick read. A security configuration or dependency version deserves a deliberate check against the primary source.

Agents: What They Actually Are

An AI agent is an LLM that can take actions — read files, run commands, call APIs, write code, open browsers — and loop: observe the result of an action, reason about the next step, act again. The loop continues until the task is done or the agent gets stuck.

Task / Goal
→
LLM (Reason)
→
Tools / Actions
↑ loop until done ↓
read_file
run_command
write_file
call_api
browse_web
An agent loops between reasoning and action until the goal is reached — each action's result feeds the next reasoning step

This is qualitatively different from a chat assistant. A chat assistant responds to your prompt. An agent acts autonomously over multiple steps to complete a task — and it can compound errors. If the LLM's reasoning at step 3 is wrong, steps 4 through 10 might execute confidently in the wrong direction.

Skills: Reusable Behavioral Packages

Skills (also called tools, functions, or capabilities depending on the platform) are the specific actions an agent can take. They bridge the gap between the LLM's reasoning and the real world. A skill is essentially a function the agent can call: it has a name, a description of what it does, a defined set of parameters, and it returns a result the agent can act on.

// Example: a skill definition for an agent { "name": "run_tests", "description": "Runs the test suite and returns pass/fail counts and failing test names", "parameters": { "path": { "type": "string", "description": "Directory or specific test file to run" }, "filter": { "type": "string", "description": "Optional test name filter" } } } // The agent can then reason: // "I just wrote a new function. I should run the tests to verify it works. // Let me call run_tests({ path: 'src/payment' }) and check the output."

Skills make agents powerful — and risky. A skill that can write to a database, push a git commit, send an email, or call a payment API is a skill that can do real damage if the agent's reasoning is wrong. The capability gap between an agent with read-only skills and one with write skills is enormous.

The Vibe Coding Trap

"Vibe coding" — generating code by vibes, accepting what the AI produces without deep comprehension, iterating by prompting rather than understanding — has a seductive short-term appeal. Tasks close fast. The developer feels productive. The feedback loop is immediate.

The debt accumulates in invisible ways:

The test: If you can't explain, in plain language, why the AI-generated code works — what invariant it maintains, what edge cases it handles, what it would break if you changed line 7 — you don't own that code. You're renting it from the model, and the lease can be recalled at any incident.

The Skill Atrophy Risk

There's a subtler, longer-term cost that doesn't show up in sprint velocity: the erosion of the ability to work without AI assistance. Skills that aren't practiced degrade. If you've spent two years never debugging without AI, never designing a system without AI generating the first proposal, never reading documentation because the AI summarized it — you've been trading long-term capability for short-term throughput.

This matters because AI tools are not always available, not always accurate, and not always appropriate. The engineer who can function without them is resilient. The engineer who can't is fragile — and in high-stakes moments (production incidents, security audits, architecture reviews), fragility is expensive.

How to Use AI Correctly: A Practical Mental Model

The mental model that works: AI is a fast, knowledgeable, sometimes overconfident colleague who needs review. You wouldn't merge a PR from a senior engineer without reading it. You wouldn't deploy a config a colleague sent on Slack without checking it. The same standard applies to AI output — and the review burden scales with the risk of the change.

Rule 1 — Match the verification effort to the risk

Low risk → quick read: - Boilerplate, repetitive code, test fixtures - Refactoring with clear intent - Code transformation (e.g. Python → TypeScript) Medium risk → careful read + run the tests: - Business logic implementation - Database queries - API integration code High risk → verify against primary source: - Security configurations (auth, CORS, encryption) - Dependency versions and their changelog - Infrastructure as code (IAC) that touches production - Any code handling money, PII, or access control

Rule 2 — Use AI to accelerate understanding, not to bypass it

The most effective pattern: use AI to get to a working first draft quickly, then make sure you understand it before shipping. "Explain this code to me" and "What could go wrong with this approach?" are power prompts that force the AI to expose its reasoning — and expose gaps and risks you can then address.

Rule 3 — Give agents the minimum necessary permissions

The principle of least privilege applies to AI agents exactly as it does to service accounts. An agent that needs to read your codebase to answer questions doesn't need write access. An agent that can run tests doesn't need to push to main. Design agent permission sets deliberately:

// Tier 1 — Read-only agents (safest for exploration tasks) permissions: [read_files, search_code, read_docs] // Tier 2 — Write-in-sandbox agents (safe for development loops) permissions: [read_files, write_files, run_tests, run_linter] constraints: [no_git_push, no_external_api_calls, no_db_writes] // Tier 3 — Full-action agents (require explicit confirmation per step) permissions: [all] constraints: [require_human_approval_for: [git_push, db_write, api_call]]

Rule 4 — Deliberate practice outside of AI assistance

Treat your core engineering skills like a muscle that needs deliberate exercise. Periodically solve problems without AI — not because AI is bad, but because your ability to recognize when AI is wrong depends on your ability to reason correctly without it. The engineers who get the most out of AI are the ones who remain capable without it.

Prompting Patterns That Actually Work

The quality of AI output is highly sensitive to how you frame the request. These patterns consistently produce better results:

// ❌ Too vague — leaves critical decisions implicit "Write a function to process payments" // ✓ Constrained — explicit requirements, stack, and edge cases "Write a TypeScript function that processes a payment using the Stripe SDK. It should accept a customerId and amountInCents, return { success, transactionId } on success and throw a PaymentFailedError with the reason on failure. Use stripe@14. Handle network timeouts and idempotency." // ✓ Review mode — expose AI reasoning for critique "Here is my implementation of the payment processor [paste code]. What edge cases am I missing? What could fail in production?" // ✓ Risk surfacing — force the AI to think adversarially "This is my auth middleware [paste code]. Assume a malicious user is trying to bypass it. What attack vectors exist?" // ✓ Verification prompt — catch hallucinations in library usage "You suggested using axios.get() with an { onUploadProgress } option. Does that option actually exist on GET requests? Show me the docs reference."

A Realistic Picture of AI in a Production Team

The teams that use AI most effectively aren't the ones that automate the most — they're the ones that apply AI selectively and maintain strong engineering judgment about when to trust the output. Concretely:

The compounding gain: Engineers who use AI to handle the mechanical parts of their work — boilerplate, lookup, first drafts — free up cognitive bandwidth for the parts that actually require judgment: architecture, edge cases, security, maintainability. That's the right trade. Using AI to bypass the judgment parts is the wrong trade, and the debt it creates is real.

Key Takeaways

Back to all articles