Barte/ dev

Engineering

AI made code cheap, but trust is still expensive

AI made generating code cheap. Trusting the changes became the bottleneck — and a solid test suite is what sustains that trust.

by Rafael Souza da Silva··7 min read

With the evolution of coding agents and the various autonomous development flows that have emerged in recent years, one thing has become clear: producing code has never been so cheap. The main bottleneck in software development is no longer writing code, it is trusting the changes being made.

Today it is common to work with agents that analyze a problem, suggest different implementation approaches and recommend which one makes the most sense for a given context. Once we approve an execution plan, whether in an iterative flow or a one-shot prompt, the agent is able to implement a complete feature in a few minutes. The process seems simple: code delivered, tokens spent and task finished.

That is the happy path.

In practice, we know the work does not end when the code is generated. On the contrary, it is precisely at that moment that the main question arises: how can we trust that the changes made are correct and did not introduce regressions in the system?

Agents tend to produce better results when they work on smaller, well-defined tasks, however, that does not mean that small changes are necessarily low-risk. A simple change can modify contracts, break integrations or introduce side effects that are hard to spot during a manual review.

AI has solved much of the code generation problem, but it has not solved the fundamental problems of software engineering, such as business context, architectural consistency, contracts between components and guarantees about system behavior. These remain challenges that must be handled by the development process.

This is exactly where a good test suite becomes even more relevant.

Tests have always been important

Tests have always been important, long before coding agents existed. Unit tests, integration tests and validation pipelines have always played the role of protecting the evolution of software, ensuring safety during the deploy process and reducing the risk of regressions. The arrival of AI did not change that fact; it only increased the return we get from investing in a well-built test suite.

Within the testing pyramid, unit tests remain one of the fastest and cheapest feedback mechanisms we can have. They let us validate specific system behaviors in a few seconds, providing confidence for code changes and speeding up the development cycle.

More than validation mechanisms, tests also work as executable documentation of the expected behavior of the system. They provide context for developers, continuous delivery pipelines and, now, also for agents responsible for implementing and evolving the software.

In the context of AI-assisted development, tests have also become one of the most precise ways to specify behavior for agents. A failing test is usually far less ambiguous than a textual description of a requirement. The more explicit the system’s contracts are, the greater the agent’s ability to propose and validate changes safely tends to be.

A robust test suite does not only protect the application in production. It establishes clear guard rails about what can and cannot be changed, allowing agents to operate with greater autonomy and safety. The greater the autonomy we delegate to AI during development, the greater the need for mechanisms capable of ensuring that the expected behavior of the system has been preserved.


TDD and software design

Adopting unit tests as part of the development flow has never been simple. Whether because of the difficulty of getting started writing tests using TDD, the complexity of maintaining high cohesion and low coupling in the code, or the challenge of thinking granularly enough to allow the software to evolve over time, building a good test suite has always required engineering discipline.

But there is an extremely positive side effect in all of this: good tests are usually a consequence of good software design.

Whether or not you follow TDD strictly, keeping tests as part of the development culture tends to lead us to better domain modeling, more decoupled components and more explicit contracts about the expected behavior of the system.

Once these contracts exist, they start to be consumed not only by developers, but also by the agents responsible for evolving the software. Tests stop being just a validation tool and become part of the system’s specification itself.


AI-assisted development

In a modern AI-assisted development flow, it is common for the process to look something close to this:

flowchart LR
  A[Requirements]
  B[Specification]
  C[Specification + Tests]
  D[Implementation with AI]
  E[Local review with AI]
  F[Validation]
  G[CI]
  H[Deploy]
  I[Monitoring with AI]

  A --> B
  B --> C
  C --> D
  D --> E
  E --> F
  F --> G
  G --> H
  H --> I

When we think about this pipeline, it becomes clear that tests play a much larger role than simply validating whether a feature is working. They act as guard rails for the agents, limiting the space for error during implementation and significantly increasing confidence in the changes made.

This lets us delegate increasingly complex tasks to agents. Large refactors, architectural changes, library migrations and API evolution stop being changes that cause constant apprehension and become changes protected by contracts previously established by the test suite.

The question stops being “can the agent do it?” and becomes “how do we know it did it correctly?”.

With a mature test suite, we drastically reduce the need for manual validations during development, since a large part of the checks are already automated within the delivery pipeline.

It is worth noting that agents are excellent producers of code and pull requests, but they still depend on the same mechanisms we have used for years to build confidence in software. The role of the validation pipeline remains exactly the same: to answer whether that change is ready to move to production.


Test-driven bug fixing

Another point that has helped us a lot is the flow for solving bugs using agents. Instead of starting a fix directly in the code, development begins with the creation of a test that reproduces exactly the behavior observed in production.

The flow is relatively simple:

flowchart LR
  A[Bug reported]
  B[Write a failing test]
  C[Fix with AI]
  D[Tests passing]
  E[Validation in CI]
  F[Deploy]

  A --> B
  B --> C
  C --> D
  D --> E
  E --> F

This approach has two big advantages. The first is ensuring that the problem was effectively reproduced before implementing the fix. The second is turning the bug itself into a new contract of the system, preventing it from being introduced again in the future.

On top of that, it fits very well with the way agents work. A test reproducing exactly the incorrect behavior provides extremely objective context about what needs to be fixed and what the expected result is after the implementation.


Integration tests and system consistency

Finally, for applications that provide services and have integrations with partners, integration tests play an equally important role. Adequate coverage of the integration flows guarantees consistency in the API layer and in the contracts established between the components of the system.

Even if a developer or an agent makes changes in different layers of the application, the test suite remains responsible for ensuring the integrity of the service and the preservation of expected behaviors.

We can look at it this way:

flowchart LR
  A[Change in the system]
  B[Unit tests]
  C[Integration tests]
  D[Contract tests]
  E[CI]
  F[Safe deploy]

  A --> B
  B --> C
  C --> D
  D --> E
  E --> F

Each layer of the test suite increases our confidence in the changes made, allowing agents to work with greater autonomy without compromising the stability of the system.


Conclusion

AI made code cheap to produce, but it did not make software more reliable. That responsibility is still ours.

The greater the autonomy we give to agents, the more explicit the contracts that define the expected behavior of the software need to be. The test suite stops being just a validation tool and becomes one of the main governance mechanisms of AI-assisted development.

At Barte, this stopped being theory. As an example, over the past year we increased our monolith’s test coverage from around 20% to over 60% instruction coverage, with the number of tests growing roughly 10× (from ~500 to more than 5,000) — much of it from building an integration test suite that barely existed before. And this isn’t an isolated effort: that suite is one of the pieces of the paved road we’re building at Barte, the same one that makes it safe to delegate more and more to agents and to increase the confidence in our deliveries.

Writing code is no longer the hardest part of software development. Trusting that it keeps doing exactly what it should do has never been so important.