Code Is Cheap Now. Decisions Aren't
I’ve spent a lot of time working on software backlogs with coding agents. Pick an issue, inspect the code, make the change, run the tests, close it, move to the next one.
The strange part is how often writing the code is no longer the hard part.
An agent can add a field to a model, update the database, wire it through a client, and write a pile of tests before I check on it again. That would have been hours or days of time before. Now it happens in one focused session.
Great.
But the feature still needs someone to decide what the field means. Is it nullable? Which system owns it? Can it be inferred from another value? What happens when the provider stops sending it? Does an older local value survive, or should it be cleared?
The typing got cheaper. The decisions did not.
The Keyboard Was Never the Whole Job
We’ve spent decades measuring software work by its visible output. Lines of code, commits, pull requests, story points, features shipped. Code was expensive to produce, so counting the artifacts at least felt related to the effort.
That relationship is falling apart.
You can ask an agent for three implementations of the same feature and get all three before lunch. You can generate a REST API, a migration, a test suite, and a deployment manifest in one sitting. If you don’t like the architecture, ask for another one.
Now you have four implementations and a new problem: which one should exist?
Software development was never just converting requirements into syntax. It was deciding which requirements were real, where the boundaries belonged, what failure looked like, and which tradeoffs you were willing to own. Code generation doesn’t remove that work. It removes the part that used to hide it.
One Small Change, Twelve Real Questions
Let me give you an example.
Say an external API adds an optional date. Adding it to your application sounds trivial. Nullable column, property on the model, parse the response, write a migration, done.
Except the provider already has another date with a similar name. One is when the item was published. The other is when the user interacted with it. They’re both dates. They are not interchangeable.
So now the real questions start:
- Do we store only the explicit value, or infer it when it’s missing?
- Is a missing field the same as a field containing
null? - If the remote value disappears, do we delete the local value?
- Does this field participate in unchanged-record detection?
- Will a dry run exercise the same comparison path as a real sync?
- Can older installations run safely before the migration is applied?
- What happens when a second provider represents the same idea differently?
None of those are unique to any language. The agent can explain the options and implement whichever answer you pick, but it can’t discover your intended data contract from the shape of a JSON response.
If you skip those decisions, you still get code. You just get code that quietly invents policy for you.
Cheap Code Creates Expensive Options
This is the part that you might underestimate.
When implementation was slow, the cost naturally limited how many ideas made it into a codebase. You might sketch three approaches, but you probably built one. The friction forced a little restraint.
Agents remove that friction. A feature that would have been rejected as “not worth a week” now looks attractive because the first version only takes an hour. A speculative abstraction feels harmless because the agent can generate it in minutes. A new internal tool seems reasonable because the prototype already works.
It worked. But “it works” and “it’s a good idea” are two very different things.
The generated code still has to be reviewed. Its dependencies still need updates. Its behavior still needs tests. Someone still has to understand it when the surrounding system changes. If it handles credentials or customer data, somebody owns that risk too.
The implementation cost may be close to zero. The ownership cost is not.
This is how you end up with a backlog full of individually reasonable features that collectively make the project worse. Each one was cheap enough to add. Nobody stopped to price the maintenance costs associated with each successive feature.
Decision Debt
We already have a name for shortcuts in implementation: technical debt. You move quickly today and accept that the code will cost more to change later.
Agentic development creates another kind. Call it decision debt.
Decision debt is what happens when code gets produced faster than anyone can answer why it exists, what promise it makes, and who is responsible for it. The implementation is complete, but the boundaries are fuzzy. The tests prove what the code currently does, but nobody has decided whether that’s what it should do.
You can see it in questions like these:
- Are we supporting this behavior or merely tolerating it?
- Is this data authoritative, derived, or cached?
- Is this workflow meant for one person or every user?
- Is this abstraction solving a repeated problem or predicting one?
- What would make us remove this feature?
An agent can help you reason through every one of those. That’s one of the best uses of the technology. Ask it to inspect the repository, find conflicting assumptions, model failure cases, and challenge the proposed design.
Just don’t confuse receiving an answer with making a decision.
The Human Work Moves Upstream
If agents keep getting better at implementation, the valuable human work moves toward choosing and framing the work.
That means writing a clear definition of done before generating code. Deciding which system is the source of truth. Recognizing when two similar concepts need separate names. Looking at a working implementation and saying, “No, this does not belong here.”
It also means treating restraint as engineering work.
Closing a stale issue without implementing it can be more valuable than shipping the feature. Reusing an existing boundary can beat introducing a cleaner new abstraction. Deleting a half-maintained tool can improve a system more than generating its replacement.
None of those choices produce an impressive diff. That’s fine. The diff was never the product.
What Good Looks Like Now
I don’t think the answer is to slow agents down, or to pretend generated code is somehow less legitimate than code typed by hand. The code doesn’t care who wrote it. If it’s correct, understandable, tested, and worth owning, ship it.
The change is in where we spend our attention.
Spend less time admiring how quickly the implementation appeared. Spend more time checking the assumptions it smuggled in. Ask what new state the system owns, what promise the interface makes, what can fail, and whether the feature deserves to survive its prototype.
Agents make it possible to build almost anything you can describe. Our job is deciding what should still exist six months later.
I’d appreciate a follow. You can subscribe with your email below. The emails go out once a week, or you can find me on Mastodon at @[email protected].
AI Software-development Engineering Agentic-coding Technical-debt