We can build more, faster, “better”, than ever have before. What we’re seeing as a consequence is a rapid “spread” of features - applications that go from doing nearly nothing, to everything short of taking out the rubbish - in the span of a few days/weeks.

Personally I’ve always been an advocate of slowing down, even before we had LLMs in the mix, but I think there’s a different way of phrasing it. Now we can build features incredibly quickly, and we aren’t compensating for the maintenance burden that used to build slowly over time.

The Insane Concept of Letting Support Support

Years ago, long before even rudimentary LLM tools existed, I was part of a small hackathon. The business I was part of had very much cobbled itself together from startup roots and had broadly relied on developers and operations teams configuring the application for users. While this had scaled fine, a true bottleneck had developed when the much-needed customer support team had joined the business. They understood the platform very well and were well versed in what it was capable of and how it worked. They were good at getting requirements from the customers and breaking that down into what needed to be set up in the system. However, they had not access to change these things themselves - and even if they did, they had limited understanding of how the database worked, so would need technical guidance to perform the changes anyway.

During the hackathon, a trio of us from different functions got together, and built a quick CLI tool. It wasn’t anything robust or fancy, but what it did allow was a customer support person to directly configure the service without needing to understand how DynamoDB worked. It was great, it was a simple tool that’d have saved loads of manual poking, it was essentially ready to go even in the state it was in… and it was immediately shelved after the hackathon and never touched, in favour of more “feature work”.

Because it was shelved, the application moved on, the prototype quickly became useless, and we remained with the same burden of maintenance we had before.

But it is just an MVP?

The “minimum viable product” is something of a meme in software development. It often gets tied to agile working processes - although historically it still used to drive the idea of a shorter waterfall in order to get something delivered to the client. The MVP was typified by a slightly “robust” looking UI that did the thing the client needed to do, and nothing more. Backend provisioning and setup would be a manual process and things going wrong outside of the “happy path” was basically expected. In my mind, the only real change I’ve seen from agentic workflows is that the UI is significantly slicker on the early versions of software, and it has more apparent features to play with. Provisioning is still rarely considered - usually an MVP is for the first client/user, and the idea of tenancy comes later.

The focus is to get something in the “hands of a user” so they can prove that there’s a desire for the software. Hence why one of the key criteria is the MVP being cheap to produce - not maintain, critically. An experimental development step to see if continuing to invest in the idea will bear fruit, or if the resources should be funnelled elsewhere. With agentic development however, the minimum seems to have radically shifted. It’s possible to create weeks, months or even years worth of code and apparent functionality in magnitudes less time. Obviously this should be great, except it means the software we develop can easily outstrip our ability to maintain said software. Where before a team might build out a feature in a few weeks and have a deep understanding of how it works, now an individual can build the same feature in a couple of days. The knowledge of how it works and is configured isn’t spread amongst a group and is instead (at best) contained to a single individual and maybe some specification documents. The industry hasn’t adapted to this, and we still then rapidly shunt onto building the next feature, as we’re used to the throughput being much lower.

We need all these features to sell our product though!

Working with LLM agents, it’s quite “easy” to turn out software that’d meet or exceed the bar of what we’ve classically considered an MVP. Businesses are obviously delighted by this - they can get what they need faster, and in turn can ship to consumers quicker. As much as I wish the argument could just be dismissed as “well, you didn’t need all those features to sell in the past” - with all the competition also leveraging agentic development, it’d be like hand-crafting C while everyone else is writing Go. You might end up with a slicker, refined system - but your competition beat you to a broader market in a fraction of the time.

The problem is that the maintenance burden of this work doesn’t change as much in the agentic world. You can ask the agent to fix bugs or configure infrastructure when issues come up, maybe reply as “first line” to some tickets. But fundamentally these models don’t have a concept of production, continuity or customers (no matter how much context you force into them), meaning these steps still require quite a lot of supervision. They also don’t have the ability to accept responsibility for an issue - they feel nothing if a customer threatens to leave the business because the configuration is going to take days to be actioned.

Backfilling admin functionality has always been a hard task, and one that’s incredibly hard to convince a business to prioritise. In my opinion, it also doesn’t scale linearly with the number of features a piece of software contains. Every time a feature is added, the way it interacts with other features also needs to be considered as part of the configuration surface. And there is always a configuration surface. Be it everything from “simple” feature flags turning things off, right through to entirely configuration driven systems with their own meta programming. If the features didn’t interrelate, then often the system wouldn’t be worth provisioning. I’ve made analogies in the past to data being like oil, and software being pipelines and refineries - ultimately users aren’t paying for the pipe, they’re paying for the product of it. The more your features interrelate over the data, the more value you’re often providing - even if the complexity spikes massively from the interconnections.

The holy grail solution to this is the idea of user self provision - every business I’ve worked in has pushed in this direction, with varying levels of success. However, especially in a B2B context, a user is looking to pay for configuration and maintenance as part of the service. So even if the tool for configuration is nominally customer facing, you should still handle this as a part of the larger ask for back-office administration.

How can we change our approach to building software?

We do ourselves a disservice when we don’t consider the full loop of how a system works. In traditional development, to hit a milestone the administration and control of features is pushed into a future that is to be strived for, with the understanding that some databases can be poked to get things over the line. This feels like a missed opportunity - a key property of administration tools is that the maintainers (be that developers, a platform team, or the business itself) are uniquely tolerant of rough edges and user guides. This means just a modest amount of time (or prompting) is enough to give quite a lot of control to someone outside the developer, or other developers, or at least have the tool exist as a form of “living documentation” for the feature.

Really what I’m asking you to consider is extending what is seen as the consumer of the code, beyond the end user who pays for the service. What is important to remember though that even if the person doing the config is a programmer - they’re still not you. It can be tempting to build out administration tools for our use, where we have working knowledge of the systems behind the configuration, as well as a high tolerance for configuration-as-text such as TOML or YAML and can keep in our heads what all the fields mean and control. We still have a duty of care though to present a human interface which doesn’t require specialist knowledge or understanding to use - instead, we should prioritise an interface that leverages internal consumers knowledge of the business domain in which we are operating. Put simply with an example - a specialist may not be able to understand a TOML file that configures the endpoint and its authentication to use for a person lookup, but they are going to know the company names and which ones are trustworthy from a dropdown.

Conclusion

As developers, our goal is not to be a constraint on the business. We should be enabling operations and providing simple, clean solutions not only to our end users but to consumers within the business as well - be that operations and test in our local domain, or more traditionally distant teams of sales and customer relations.

We can continue on a path of getting features out incredibly quickly to users, drowning them in half-built software that fits the needs of now but cannot be carried into the future. Except all I think we’re really doing is accelerating ourselves into the worst state of software development - the hard to change, inscrutable legacy enterprise system comprised of tens (or hundreds!) of thousands of lines of code, where the only person who can configure it is Jo, who has been with the company forever and remembers everything. Except there is no Jo, just an infinite monkey cage which prioritises trying to write more code and features to solve the problem, because it doesn’t feel the pain of maintenance, because it doesn’t feel anything.