The Programmer’s Guide to Hating AI – Part 4: A Brief History of “Coding Is Dead”

Introduction

Those who do not know history are doomed to repeat it.

In the previous parts of this series I have been addressing AI itself. Now I am going to start talking about how it has been targeting my field of software engineering. None of this is new. This is not the first time “coding is dead”, or even the first time AI in particular was going to kill coding.

An excellent review of this cycle of history is here. I encourage you to read this, it covers the timeline better than I ever could. What I want to do is highlight the most pertinent parts of the timeline, and give a somewhat different perspective on why this cycle keeps repeating, and especially why it keeps not working out the way it is supposed to. If you have read the previous parts of this series, you will know I do not agree with him that AI provides any significant productivity improvement to programmers or that it is a tool similar to high-level programming languages.

In that article the author discusses the issue of fixating on tools, which misunderstands what programming is really about: understanding. He also says that typing code has never been the “hard part” (or bottleneck), it is working out exactly what software is supposed to do, which is enormously complex, and becomes more complex the more tools emerge that simplify or abstract away low-level programming tasks. This is another manifestation of the Jevons Paradox: any tool that makes coding easier doesn’t shift the job of programmers down to a less cognitively demanding one, it shifts the complexity of computer programs up until the cognitive demand is back to what it originally was.

The point about fixating on tools is one that cannot be overstated. I have lost multiple job opportunities because the hiring manager believed I did not have enough years of experience in a specific language, framework or platform, despite the fact that my overall experience, both in programming in general and even in the relevant more specific domains (like frontend or mobile app development) were more than twice the job requirement (they missed a huge opportunity not hiring me). Almost every manager I have worked with believes my “skill set” is one of these things (a language like C#, Swift, etc., a framework like .NET, Ruby on Rails, etc., a platform like iOS, Windows, etc.), which is ironic because multiple such managers did not realize (due to the way I came into a job, such as through referral) my experience with the relevant tools was almost nonexistent.

It is from this misunderstanding of programming, which is analogous to viewing carpenters as having skills in “hammers” or “drills”, or novelists as having skills in word processors, or mathematicians having skills in drawing symbols, that people are now saying absurdities like that a programmer’s skills are now suddenly “obsolete”, because he will now use AI as his primary tool instead of those other things. Even if programmers shift entirely from programming with e.g. Visual Studio and C# to Cursor and prompts/skill files/etc., this is a trivial change to the job. Competently guiding an agent to produce acceptable code requires the exact same skill sets that programmers already had (or did not have), which are primarily about breaking high-level operations down into precise parts, ultimately down to algorithms, and managing the resulting very cognitively demanding complexity of all the required precise specifications. Programmers are the authors and maintainers of very elaborate, exhaustive and exact blueprints for information processing systems. Nothing has changed in this regard, even if we fully accept (which, remember, as I will get into, I do not) that AI is now the best tool available for programmers to perform this work.

He also specifically mentions that this is now the third time humanity finally figured out AI, it’s going to revolutionize everything, but first it’s going to eliminate computer programming. That happened in the mid 1960s, and then again in the mid 1980s. Well, the AI research community told everyone that’s what happened. What actually happened was that the thing people called AI that actually existed wasn’t anything like what AI researchers were promising, the false promises first hoodwinked a lot of people and then, once they realized they had been taken for a ride, they turned against not just the AI they had at the time but AI as a concept, and what followed was AI Winter: a large dry-up of public interest and funding for AI research. The author seems to suggest this time is different for AI. I don’t agree. I think the only thing different this time is the scale and sophistication of the magic trick, which only means when everyone turns on it this time (and especially after the enormous malinvestment into GPU supercomputers causes major economic damage), the winter that follows will be much more severe.

But the author of that piece does not dig into what I think is the most important part of why these promises to “eliminate coding” never worked out, which when we address, also reveals why AI is not an appropriate tool for code authorship at all, all the reasons given for why it is being based on gross misunderstandings of programming and programming tools.

The Original “Coding Is Dead”: COBOL

As stated in the article, “the story begins” with the first promise made to businesses that their businesspeople could now handle the creation and maintenance of their software directly, instead of hiring programmers to do this, thanks to a new tool created to enable businesspeople to specify software in terms they already understand. This tool was called Common Business-Oriented Language, or COBOL. This was a language based on English that could be understood and executed by computers, allowing the businesspeople to write the software specifications in familiar English terms and eliminate the need for programmers to manually translate those specifications to computer code.

Of course it did no such thing. COBOL didn’t eliminate programmers and allow business managers at banks to write and maintain the computer code for banking systems, it just created a new profession of COBOL programmers. But this should be “obvious” in hindsight. After all, COBOL is a programming language! Since when has creating new programming languages eliminated programmers (as in, the people who read, understand and write documents in programming languages)? The idea that something like COBOL would open up programming to non-programmers seems very strange. Did anyone think Java, or C for that matter, would do this? The problem, which we will discuss thoroughly later, is that people in these discussions have no coherent definition of “code”, or “programming”. This is why they don’t realize why business managers don’t want to touch COBOL with a 10 ft. pole any more than they wanted to touch assembly, or C, or any other computer code.

He goes on to say “COBOL succeeded spectacularly as a programming language”. That, I most emphatically do not agree with. “Success” here is measured only by how widely it was deployed… and even then, it really wasn’t successful. Almost no programmers ever touch COBOL today, and it has been that way for several decades. COBOL is widely used in mission critical parts of modern society, most importantly the banking system, but it is strictly quarantined in those areas, and every business that has to own such codebases has done backflips to minimize how much they have to touch them or expand them to new responsibilities. Banks usually have software systems written in Java or C# that handle all the newer stuff like their web applications and middleware, that call into the “core” COBOL system only to handle the transaction logic that they built decades ago.

The fact that this core of the banking system is still in COBOL is actually an expensive disaster. IBM has to continue manufacturing otherwise grossly obsolete mainframe computers, with old CPU architectures and instruction sets, just to allow these core codebases to continue to run without heavy, and risky, modification. Everyone is so terrified of making any modifications to this code, they don’t even want to update compilers to let it run on newer hardware. The vast majority of professional programmers today are not qualified to touch that code and banks won’t let them. This situation already became a disaster in the 90s, when people realized that code is full of a specific mistake: the Y2K problem (dates being represented as two-digit numbers that rolled over at the century). This required COBOL developers, most of whom had retired (again, most of the actively developed code for banks by this point was something like Java that just called into the COBOL core), to be brought out of retirement just to scramble to fix this problem before it started breaking the banking system.

This all begs the question of why banks didn’t just hire and train programmers in COBOL and build all of their systems, including the newer stuff, in COBOL. Marshalling calls between separate systems written in different languages is a significant architectural complexity added purely as a result of deciding to make the rest of the system separate and in a different language. Why did the industry pay for all this extra complexity, and in the process make maintenance of the COBOL core a niche speciality that requires rare and expensive (and increasingly unavailable as time goes on) talent, instead of just sticking with COBOL all the way?

The answer is precisely because COBOL is not a good programming language. The reason is obvious: it wasn’t made to be a good programming language. It is a programming language designed with the contradictory goal of not being a programming language, but instead being… something else, something that appeals to non-programmers. Programmers were explicitly not the target audience for COBOL, so it is not surprising that programmers don’t like it. Judged on the same basis as other programming languages like C or Java, COBOL is not appealing at all. It failed its promise to make business managers the programmers, and forced programmers to deal with code trying to obscure the fact it is code, which makes it harder to work on. There is a very important lesson in this: trying to replace programmers not only doesn’t work, it causes decades of expensive and difficult problems for any part of the industry that is seduced by the promise.

The Elusive “Fifth-Generation Language”

In the 80s, as programming languages were getting more advanced (object-oriented programming was starting to show up), people noticed that code written in these languages was more abstract, more declarative and less imperative, and read much more like the business specifications for software than exercises for computer science students compared to older code written in, say, C or BASIC. So naturally they imagined that one more round of advancement in programming languages would “raise the abstraction” all the way out of “programming” entirely, and again eliminate the need for a specialized “programmer” profession and instead allow the product owners, who create the specifications, to create the software directly.

The idea was that the move away from imperative and toward declarative programming would finally be “completed”, so that the text documents prescribing a software system were entire built out of constraints or rules without any spelling out of “how” a computer would perform calculations in line with those constraints or rules. The product owners are the ones who write the constraints or rules, so they could just write them directly in some kind of editor program that would generate executable code directly from those specifications.

My first professional job that involved any kind of “programming” used one of these languages: LabVIEW. I was an assistant at one of the laboratories at the physics department of my university, and they needed to add a thermostat to their lab setup. We added the necessary hardware, a thermometer and heater, to the setup, and connected them to the computer. Then I programmed a control loop that would keep the system at a specified target temperature using LabVIEW to describe the feedback loop that takes a difference in actual and desired temperature and calculates how high to set the heater. You do this by literally drawing circuits.

At the time this seemed fine. In retrospect, with 15 years of professional programming under my belt, I think it would have been much simpler to just write this program in C, or maybe Python. But I understand the point: most of the people working in the lab (students of the physics department, usually grad students) had little to no background in computer programming but occasionally needed some simple algorithms like this, but they all took multiple classes in electronic circuits (something every physicist needs to understand) so drawing circuits, and knowing what circuit to draw to implement a simple algorithm, was something they could handle.

These kinds of languages found niche applications like this. What they did not do is make any kind of impact on the software industry. The reason is basically the same as COBOL, just to a larger degree: these are tools explicitly targeting non-programmers, that may allow non-programmers to do some things they otherwise would not be able to do, but certainly did not allow non-programmers to start building advanced or complex computer software. You still need programmers for that, and if you know a programming language, it cannot be more obvious how silly it would be to try to use one of these “non-programming” tools to build software instead of just using a programming language. I mean, I shudder to imagine trying to draw a circuit that would implement even a basic calculator or todo list mobile app in LabVIEW.

The lesson here is that programming languages are by their nature general purpose, while “more abstract” specification tools achieve the higher level of abstraction as a tradeoff with less generality. What makes programming languages so… “programming language-y”, the characteristics everyone is so desperate to get rid of, is precisely their ability to express the requirements of any computer program. What non-programmers don’t like about programming languages aren’t mundane syntax features like braces or parentheses, it’s how complicated it is to spell out exactly how to do things. The only way to relieve people of that burden is to limit the scope of what they are specifying. This is basically what all productivity software is. You could write a C program that renders any word document you can think of… but C is so much more powerful than that, so this is sort of like killing a mosquito with a machine gun. The alternative is to use Microsoft Word. You can’t build an arbitrary computer program in Word, but you can render a word document by just describing the elements to render (text, images, etc.). What makes it easier (much easier in fact, I’m a professional programmer but I don’t want to write my word documents as computer programs) to create word documents is also what makes it impossible to create anything else.

The idea of a “general purpose computer program that lets you build programs” but that isn’t a programming language is “trying to have your cake and eat it too”. It is trying to achieve two contradictory goals simultaneously. In doing so you will either create another programming language (and probably not a great one, like COBOL) or you will create a tool that has a specialized use case but does not target computer software in general.

Visual Programming Languages, WordPress, etc.

The idea of a more abstracted editing tool for making software was also approached from a different angle. Software is almost always a GUI these days (and has been that way since at least the 90s, if not 80s), so a major part of building software is building the GUI. The GUI is designed by designers (graphical artists for computer software, who also work out how the user experience should work, i.e. what buttons do what, what elements to activate to navigate around, etc.). Programmers would build these GUIs in code, and wouldn’t even know what it “looks” like until they compile and run the program. Wouldn’t it be nice if you could build the graphical user interface of a program graphically? And then, since it’s designers who are really the ones building those interfaces, can we just cut the programmer out of this entirely?

This is an interesting one because as a professional programmers who’s worked mostly on frontend GUI systems, I would love it if this could actually be accomplished. I have always been frustrated by the significant overhead/waste of designers using their own software (Photoshop, or more recently something like Figma) to draw the GUI of the system I’m working on, only for me to have to take those drawings and redraw them myself in the programming tools I use (and then at the next demo get yelled at by the designer about how something is off by a pixel or has slightly the wrong color or gradient shape). I won’t talk about the ideas I have about how to do that because that’s a topic for another article. The point is: the software industry really tried to do this for a solid 20 years, it totally failed, and by now they have completely retreated.

This started in the 90s with “what you see is what you get” drag-and-drop GUI editors. NeXTSTEP, which eventually became Mac OS X, had Interface Builder (it was originally an entirely separate application from Project Builder, the code editor, before they were combined into Xcode, which strongly indicated the idea that different professionals would use each one). Microsoft had the “visual” programming languages (Visual Basic and Visual C++), whose respective identically named editing tools were eventually combined into “Visual Studio”. Java had Swing, with various vendors providing graphical editors. Web applications have always been strongly divided between code and GUI descriptions, owing to its history of emerging from simple HTML (the HTML itself is the data describing the GUI, adding code to web pages to turn them into applications required special <script> tags to be added to HTML).

These all got pushed hard in the 2000s and early 2010s, but by the mid-late 2010s, the trend had started to reverse. No one was using them according to their original intent. Designers weren’t opening up Interface Builder or Visual Studio, working on the GUI directly and saving their work back to the code repos. They didn’t want to go anywhere near those “programmer” tools or the code repos, which would have required training in version control systems. Instead, they used their own tools made just for designers (Photoshop, Figma, etc.) and delivered programmers mockups they then had to rebuild in these graphical editors. Programmers gradually got fed up with the graphical editors and started doing this directly in code, which is more expressive, and simpler because there’s no awkward boundary between data files or generated code and the code they had to work on directly anyways.

The tools eventually caught up with this in the late 2010s and early 2020s. For example on mobile, both iOS and Android pivoted to “next generation” reactive UI frameworks modeled after React (SwiftUI on iOS, Jetpack Compose on Android). A key part of this was there is no graphical editor. You always and only build the user interface in code. But you also get a live preview of that user interface in the code editor. This captures the fact the useful part of those graphical editors to programmers was just being able to see what the code produces. Editing the code graphically was just annoying, but seeing the results of code graphically is useful.

With this move, the concession was clear that designers are not going to jump into the tools that produce the artifacts that actually go into the code repo and become part of the software system. They are going to work on their own separate mockups with their own dedicated tools, then hand them off to programmers to rebuild what’s in those mockups in code, which will then be wired up to the rest of the code that makes it a “live” interface instead of a bunch of static images.

The problem, in addition to designers not wanting to use programmer tools or deal with the version control of the code repo, is that the line between “interface” and “code” is blurry and jagged. In these graphical editing tools, there was always a way to wire up an “action” like clicking on a button to a function/method in code. Who would do this, designers or programmers? Designers needed to design and explain the basics of UX, like that clicking a button should expand a menu, or navigate to another page, or trigger a transition within a view to a different layout with a specific animation. The graphical tools supported some, but not all, of this sort of stuff. Also, they directly supported some, but not all, more advanced visual building blocks and effects, like gradients, drop shadows, transparencies, templated widgets (like a mask that would be shaded differently in different instances), etc., but building those directly in the tool meant they would be rendered directly by the program. This might have poor performance, compared to baking these building blocks into an image. This was the concern of programmers, not designers, and the decision would mess up how designers edited their designs.

All of these systems were built with the idea of drawing a line between design and coding, and helping each class of professionals work exclusively on their side to minimize overhead. Other graphical editing tools were created with the idea of completely taking over the work of building an application. A canonical example is WordPress. WordPress is a tool to build web apps, which in its most basic form supports making documents, but also comes with a set of tools, that are expandable through a plugin ecosystem, to implement more sophisticated behaviors that start to get into full blown web applications. How are these plugins made? With PhP code. The idea is that programmers can build the plugins and make them available to designers/product owners, who can then just assemble them as needed into applications. You don’t need programmers to build your applications, your designers/product owners can just assemble them interactively/graphically.

This is essentially the same as “fifth generation languages” as described above, so it worked out the same way and suffers from the same problems, although I think it was a more sensible way to approach it, so the niche WordPress and similar “web site builder” tools settled into is much larger. These tools are fine for a restricted set of common web pages that don’t do anything very sophisticated or unique, and correspondingly they are used widely for such web pages, allowing them to be built by people with no programming background. But as a replacement for web application development in general, they didn’t even slightly penetrate that industry, because as soon as your needs reach the level of needing programmers, those programmers will very much want to avoid such tools and instead use the tools made specifically for web programming (JavaScript/TypeScript, frameworks like React, Vue, etc.). They won’t even want to offload the “basic” stuff to something like WordPress and handle the rest by marshalling back to a web application or custom plugins. That just makes everything harder. If your web site needs code, and once it gets past trivial requirements it will, it’s much easier to just go all in on web programming, and leave those “web site builder” tools in the drawer.

No/Low Code? What About Everything As Code?

The article talks about the No/Low Code era of the 2010s, with all sorts of specialized applications designed to try to offload certain common parts of software systems away from general purpose programming (again we see the same tension between eliminating “code” and generality), but when I read this I couldn’t help think of the exact opposite trends going on around the same time.

A major example is infrastructure as code (IaC). This got big when everything started moving to the “Cloud” with services like AWS, and the infrastructure for backends went from being a simple server or two to complex orchestrations of instances, clusters, and so on, all with their own scaling and resource consumption rules. For a while people would just use the GUI or CLI for AWS to set all of this up and modify it when needed. But this is a big headache. What if you accidentally break something and need to undo a change? What if you want to duplicate an environment in another region, but change certain parameters? What if there are layers of abstraction in how things are configured, like the instances for one web app follow the same pattern as another web app but with certain parts being different?

Ironically we see the same basic principle emerge: when configurations or systems get complicated enough, the tool best suited to express, manage and organize that complexity is code. It becomes desirable and then necessary for the entire exact specification of such a system to be described in text documents that are checked into version control, and expressed in a language fully capable of abstraction, and verified with static analysis tools that detect mistakes in the configuration at design time. So now the preferred approach is not to go in and issue a bunch of terminal commands or take a bunch of GUI actions to manage these environments, but instead write the infrastructure as code.

A similar thing happened with virtual machine configurations, which can cover all the machine dependencies needed to build, test, run or deploy an application. Instead of elaborate plain text onboarding documentation or READMEs for developers who join projects, instructing them on everything they need to download, set up and configure on their laptops to be able to work on a project, as well as similar documentation instructing DevOps on how to set up hosted environments for those same projects to run in, this can all be written as code and code-like configuration in DockerFiles and Docker Compose configurations, which are instructions for how to build a virtual machine from scratch that contains all the necessary setup.

Yet again, on the side of managing software requirements, behavior-driven development (BDD) is a technique focused on turning the specifications originating from product owners into another type of code, written in a programming language called Gherkin, and put into .feature files that are checked into the code repository and become part of the living documentation of the software system and drive the execution of automated tests verifying whether those requirements are currently satisfied. This comes up against the same friction that GUI editing tools always have: getting product owners to install programming IDEs (which is where the best support for writing and maintaining feature files is found) and participate in the development lifecycle of opening pull requests and committing changes to the code repo is like pulling teeth. They don’t want to, but the alternative they do instead is creating a graveyard of unorganized and frequently contradictory JIRA tickets and claiming that’s the “source of truth” for the requirements, written in vague natural language that is missing large details and includes a bunch of irrelevant commentary.

Gherkin also suffers from the same problem COBOL does. It is a programming language designed explicitly to not be a programming language, so it intentionally leaves out anything “programmer-y”, such as variables, types or even just loops. This makes it pretty challenging to express very complex requirements in Gherkin, and forces anyone who tries to invent their own ways of expressing those kinds of constructs. Programmers generally find Gherkin annoying because it’s not very expressive as a programming language, and they have to deal with marshalling between Gherkin and whatever programming language powers automated tests. Product owners often protest working with Gherkin or feature files specifically because it’s “too much like coding”, which many of them explicitly insist is not their job and instead the job of programmers.

So while everyone is out here shouting “coding is finally dead!”, there have been long-running movements to absorb even more of the software industry’s work into the domain of computer programming, including DevOps and even product ownership. If designers learned to code and built their GUI designs in code with modern reactive UI frameworks everything would get a lot simpler and more streamlined. As computer software continues to grow in complexity, there’s a better chance non-programmer roles like product owners and artists will be increasingly forced to become more like programmers than programmers being increasingly forced to be like product owners or artists. Sorry, we’re taking over the world even as you all keep trying to eradicate us!

Honorable Mention: The Turing Complete Programming Language Called “Excel”

A fitting final example to review of the idea that programming can be eliminated from software is good ol’ fashioned spreadsheets. If you didn’t know that Excel spreadsheets are an IDE for making general purpose software, boy do I have some news for you!

Software, generally, is dynamic, it does calculations. That’s what makes it different from just documents. Of course, spreadsheets can do calculations. There’s a whole syntax in Excel for what to put into cells to make them compute values from other cells. People use this all the time. It’s a very useful feature of computerized spreadsheets. It should come as little surprise, if you understand how computation works, that the ability to do basic computations like adding or multiplying enables pretty much any software system, no matter how complex in its requirements, to be built out of nothing but Excel spreadsheets. The only major limitation is that your GUI has to be in the form of spreadsheet cells, but as long as you can make them emit solid colors, then they’re just pixels and nothing is stopping you from building GUIs in Excel (well, except for your sanity, more on that in a moment).

Now, for spreadsheets to be able to implement literally any computer program, the formulae expressible in spreadsheets need to form a Turing complete language. Basic computation isn’t enough, you also need to be able to do loops whose bounds are themselves computed (i.e. “do something X times, where X is itself computed by the program”), which is equivalent to recursion (the ability for a computational operation to call itself). But Excel has long been able to do this, through fixed-point combinators and later LAMBDAs.

This isn’t a completely academic problem. I haven’t seen this myself, but I’ve heard stories from fellow programmers about companies that built incredibly elaborate computation systems, that would be complicated enough if they were computer programs, in Excel spreadsheets, and of course maintaining and modifying them was an absolutely awful experience. Can you write any computational system in Excel? Yes. Would you want to write any computation system in Excel? Hell no! And where’s the line? How complicated does a computational system need to get before the Excel manifestation of it will have a business manager begging to learn Java? Not very complicated at all. There’s a level of complexity where WordPress stops being convenient and starts becoming a headache compared to a TypeScript web application. Similarly, there’s a level of complexity where Excel stops being the “easy” way to do something, and it’s surely at a much lower level.

Why Does “Coding Is Dead” Always Fail?

See, the problem has never been code. To the extent it’s even meaningful to “kill” coding, you very much wouldn’t want to, unless you only want to do some basic arithmetic. If you want to build nontrivial software, you better hope you have code. And if for whatever reason you don’t, someone is quickly going to reinvent it, discovering again everything academic computer scientists and industry programmers worked out nearly a century earlier when they designed the programming languages we already have (a major problem with any kind of “everything from the past is now obsolete” movement is it begins by announcing its refusal to learn anything from the past or stand on the shoulders of giants, it is practically defined by a complete regression of progress that must then be painstakingly relearned).

If it is not obvious to you that everything I have discussed above is completely relevant to, and in fact damning for, the very concept of “AI programming”, then you don’t have a correct mental model for what “AI programming” is to begin with. It is just the latest manifestation of this ill-conceived desire to remove, or even just reduce, the “programming” part from software, while at the same time maintaining the full general purpose nature of software. This is, again, trying to “have your cake and eat it too”. Just like trying to build software by drawing circuits in LabVIEW, assemble widgets in WordPress, or write formulas in Excel spreadsheet cells, is possible and also a terrible idea, imagining AI as some kind of simplification tool that takes care of the “programming” part but lets us “work at a higher level of abstraction” (I’ll talk about this more in the next part of the series, this is a misunderstanding of what “abstraction” is) is running afoul of the same erroneous beliefs about what makes programming difficult, why it is cognitively demanding, what the real bottlenecks are, and why we do it the way we’ve been doing it for decades (using programming languages and the tools around them).

The fact that programmers are now using AI to write code can be properly put in perspective when you remember they also do things like port Doom to run in Excel, or build an NES emulator in Minecraft.

After all, what is the definition of “code”? Originally “code” meant literally the opcodes, which are a set of codes for operations in the instruction set of a CPU (“code” here means a lookup table from numbers to something else, the same way ASCII is a set of “codes” that map numbers to text characters, or health insurance companies have “codes” mapping numbers to certain categories of doctor visits or procedures). In this narrow definition, only literal machine code is “code”. It’s a stretch to even call assembly “code”, and it certainly doesn’t apply to “high level programming languages” (which includes C and BASIC). If we look at a C source file, we don’t see literal “codes”. When we add two variables, we see the “+” symbol. That’s not a “code” for addition, it is the symbol for addition. There’s no lookup mapping a number or something else to an “add” instruction, the source literally says what it’s doing. The same is true of assembly, which deliberately replaces the opcodes with abbreviations of the corresponding instruction.

When we say “computer code”, the term has been generalized to mean something else. Computer scientists meditated a lot on this. What, really, is in common among a binary executable, a C source file, a Bash script, a Python source file, and a Java source file, but distinct from a JPEG image? We consider all those except the last to be “computer code”. But we don’t consider “plain” text documents, images, or even configuration files, to be “code”. Why? What’s the distinction that captures this boundary?

We might think the answer is whether something is “executable” by a computer. Machine code literally is. Those other examples of “code” are executable indirectly because of compilers and/or interpreters. Those things not considered code are not. But this doesn’t really answer the question, because it instead begs the question of why those other things aren’t “executable”. What’s stopping us from writing an “interpreter” for plain text documents, or JPEG images? Do we just need to do that and then suddenly plain text documents and JPEG images are now “code”? Is it even possible to write such an interpreter? If it’s not, is it simply too difficult, or is it actually conceptually impossible?

What even could it mean to “execute” a JPEG, for example? What does a JPEG mean, interpreted as “instructions”? Instructions for what, exactly? Unless the pixels are codes for instructions (meaning the JPEG actually does contain computer code, just “hidden” in an image), this question has no answer. An image is an image, not an instruction, or recipe. The category of computer programs is not a subcategory of images. For plain text documents, the problem is different: some text documents in natural language are instructions, but some are not. What would it mean to “execute” a novel, or a forensic report of a crime scene? Natural language is not just imperative, and when it is declarative (which code can be too), it is not necessarily declaring something desired (which makes it implicitly imperative, or at least interpretable in that way), it is usually declaring something that just is. “The sky is blue”. How do you “execute” that!?

What about “be a Point of Sale system for bakeries”? Is that computer code? It is imperative, after all. But what does it mean to “execute” that? We might think that means do all the things a Point of Sale system for bakeries needs to do. But what are those things? Whatever they are, they are not contained in this request. The problem here is it is too vague. It’s not actually instructing anything specific or concrete. The word “specification” begins with specific. “Be a Point of Sale system for bakeries” is not specific, therefore it is not a specification, so it is not computer code. It is missing details and needs to be fleshed out before it could be. The problem here isn’t that we aren’t spelling out everything explicitly. “Make a double espresso” doesn’t explain how to do that but it is (or at least could be, maybe it’s missing details that coffee aficionados know about) a precise instruction. The word “espresso” contains in its definition (which we can look up) everything needed to know exactly what is being instructed here. The problem is that “be a Point of Sale system for bakeries” does not. The term “Point of Sale system” does not have a definition detailed enough to be an instruction, especially with the “for bakeries” qualifier. At best, we can consider this an instruction to specify what that means, and then the resulting specification would be computer code.

If we pull on this thread enough we will eventually realize that “computer code” is an exact and exhaustive specification for computer software. The reason why machine code, C source files, Bash scripts, etc. all qualify is because they all do this: they describe exactly and thoroughly what we want a computer to do. But this is also true of LabVIEW circuits, WordPress data files, and, wait for it… the prompts and markdown files that get fed into AI. If all these things are “code”, then they can’t possibly kill code! They just change code from one form to another.

And this isn’t a pedantic distinction. “Coding is dead” sounds seductive because “coding is hard”. Getting rid of it sounds like we just eliminated the biggest, hardest part of making software. “Coding is different” doesn’t have the same ring to it, does it? Coding was different when C was introduced, and then again when Java was introduced, and so on. AI programmers like to claim AI is just “the next compiler” or “the next higher abstraction” (which we’ll talk about more later), but some of them still say “coding is dead”. Well, which is it? Is AI the “end of coding” or just “the next programming language”? It can’t be both. Outside of programmers, the product owners, managers, executives, etc. who are so excited to talk about AI being “revolutionary” to programming are all firmly in the “coding is dead” camp, because that’s always what they’ve wanted: to make building software possible without needing “specialized programmers”. If AI merely makes coding different and shifts it to another programming language, their dream is dead.

And if we instead have a discussion about coding being different, we have to assess AI programming in ways no one, not the non-programmers or AI programmers themselves, seem at all willing to do, and usually don’t even realize needs to happen. If coding is now merely different, we have to ask if this difference is an improvement or a degradation. Is the code AI programmers write (accepting that prompts and markdown files are code) better or worse than the code they were writing before? Well, are prompts and markdown files more or less similar to Excel spreadsheets than industry programming languages? And to what extent is the appeal of AI prompts and markdown files precisely that they’re not written in programming languages and don’t “feel” as “code-y”?

Conclusion

“Coding is dead” fails, and will always fail, because it is an ill-formed concept. “Code” just refers to the instructions precise and thorough enough to actually specify a software system. The only way to not have code is therefore to not have software. The form that code takes is a different issue, but the sales pitch of AI programming has never been that it changes code to a different (and hopefully better) form, it is that AI eliminates it. This is the same promise that COBOL, fifth-generation languages, drag-and-drop tools, and so on, have been making for decades. It never works out because there is nothing to work out. Talking about eliminating “code” from software is indicating deep confusion about what “code”, and really what “software”, is to begin with. Thus, every time a group of people announce that they accomplished “killing code”, it becomes clear eventually that they don’t know what they’re talking about, and if they accomplished anything, it has nothing to do with what they’re describing, and therefore unintentional, and therefore almost certainly counterproductive if not outright destructive.

What I think the author of the history piece (which again I think overall is very well-written and reasoned) misses is drawing a sharp distinction between these tools that aimed to reduce or eliminate “code” and the tools that embrace code as the thing computer software is about and instead aimed to improve it and empower (rather than replace) programmers to lean more fully into it. In the former we have things like COBOL, fifth-generation languages, no/low code tools, and all three (so far) generations of AI hype. In the latter we have programming languages designed by programmers or computer scientists with the concepts programmers deal with (precision, composition, abstraction, type safety and other types of static verification, etc.) explicitly in mind: assembly, C, C++, Java, C#, JavaScript, TypeScript, and more on the academic side (and for this you have to get into PhD level math to even follow what’s going on), functional languages like Haskell or OCaml.

Going from machine code to assembly, to C, to Java, etc. is a completely different, if not opposite, progression than what something like COBOL or WordPress was, and AI now is, trying to do. These programming languages are more “complicated” (advocates of one criticize the latter ones precisely of being “too complex”) and require more programmer/computer science type expertise to use effectively on every successive generation (it is a popular misconception that e.g. Java is “simpler” than C just because it, for example, has a garbage collector, but really it shifts complexity from things like memory management to management of the high-level conceptual complexity of requirements, in the form of design patterns, for which C programmers routinely mock the Java community as examples of overengineering or complexity for complexity’s sake. Abstract factory builder strategy mediators are more, not less, complex programming concepts than the memory heap). It is a category error to conflate these two.

In the next part I will continue this analysis into the concept of programmers “delegating” the coding part of their job to some kind of assistant or tool.

Leave a Reply

Your email address will not be published. Required fields are marked *