What has happened since ITMGT 45
2026-08-13
This time last year, a colleague and I began delivery of ITMGT 45, which was a tech bootcamp of sorts for our ITE students. In a way it was the swan song of the "old" way of software engineering, where programmers would have to write (or at least paste) most of the code in their codebases themselves. I emphasized in the final modules that programs are ultimately a product of the mind, and thus protecting the conceptual integrity of the codebase is critical. I also emphasized that, in pursuit of this goal, it was worthwhile to invest in simple (i.e., unentangled, or uncomplected) tools even if they look unfamiliar. This was advice for a programmer that was expected, over the course of their career, to knead the codebase with their own hands.
It is now 2026. Very few people now doubt that LLMs, specifically used within coding harnesses, are capable tools. I personally haven't written a line of code (not counting commands and demos) in the few months since I first subscribed to Claude Max (if I may add, unwillingly at first). This isn't the place for me to dwell on the loss of my craft, though I still mourn it. This is instead my first stab at what I would tell my students about what has changed about software engineering since we last met. Perhaps some of you, dear readers, are from that ITMGT 45 class, in which case, this is for you.
As a codebase grows, you need to separate it into parts to keep it manageable. The design of these parts is part of the work of software engineering, as good separation means that changes to a part can be made in isolation from the rest of the codebase. Bad separation means that not only do you have to attend to a much larger part of the codebase, you also have to spread your attention across multiple files.
Typically these "parts," or "modules," have at least two components. The first is their interface, or the component that users from outside the module actually interact with. The second is their implementation, or the component that performs the logic of the module that is hidden from the user. The way I usually explain this is that, when you drive a car, your interface is the car's steering wheel and pedals, and the engine and fuel injection systems are the car's implementation details. As the driver of a car, you are not supposed to need to know how an engine works most of the time. You simply know that when you press the accelerator, the car moves, and when you press the brakes, the car slows and stops. This is of course rarely perfect in practice, since you need to bring a car in for maintenance and to a station for refueling, and some petrolheads really like getting into engine details, but most of the time you should not have to care.
Imagine now that you want to switch to an electric car. You don't need to re-learn how to drive, because what changes between a gas car and an electric car is the implementation. An electric car still maintains the pedals and steering wheel as its driver's interface, so you can still pursue the outcome (getting somewhere with your car) with controls familiar to you.
This is the principle of indirection. Good modules separate what from how. When a better how emerges, or if circumstances dictate a different how, a good module can change its how without changing what it does. Bad modules leak implementation details.
My thesis here is that a programming language used to be the interface between a programmer and the computer. That is why we were previously so tribal about our languages. We cannot help but develop opinions on the tools we use with our own hands. The rise of coding harnesses means that, for a lot of work, the programming language becomes an implementation detail. It is now far less important than the outcome it enables.
Some may argue that this has always been the case, but try telling that to anyone who got into Clojure or Elixir from the more mainstream languages. Some of us like it when the tools in our hands let us express ourselves. Yet now that a lot of common work can't economically be done by hand anymore (compared to just using a harness), the experience of commercial programming degenerates into a sameness of reviewing Markdown docs.
Let me be clear: I hate the way this is going. This must be how petrolheads feel about electric cars. But for you, dear ITE student, programming is a means to commercial end, so you mustn't close your eyes to agentic coding. I've stared into that abyss. This is not going away. Part of the trouble is that this new indirection, where coding harnesses and Markdown are the interface and the code is an implementation detail, satisfices nowadays. You can get a good-enough outcome without even seeing the code. I know because I've done it and because I've done enough the hard way to know that the vibecoding was good enough. I've had some disagreements with colleagues about whether we should present this fact to you or make it appear as if we are endorsing this, to which I say: I am not endorsing this. What's beautiful about software is that it's a product of the mind. It is, or maybe was, one of the few ways that labor could create something from nothing, and every month I have to give more of that ground to AI. It's miserable. I simply think that it's irresponsible to try to hide where the world has gone.
Notes
- Much of the vocabulary on indirection comes from Zach Tellman's talk on abstraction.