Blog post

I Could Build Faster. That Was Not the Hard Part.

AI makes software cheaper to explore and build, but not equally cheap to understand, secure, review, and own.

I Could Build Faster. That Was Not the Hard Part.

When I started using coding agents seriously, the most obvious change was speed.

Things that previously required enough effort to deserve a place on a backlog could suddenly be tried in an afternoon. A new workflow, another screen, a role distinction, a settings branch, an integration: none of these became free, but the implementation cost fell far enough that the old hesitation largely disappeared.

At first, this felt like a straightforward productivity gain. I could explore more ideas, discard weak ones earlier, and move through the first version of a product much faster.

All of that was true.

What took me longer to notice was that implementation effort had been doing another job for me. It was a crude filter on decisions.

When an additional feature took days, I had to care about whether it belonged in the product before building it. When a second role implied several state transitions and permission rules, the cost forced the question into the open. When an abstraction was expensive to introduce, I was less likely to create it because a hypothetical future might need it.

That friction was not good judgment. But sometimes it forced judgment to happen.

Coding agents removed much of the friction without removing the need for the decision.

I started seeing the consequence in small, plausible additions. An agent could produce a route, a query, a component, a test, and a helper in one pass. Each part could look reasonable. The feature could work. The tests could pass. And yet I could still end up owning a new piece of system behavior before I had really decided that the behavior deserved to exist.

The problem was not that the AI produced bad software. It was that software could become durable faster than my decisions did.

That changed how I think about MVPs.

Earlier, “minimum” was partly enforced by cost. Today I can build a surprisingly broad first version while still calling it an MVP. Roles, notifications, settings, edge flows, polished onboarding and future-facing abstractions can all fit inside a small implementation budget.

But an MVP was never supposed to mean the largest first version I can afford.

It is useful when it reduces a specific uncertainty.

If I am testing whether one recurring workflow removes enough friction for a user to care, a broader product does not necessarily give me a better answer. It may give me a more impressive demo, while making the result harder to interpret. If users do not adopt it, I now have many possible explanations. If they do adopt it, I still may not know which part mattered.

AI increased what I could include before it increased what I could learn from including it.

That was the first shift.

The second was architectural.

I used to understand patterns such as application layers, ports and adapters, domain boundaries and explicit request context mostly as ways of keeping a codebase clean. On a small product, some of that structure could feel premature. Another boundary looked like another file between me and the feature.

That changed when implementation became faster than review.

Agents are very good at extending the patterns already present in a repository. That is useful when those patterns encode deliberate decisions. It is much less useful when they encode shortcuts.

A convenience added in one route can become precedent for the next route. An optional permission check can become the locally normal way to call a repository. A tenant identifier passed manually once can become the shape reproduced everywhere.

The resulting codebase may be consistent. That does not mean the consistency was designed.

This was the point where architecture stopped feeling like ceremony to me. I no longer cared primarily about whether a codebase matched a named pattern. I cared about which mistakes would become cheap to repeat.

Tenant scope was an obvious example. If a future patch can casually replace trusted tenant context with a value coming from a request, that is not a code organisation problem. It is a different class of failure. The architecture should make that mistake difficult to express.

The same reasoning applies outside security. A business rule repeated inside routes will be reproduced as if the repetition were intentional. An external integration allowed to leak its types through the domain will become harder to replace every time an agent follows the precedent. A UI component that quietly invents its own state interpretation can teach generated code that local interpretation is acceptable.

Agents amplify the repository they are given.

That made me much more selective about where I want friction. I still do not want architecture everywhere. I want it where cheap implementation would otherwise make an expensive mistake easy to multiply.

There is also a third cost, and this one is easy to miss while a product is still young.

Software can be cheap to create and expensive to own.

Once a feature becomes part of the product, somebody has to understand what it does months later. Permissions have to remain coherent. Migrations have to work. Failures need to be visible. Integrations need to be maintained. Tests need to challenge more than the happy path. A future change needs enough context to avoid rediscovering the original intent.

None of this appears in the first successful generation.

I now find it useful to think in terms of two budgets.

The first is an experiment budget. I am willing to spend it to answer a question. Code can be narrow, temporary, even disposable if discarding it is part of the plan.

The second is an ownership budget. The moment I decide that a piece of behavior belongs in the product, the accounting changes. I am no longer paying only for its implementation. I am accepting its tests, observability, access rules, migrations, failure modes, documentation, operational context and future review cost.

AI has made the first budget much larger.

It has not enlarged the second by the same amount.

That distinction has become particularly useful when something starts as an experiment and quietly survives. A prototype can prove that an interaction is worth pursuing without proving that its current implementation is the right foundation. A generated integration can demonstrate value without earning a permanent place in the architecture.

Calling such work “experimental” after users depend on it does not make the ownership disappear.

This is also why I have become less interested in asking whether AI makes software development cheaper in the abstract. The answer depends on which phase of the software's life I am pricing.

Exploration is cheaper. Initial construction is often dramatically cheaper. Some maintenance work is cheaper too.

Responsibility is more stubborn.

The practical consequence for me is not to slow AI-assisted development down. It is almost the opposite. I want to use the cheap part aggressively: prototype, compare, discard, learn.

But I want a clearer moment where cheap possibility turns into owned product surface.

Before that transition, I now ask a few concrete questions.

What uncertainty did this work reduce? Which part of the implementation is evidence, and which part am I about to treat as product? What new behavior will I have to keep coherent? Which boundary becomes consequential if the next generated change copies this one? If this still exists in six months, will I understand why?

Those questions are not an argument against speed. They are how I decide where the speed is actually useful.

This also changed the way I review AI-generated work. A working implementation tells me that a behavior can occur. It does not tell me whether the product should own that behavior, whether the architecture placed responsibility correctly, or whether the tests examined the dangerous assumptions.

I explored that distinction more directly in Working Is Not a Quality Metric. And once the bottleneck moves from implementation to judgment, planning becomes less about ceremony and more about making consequential decisions visible before generated work spreads — the subject of Planning Is Where AI Work Becomes Reviewable.

I still build much faster than I did before coding agents.

The difference is that I no longer treat that speed as the answer.

It is capacity. What matters is what I decide to turn into a responsibility.

Continue exploring

Follow the same line of thought through themes, tags, or a broader local search across the archive.

Keep following the thread.