AI is a Compiler
Moving up the abstraction chain
The Hard Part Was Never the Code
I have been a professional software engineer for over 15 years and in that time I have built many enterprise grade systems in large multi-national corporations, small businesses, and high growth startups.
I have, in the last couple of years, started to lean heavily into the use of AI agents for systems building and generating code. I personally find the use of these tools exciting and liberating because they allow me to think at a higher level along the abstraction chain. For me, writing the code was never the rewarding part of software engineering, nor was it the hard part.
The hardest part of building any digital system is creating abstract representations of a particular problem domain with sufficient ontological completeness that it may be compiled into machine code — while maintaining enough high-level abstraction that the code can be understood by others who have to improve or debug it.
Put differently: the real work of software engineering has always been modeling a problem space accurately enough for a machine to execute it and clearly enough for a human to reason about it. The code itself is just the medium.
The Abstraction Chain
When high-level languages like Java, C#, and Python began to become more prevalent, and as even more abstract frameworks were built on top of those languages, there was a generalized negative sentiment toward these higher-order languages from those who cut their teeth on C++, C, and assembly. That negative sentiment is similar to the negative sentiments that I hear today about the use of LLMs and agentic workflows.
The refrain from some of the programmers who came before was that by abstracting away these details developers could shoot themselves in the proverbial foot and build systems that had deeply nested bugs which could only be fully understood if one knew the mechanics of the underlying computational model.
They were right. Having a good understanding of how things work under the hood makes for better engineers and more resilient systems.
They were also sometimes misguided. By their very nature binary digital systems are predicated on treating each compilation layer as a black box. Instead of thinking in terms of memory registers, goto statements, and pointers, languages like Java and C# allowed developers to think in terms of objects, functions, and iterative loops. It would be very difficult to achieve practical utility in modern enterprises if that were not true. Every step up the abstraction chain has traded fine-grained control for broader expressive power, and every step has been met with resistance from those who mastered the layer below.
Thinking in Concepts
LLMs represent the next step on this chain. Unlike the compilers that came before, LLMs move beyond abstract representations like functions, objects, and loops. LLMs allow the systems builder to think in terms of linguistic concepts which are naturally much easier for humans to understand.
We are already at the point where the latest models can rapidly generate code which is both computationally valid and operationally cogent, assuming the LLM is given a sufficiently abstract and logically complete conceptual understanding of a given problem domain.
In practice this means that instead of designing a class hierarchy for an order management system, I describe the business rules and constraints of how orders flow through the organization. Instead of writing repository patterns and service layers, I articulate the boundaries between domains and the contracts that govern their interactions. The LLM handles the compilation down to code; my job is to ensure the conceptual model is complete and coherent.
Just as thinking in terms of objects was critical for the Java developer, thinking in terms of the conceptual boundaries in a given problem domain will be critical for engineers who leverage this new semantic layer of computing. The discipline is closer to domain modeling than to traditional programming, and it demands a different kind of rigor — not syntactic precision, but ontological completeness.
Moving Up
If you made your career building object-oriented or functional systems using higher-order languages like Java and Haskell, then these skills will serve you well in this new model, but it will require that engineers move up the abstraction chain and start first with an abstract representation of the problem space.
For junior engineers, it will still be valuable to understand the underlying principles of digital computational models, but in general the focus should be on design patterns and the process of breaking a problem into constituent parts.
To thrive in this new engineering paradigm everyone will need to move up the abstraction chain — just as the assembly programmers did when C came around, and C programmers did when Java took hold. The engineers who will struggle are those who confuse the medium for the craft. The code was never the point. The model was always the point.