The Component We Didn't Need to Build

I've been thinking quite a bit lately about how AI is changing the decisions we make when developing software.

Not just how quickly we can write code, but whether we should be writing certain code at all.

Consider something as ordinary as a data grid.

We could ask AI to build one, and there's a good chance it would produce something useful fairly quickly.

But we could also choose an established component that already incorporates years of development, testing, and practical experience.

And as I've been working with more AI agents across larger projects, I've come to appreciate another benefit of those established components.

Consistency.

That's something that may be even more important than the code we didn't have to write.

The Temptation Is Obvious

Suppose we're building a business application that needs to display information in rows and columns.

We want sorting, filtering, searching, selection, and perhaps some editing capabilities.

That's a problem AI understands quite well.

Describe what you want, give it the appropriate development environment, and it can probably produce something useful fairly quickly.

If you're experimenting with an idea, that may be exactly what you need.

But there's a difference between displaying a hundred records in a demonstration and providing a dependable grid for a business application.

What happens when the user changes the column order?

What happens when someone wants to resize a column and have that preference remembered?

What about keyboard navigation?

What about selecting multiple records?

What about displaying large amounts of information without loading everything into memory?

What happens when the application needs to refresh data while preserving the user's position?

And how well does everything behave when the application changes size or the available screen space becomes smaller?

None of these questions makes building a grid impossible.

But they demonstrate that the problem is considerably larger than placing some rows and columns on the screen.

And that's before we consider how the grid should behave consistently with the rest of the application.

The Part We Don't Have to Learn Again

This is where mature components become interesting.

A good component represents more than the code that implements its visible features.

It also represents the experience accumulated while developing and maintaining it.

Someone has encountered unexpected requirements.

Someone has discovered interactions between features that weren't obvious in the original design.

Someone has worked through performance problems, unusual data, and user expectations.

Someone has probably had to fix a bug that seemed simple until the fix broke three other things.

That experience has value.

Not because the code is necessarily difficult for AI to reproduce.

Much of it probably isn't.

The value comes from knowing what needs to be reproduced in the first place.

That's the part we can easily underestimate.

We look at a finished component and see a collection of capabilities.

We don't necessarily see the years of decisions that led to those capabilities behaving the way they do.

And when we ask AI to create an alternative, we're not automatically getting the benefit of that history.

We're getting an implementation based on what we asked for and whatever additional requirements the AI recognized.

There may be quite a bit of distance between those two things.

One Application, Many AI Sessions

There's another benefit to using established components that I've come to appreciate more as my own AI-assisted development work has grown.

Consistency.

When we're developing a substantial application, there's a very good chance that different parts of it will be built by different AI sessions.

Perhaps one session builds the customer maintenance screen.

Another builds an order-entry interface.

A third adds reporting functionality.

A fourth comes along several weeks later to implement a new feature.

Each session might be given the same general instructions.

And each might produce something that works perfectly well.

But there's no guarantee that they'll make the same decisions.

One agent may choose a different layout.

Another may implement its own dialog controls.

Another may change the way search results are displayed.

And yet another may introduce a slightly different approach to keyboard navigation.

Before long, the application begins to accumulate small inconsistencies.

Not necessarily bugs.

Not necessarily failures.

Just differences in how things look and behave.

From the developer's perspective, those differences may seem minor.

From the user's perspective, they can make the application feel as though it was assembled from unrelated pieces.

This is one of the reasons I'm inclined to use established interface libraries and component toolkits when they fit the application.

A mature toolkit can provide a common vocabulary of controls and interactions.

Buttons have established appearances and behaviors.

Dialogs follow familiar patterns.

Selection controls work consistently.

Navigation and keyboard interactions follow recognizable conventions.

And when different AI sessions use those same components, we reduce the number of design decisions each session has to make independently.

That doesn't solve every problem.

Even with a mature toolkit, an AI agent can assemble the available components inconsistently.

A standard button doesn't tell the agent where the Save button belongs or what should happen when the user cancels a transaction.

We still need application-level design rules.

We still need shared patterns for common operations.

And we still need to verify that the result behaves the way we intended.

But we've eliminated a considerable amount of unnecessary invention.

Instead of asking every AI session to independently discover what a good interface should look like, we're giving those sessions a consistent foundation to work from.

And sometimes that consistency is just as valuable as the code we didn't have to write.

It's Not a Contest Between AI and Existing Software

I think this distinction gets lost in some discussions about AI-generated code.

Someone demonstrates that AI can build a component.

Someone else points out that a commercial or open-source version already exists.

Then the conversation becomes a debate about which approach is better.

But that isn't necessarily the interesting question.

AI isn't obligated to replace everything developers previously purchased, licensed, or reused.

It's another tool that changes what we can accomplish.

In fact, AI can make existing components more valuable.

It can help us understand unfamiliar APIs.

It can create working examples.

It can help integrate a component into an existing application.

It can investigate compatibility problems.

It can write tests around the behaviors we depend upon.

And it can help us decide whether a particular component is suitable before we've made a substantial commitment.

That means we're not limited to choosing between building everything ourselves and struggling through someone else's documentation.

We have a very capable assistant that can help us evaluate and use existing technology.

That's a much more interesting opportunity.

Existing Doesn't Automatically Mean Better

I also don't want to suggest that finding an existing component settles the question.

It doesn't.

A component can be mature and still be wrong for our application.

Perhaps it doesn't support the development environment we need.

Perhaps its licensing is inappropriate for our intended use.

Maybe it introduces dependencies we don't want.

Maybe the project is no longer maintained.

Or perhaps our requirements are sufficiently different that integrating it would create more complexity than building a focused implementation ourselves.

Those are all legitimate considerations.

Sometimes creating our own component really is the best decision.

But even then, there's an important distinction between creating a shared component that serves the application and independently recreating the same functionality every time we need it.

We might have a perfectly good reason to develop our own grid, editor, or navigation system.

Perhaps we need capabilities that existing solutions don't provide.

Perhaps we need tighter integration with our application's architecture.

Or perhaps owning the implementation gives us an advantage that justifies the ongoing responsibility.

Those can all be sound reasons.

But if we make that decision, we should still establish a common implementation that the rest of the application can use.

The real objective isn't to avoid writing our own components. It's to avoid repeatedly solving problems that should only need to be solved once.

The Question I Would Ask AI First

Suppose I need a sophisticated grid in a new application.

I could begin by asking AI to build it.

But I think a better starting point would be to ask something like this:

What existing components could satisfy these requirements, and what would we gain or lose by using them instead of creating our own?

Then I would want to look at the answers.

Not just a feature checklist.

I would want to know about integration, customization, licensing, performance, support, and the kinds of limitations that might become important later.

I'd want to see an actual working example.

I'd want to try the unusual cases that matter to the application.

And I'd want to understand what responsibilities we would still own after choosing the component.

I'd also want to know how well it fits the rest of the application.

If we're already using a particular component library, does this new capability follow the same visual and behavioral conventions?

Will another AI session be able to use it consistently?

Can we establish a common implementation that doesn't have to be reinvented every time we need another screen?

Because using an existing component doesn't eliminate our responsibility for the application.

It simply changes where we concentrate our effort.

Instead of developing and maintaining every underlying capability, we can spend more time on the things that actually distinguish our software.

The workflows.

The business rules.

The information.

The user experience.

The problems our customers are paying us to solve.

That's a pretty good trade when the component fits.

What AI Changes About the Decision

Years ago, the build-or-buy decision was influenced heavily by development cost.

If something would take six months to build and a suitable component could be licensed for a reasonable amount, the calculation was fairly obvious.

AI changes that calculation.

Perhaps we can now create a workable version in a few days.

Perhaps we can build a custom implementation that would previously have been too expensive to consider.

Those are genuine advantages.

But they don't make the maintenance question disappear.

Every component we create becomes something we own.

We own its defects.

We own its compatibility requirements.

We own its future enhancements.

We own the obligation to make sure it continues to work when the surrounding application changes.

And if we've created several slightly different versions of that component across different AI sessions, we own the problem of keeping those versions consistent, too.

AI can help us discharge those responsibilities.

But somebody still has to recognize what needs doing, decide whether the result is correct, and accept responsibility for the finished software.

Of course, adopting someone else's component creates responsibilities of its own. We may depend on its continued maintenance, its licensing terms, and its compatibility with future versions of our development environment.

Those costs need to be considered as well.

But the decision should be based on the long-term value of the approach, not simply how quickly AI can produce the first working version.

The cost of writing that first version may have dropped dramatically.

The cost of owning the result hasn't necessarily dropped nearly as much.

And I think that's the part we need to keep in mind.

Sometimes the Best Code Is the Code We Never Write

The more I work with AI-assisted development, the more convinced I become that there's still tremendous value in reusable software.

That value isn't disappearing because AI can generate code.

If anything, AI gives us more ways to take advantage of it.

We can create components where our requirements justify them.

We can reuse mature components where they already solve the problem.

We can build integration layers that make different technologies work together.

We can establish common conventions that allow different AI agents to contribute to the same application without each inventing its own approach.

And we can direct more of our development effort toward the parts of an application that actually create value for its users.

The important thing is that we're making those decisions deliberately.

Not because writing code is difficult.

Not because AI can or cannot reproduce a particular component.

But because we've considered what we're trying to accomplish and where our effort will produce the greatest return.

AI has made it easier than ever to build another component.

That may be the best reason yet to ask whether we need to.


Related Guide: The Fiftieth Screen Is the Real Test explores why the real measure of software architecture is often how easily an application can change after it has grown.