The rate of adoption of AI coding assistants has been astonishing and impressive. This trend speaks to the utility of AI assistants, but it also reveals a huge gap in the evolution of software engineering. AI assistants like Claude and GitHub Copilot, and tools like Cursor and Windsurf, are helping developers “vibecode” entire features in minutes. Even non-developers can prompt them to create a ReactJS webpage or a Terraform configuration for an ECS container, and the tool does the rest. We marvel at this outcome, because it is so simple, but these feats distract us from what engineering leaders should really consider: software development has not evolved with the times.

To this day, when creating cloud infrastructure, we start with a blank AWS account, or an empty VPC. Or if a developer wants to create a web app in Flask, they start with a blank Python file. Even a more powerful framework like Django only creates a directory structure. To be sure, we have starter templates, boilerplates, and generators, but none of it has matured into true interlinkable, reusable components. Once Django has created the shell of an application, the developer still has to add a database. They still have to wire up authentication. They still have to configure local and remote environments. They have to manage secrets. These are

AI Is Repeating What We’ve Already Done

The current generative AI tools work along the basic principle of predicting the most likely output to a given input, using a neural network model that has been trained upon a huge data set. Coding assistants are resurfacing patterns that have been repeated thousands, perhaps hundreds of thousands, of times. The fact that AI can so accurately generate this code means it has seen the pattern before.

Therefore, when prompted to write the configuration to deploy a Lambda function in AWS, AI is up to the task. It not only produces the Terraform configuration for a Lambda function, but also the additional configurations that often go with it, such as logging and execution permissions in AWS’s identity and access management framework, because those components are also always present in examples and working code. The output has a high statistical probability. However, since the output is probabilistic, it often is not the same response each time.

Artisan Software: We Start From Scratch

Before AI assistants, a cloud engineer who wanted to create infrastructure would start with a blank file and fill it in from their own knowledge, a prior project, template or copy it from an article on the Internet. However, ideally they should have been able to issue a command or use a tool to generate that configuration, not based on statistical probability, but using deterministic rules on how components fit together. Many organizations end up creating these more complex building blocks for themselves (I worked at a Vietnamese bank that did this at scale), which represents untold hours of repeated effort. Open source software projects were a huge boost in productivity, but the evolution to the next step did not take place. That’s where AI is stepping in.

As mentioned earlier, there are literally dozens of foundational tasks that go into creating a production-ready application. Everywhere, there are blank files that need to be filled in. The code is one component, but there are many others. It doesn’t stop with the release. Once the application is live, more components need to be added.

Pre-release Tasks and Components

  • source code management
  • configuration parameters
  • environment variables
  • local development
  • automated testing
  • CICD pipelines
  • infrastructure provisioning
  • network configuration
  • application/image versioning and rollback
  • secrets management
  • static code analysis and dependency checks
  • linting and formatting
  • artifact lifecycle management
  • log accumulation, storage and retrieval
  • monitoring and alerts
  • backups

Post-release Tasks and Components

  • performance monitoring
  • performance testing
  • load testing
  • vulnerability monitoring
  • scaling and load balancing
  • denial of service prevention
  • intrusion detection
  • security information and event management
  • disaster recovery 

Bespoke Code: Saville Row of Software

Each of the above tasks becomes a decision point where software creation tools could have standardized the approach. Instead, each one is a potentially distinctive choice, leading to a huge variance from organization to organization. Sometimes, there is no standardization within an organization, or even, in extreme cases, within a project.

Ideally, a cloud engineer would use a tool to specify the infrastructure components they wanted, and the tool would create the code. This does not require AI. The components are formally defined and there are known interconnection points with others.

Similarly, a software engineer should be able to select the components they want in the application (a back-end framework, the database platform, an events queue, notification service, email) and a tool then should generate the boilerplate code connecting them all together. This is a task which can be repeatable across projects without requiring AI.

Use AI Now, Pay More Later

The reason that we need AI to perform routine software engineering tasks is the same reason why AI is limited when it comes to cost optimization. Since everyone started with a blank file and filled it in according to their own knowledge, everyone’s system was built slightly differently. Thus AI, which excels at generalizing based on many input samples, can overlook individual differences. Ask it for assistance in optimizing costs and it will mention the usual actions: reduce instance sizes, consolidate services, use spot instances. These are helpful, but it requires reasoning to go beyond the low hanging fruit.

For now, AI tools present a useful option to software engineers for saving time on common tasks. However, in the absence of better tools, engineering leaders should steer their teams towards creating building blocks and establishing templates, which are then reused across projects. Even with AI tools, individual developers should not be repeating work that has already been done elsewhere in the organization. This must not be a one-time exercise, because too often that leads to obsolete or incomplete components which don’t meet the development needs. Continually revisiting code libraries and upgrading across the entire app will lead to software development efficiency and improve the ROI or profitability of the application.