Skip to content

Software Architecture

When AI Gets Better at the Wrong Thing

I've been wondering why some AI development efforts become remarkably productive and strangely underwhelming at the same time.

You know the pattern. An agent creates a plan, writes the code, runs the tests, reviews its own work, finds more things to improve, and starts another iteration. Perhaps a second agent critiques the first. The implementation gets more sophisticated. The test count grows. The progress reports are encouraging.

Then you try the result.

Everything seems to work. Yet it isn't quite what you had in mind.

That's the rabbit hole I've been thinking about: not an AI going off task in some spectacular way, but an AI making steady, defensible improvements to something that never quite becomes the thing you wanted.

I Don't Want AI to Just Build What I Ask

I've noticed something interesting about the way I work with AI. Increasingly, the part I value most isn't watching an agent finish a task. It's the conversation we have before either of us knows exactly what the task should be.

There's an appealing model for AI-assisted software development: describe a feature, let the agent work, and inspect the result. Sometimes that's exactly right. If I need a straightforward implementation and can describe the outcome clearly, I don't need a philosophical discussion with my compiler's new best friend.

But some of my most valuable work with AI has happened when I didn't start with a settled answer.

I've come to think of this less as delegating to an unusually fast developer and more as collaborating with another participant in the reasoning. Not because the AI and I are identical, or bear the same responsibility, but because the ideas move in both directions.

The Right to See What AI Is Building

As autonomous agents become capable of building complete software systems, architectural visibility may become more important than architectural control.

I've been questioning something about the role of software architecture in an age of autonomous AI.

For most of my career, architecture has been something we do to guide implementation. We examine requirements, identify boundaries, define responsibilities, make technology decisions, and establish the constraints that developers are expected to respect.

The assumption is that good architecture helps us build better software.

But I've been experimenting with autonomous coding agents, and some of the results have challenged that assumption.

In one experiment, I asked two AI agents to build the same application. One had access to a formal architecture system that could model the design, bind it to technology choices, and verify its implementation. The other worked without it.

Both produced remarkably similar results. Both made sound architectural decisions. Both built polished, working applications. Both successfully handled a significant change to the original requirements.

The architecture tooling produced better traceability and caught a real structural problem. But it didn't produce noticeably better software.

At first, that was disappointing.

Then I realized I might have been measuring the wrong thing.

The Architecture Was Correct. The Software Wasn't.

What happens when we build a perfectly well-architected system that nobody actually wants?

Software architects have a peculiar talent.

Give us a sufficiently complicated problem, and we'll find a way to turn it into boxes and arrows. We'll identify bounded contexts, establish dependency rules, define interfaces, and debate whether two services should communicate synchronously or asynchronously.

Eventually, someone will ask the question we've been carefully avoiding.

"Does it actually work?"

Of course it works. Look at the diagram.

The boundaries are clean. The dependencies flow in the right direction. The services are independently deployable. There's even a message bus.

It's beautiful.

Unfortunately, the users hate it.

The Context That Lets an Agent Work Alone

I've noticed something about the way I work with Claude Code. I tend to spend a considerable amount of time at the beginning of a session talking through what I'm trying to accomplish, sometimes before I have a clear idea of the implementation. Once the agent starts implementing, I rarely need to correct its direction.

That might sound like I'm writing unusually detailed instructions. I don't think that's quite what's happening. Often I don't know what the implementation should look like yet. If I did, there would be much less to explore. I'm trying to give the agent enough relevant context to find the shape of a good solution on its own.

Agents Can Only Fix What They Can Detect

I've been spending a lot of time building Continuum Atlas, a deterministic renderer for software architecture diagrams.

One of the challenges is getting diagrams to look good without compromising their accuracy. That's harder than it sounds.

Atlas evaluates different layouts using measurable properties: how many lines cross, how many bends they contain, how elements align, how they're spaced, and how well the diagram fits within its available space.

The idea is straightforward. Generate several candidates, measure them, and select the best one.

At least, that's what I thought.

I had a diagram where none of the five layouts generated using ELK's connector routing passed validation. After replacing that routing with Atlas's own obstacle-avoiding A* algorithm, all five passed.

That was a significant improvement.

But when I looked at the results, one of the newly valid layouts was actually worse. It had less measurable clutter, yet it was noticeably harder to read.

The measurements weren't wrong. The algorithm had genuinely improved the results according to the properties we were measuring.

The problem was that we weren't measuring everything that mattered.

I've been thinking about that experience because it highlights something important about agentic AI.

An agent can only correct a problem if something in its feedback loop can recognize that the problem exists.

When "Duplicate Users" Stopped Being a Problem

There was a period in my career when seeing the same business concept appear in multiple systems made me deeply uncomfortable. If I found a User table in one system and another User table somewhere else, my instinct was to assume that something had gone wrong. The same was true for Accounts, Employees, Customers, Sites, and Organizations. Surely there should be a single authoritative service for each of these concepts. If there wasn't, hadn't we duplicated the data? Weren't we creating conflicting sources of truth?

That intuition drove many of my architectural decisions. Whenever a new system was being designed, one of the first questions I would ask was: who owns Users? It felt like the right question, and for a long time I believed it was.

Distributed Systems Are an Ownership Problem

I've been trying to understand why distributed systems felt so much harder than monoliths when I first started building them.

Not technically. I expected them to be technically harder. What surprised me was how much harder they were to reason about. I'd read about eventual consistency, retries, idempotency, message ordering, and distributed transactions, and none of those ideas were beyond me individually — if someone explained a pattern or a technology, I could usually follow along without much trouble. But when I sat down to design a distributed system myself, something felt different. Two experienced developers could look at exactly the same problem and arrive at completely different architectures. Both could sound reasonable. Both could work. Yet somehow one solution would almost always prove easier to evolve a year later, and for a long time I couldn't explain why.

I thought I just needed to learn more technology. Now I think I was trying to solve the wrong problem.