When I Turn AI Off: The Tasks Where LLMs Waste Developer Time
Why attempting to use AI for every programming task creates cognitive drag, and the specific areas where writing code by hand remains faster and safer.
Estimated reading time: 5 minute(s)
Knowing when not to use a tool is just as important as knowing how to use it. In software engineering, forcing AI onto the wrong tasks often turns a five-minute job into a thirty-minute prompting cycle.
After integrating AI tools into daily engineering workflows, it is easy to fall into the habit of prompting for everything. You open a chat window to write a three-line helper function, ask an agent to adjust margins in CSS, or ask a model to design your database relations from scratch.
That habit frequently backfires. Large language models are statistical prediction engines. When a task requires deep domain context, precise spatial intuition, or strict security guarantees, prompting creates more friction than it removes.
Here are the specific areas where I deliberately close the chat window, turn off auto-agents, and write the code myself.
1. Pixel-level CSS adjustments and micro-animations
Adjusting visual styling through text prompts is one of the slowest ways to work on a frontend application.
Consider a modal where the close icon is slightly misaligned with the header text, or an animation where a dropdown menu feels slightly stiff:
// A prompt asking an AI to "make the dropdown slide in smoother"
// will often churn out arbitrary transitions:
<div className="transition-all duration-300 ease-in-out transform opacity-100 scale-100">To see if that feels right, you have to prompt, wait for the response, save the file, switch to the browser, reload, click the trigger, evaluate the motion, switch back, and write another prompt explaining why it still feels off.
The faster method is opening Chrome DevTools:
- Inspect the element in the browser.
- Tweak the padding, flex alignment, or cubic-bezier curve in real time using the arrow keys.
- Observe the change instantly at 60 frames per second.
- Copy the final CSS or Tailwind values back into the component file.
Hands-on iteration in DevTools takes thirty seconds. Describing subtle visual relationships in text prompts takes ten minutes of frustration.
2. Security boundaries and payment webhooks
Any code responsible for verifying identities, signing tokens, or processing payments should be understood line by line by a human engineer.
When implementing Stripe webhooks, for example, the exact order of operations matters:
// app/api/webhooks/stripe/route.ts
import { headers } from "next/headers";
import { stripe } from "@/lib/stripe";
import { prisma } from "@/lib/prisma";
export async function POST(req: Request) {
const body = await req.text();
const signature = (await headers()).get("stripe-signature");
if (!signature) {
return new Response("Missing signature", { status: 400 });
}
let event;
try {
event = stripe.webhooks.constructEvent(
body,
signature,
process.env.STRIPE_WEBHOOK_SECRET!
);
} catch (err) {
return new Response("Webhook signature verification failed", { status: 400 });
}
// Idempotency check: ensure this event hasn't already been processed
const existingOrder = await prisma.order.findUnique({
where: { stripeSessionId: event.id },
});
if (existingOrder) {
return new Response("Event already processed", { status: 200 });
}
// Handle successful checkout
// ...
}If you ask an AI model to write this handler, it might omit the raw body buffer check, mishandle edge cases around event idempotency, or fail to handle async header signatures in Next.js.
Because payment and authentication errors can cause data leakage or lost revenue, you cannot afford to skim generated code. If you have to audit every single line with extreme skepticism anyway, writing it by hand from the official Stripe or NextAuth documentation is faster and safer.
3. Database schema design and relationship modeling
Database schemas represent the long-term foundation of your application. Changing a column type or a relation three months into production is expensive and requires careful database migrations.
LLMs tend to produce naive relational structures. Ask a model for a schema for a rental platform, and it will often give you a generic template: Users, Listings, Bookings, Reviews.
What the model misses are the hard business constraints:
- How should overlapping booking dates be prevented at the database constraint level?
- Should user profiles use soft deletes or hard cascading deletes?
- What composite indexes will the search query actually need when filtering by price, location, and availability simultaneously?
These choices require business judgment, cost calculations, and domain experience. You should design schemas deliberately in Prisma or SQL first. You can use an LLM later to generate seeds or write test queries, but the schema design belongs to you.
4. The hidden cost: review fatigue
When you write code by hand, you construct the mental model of the feature in your head as you type. You know which branches exist, why a particular check was added, and where the potential failure modes lie.
When you generate large chunks of code with AI, you inherit the responsibility of reviewing someone else's work without having built that mental model.
Reading code is cognitively harder than writing it. Reviewing four hundred lines of AI-generated code to spot the one missing null-check or race condition is mentally exhausting. After the third round of generation, developers naturally get tired and start skimming.
That review fatigue is where critical bugs slip through into production.
A quick filter for your daily workflow
Before reaching for an AI tool on a new task, consider this quick filter:
- Use AI if you already know how to write the code, the task has high syntax boilerplate (like updating types or writing mock data), and you have an automated test or linter to verify the result immediately.
- Write it yourself if the task involves spatial visual tuning in the browser, security and authentication rules, database schema design, or code that you do not understand well enough to debug without help.
AI tools are useful instruments, but engineering quality still depends on human judgment.