A client recently told me something I keep hearing:
“Someone can use AI to build the same thing.”
My answer was simple. I will buy you the subscription. You build it.
That usually ends the conversation. But it deserves a real explanation, because I do use AI to build. Every day. The difference is not whether you use AI. The difference is what happens after AI writes the code.
AI gives you code, not decisions
When I ask AI to build an API endpoint, it gives me something that looks correct. A non-technical person stops there. It runs, so it must be fine.
I don’t stop there, because I have seen what breaks later. I ask questions AI never asks on its own:
- What happens when this request is retried twice? Do we charge the user twice?
- What happens when 500 people press SOS at the same time?
- Where does the session live? When does it expire? What can an attacker do with it?
- What happens when this background job fails halfway?
I wrote a whole post on idempotency for this reason. AI will happily generate a payment endpoint with no idempotency key. It works in the demo. It double-charges in production. A non-technical person has no way to know that. I reject that output and ask for the right one. That judgment is the product.
The demo is 10%, production is 90%
AI is very good at the demo. A form, a button, a database insert. Looks done in ten minutes.
Here is what is not in the demo, from a dispatch system I actually built:
- Finding the nearest ambulance with the Haversine formula directly in SQL instead of pulling every row into the app layer.
- Retries with backoff when the notification service is down.
- A dead-letter queue for jobs that keep failing, so they can be inspected instead of silently lost.
- Consistent error shapes so the frontend can actually handle failures.
- Graceful shutdown so a deploy does not kill in-flight requests.
None of this is visible in a screenshot. All of it is the difference between “it worked once” and “it works at 3am under load.” A person who doesn’t know tech cannot prompt for what they don’t know exists.
Knowing what to reject
People think using AI is about writing good prompts. It is mostly about rejecting bad output.
AI once gave me a Redis caching setup with no TTL jitter. Every key expired at the same second. That causes a thundering herd — every request hits the database at once. The code looked clean. The comments were confident. It was still wrong.
An engineer catches that because they have been bitten before. I wrote about Redis vs NATS vs Kafka and SQLite WAL mode precisely because defaults matter and the wrong default only shows up months later. A non-technical builder accepts the confident wrong answer. There is no error message. Just a slow outage six months in.
AI doesn’t take the 2am call
This is the part clients forget. When the system goes down at night, who gets called?
Not the AI subscription. Me.
I am the one who reads the structured logs with the request ID, finds the failing query with EXPLAIN ANALYZE, adds the missing index, and writes the postmortem. AI helped me write the code faster. It did not agree to be responsible for it. Responsibility is what the client is actually paying for.
An excavator digs faster than a shovel. But you still don’t hand it to someone who has never dug and expect a foundation. The operator knows where the pipes are buried.
So yes, use AI
I am not against AI. I use it for boilerplate, for schemas, for boring validators, for generating OpenAPI specs from Zod schemas. It saves me hours.
But the product is not the code. The product is every decision about what code should exist, what should be rejected, and what happens when things fail. That part still needs someone who has built systems before, broken them, and fixed them at night.
So the offer stands. I will buy the subscription. You build it, deploy it, maintain it, and take the 2am call.
Or hire someone who will.
Sign in with GitHub to join the conversation.