The Craftsman Coder
A new essay by Jon Christensen asks if software developers are artists, or rather cogs in corporate machines. His conclusion is that AI is driving them toward the latter.
For the better part of two decades, I've been a card-carrying member of the code-as-craft cult, which espouses the belief that deeply considered, finely honed code can create better products.
But a blinding light on the horizon of technology has made me question everything I once believed. The meteoric rise of Large Language Models (LLMs) has cast a shadow over the concept of code as craft, threatening to eclipse it entirely.
The idea that code is akin to craft is not new. In his seminal 2004 essay How to Make Wealth, Paul Graham wrote:
The people most likely to grasp that wealth can be created are the ones who are good at making things, the craftsmen. Their hand-made objects become store-bought ones. But with the rise of industrialization there are fewer and fewer craftsmen. One of the biggest remaining groups is computer programmers.
(Emphasis added.)
He continues:
A programmer can sit down in front of a computer and create wealth. A good piece of software is, in itself, a valuable thing. There is no manufacturing to confuse the issue. Those characters you type are a complete, finished product.
Graham’s ideas have even earlier roots.
Starting in the mid-1970s programmers began pushing back against the idea that programming was a second-class activity compared with the work of the hardware engineers who designed computers or the mathematicians who historically wrote the algorithms implemented by early coders.
In his 1974 essay “Computer Programming as an Art” [pdf] Donald Knuth argued that programming was an “art” in the ancient Greek sense of a skill or craft.
These ideas took hold and grew, and coding-as-craft reached a kind of apotheosis in the late-90s and 2000s when programmers were scarce and tech was taking over the world.
But now?
Christensen writes that there’s a divide between “stalwarts of craftsmanship” who view LLMs as a “potential threat to the stability and reliability of their software because they sacrifice the careful planning of well-crafted code” and mostly young AI enthusiasts who “believe that the automation of low-level tasks will free up developers to be more creative and focus on the big picture”.
Brief History of Abstraction
Let’s take a detour into the history of coding.
The history of programming languages is mostly a history of increasing abstraction and a concomitant evolution towards natural language.
The first programming languages were binary machine codes. A program was a sequence of bits comprehensible only to someone intimately familiar with the machine hardware. A programmer dealt with specific memory addresses and operation codes.
In the early 1950's, assembly languages introduced an important tool lo assist the
programmer: naming. A programmer used mnemonic operation codes rather than the binary encoding of the operation; he assigned a name to a jump location or area of data storage, using the name instead of the memory address throughout the program. Naming provided valuable bookkeeping assistance as well as a means for the programmer to express his intentions by the mnemonic choice of names.
The late 1950’s and early 1960's saw an important step in the evolution of programming languages: abstraction away from the machine. Programming languages provided a virtual machine more amenable than the bare hardware of the real machine to the problem at hand.1
This evolution from machine code to low-level assembly languages to progressively higher level languages allowed for greater program complexity, code portability, and language specialization. (There are at least 20 different categories – categories! – of programming languages, each with many individual languages.2)
The move from arcane to accessible also gave rise to a shift in attitudes toward coding: from a menial task to an intellectually demanding creative pursuit. Higher level languages allowed – demanded, even – more critical thinking, problem solving, and creativity.
More abstract programming languages also yielded more human-readable code, a trend easily illustrated with a basic ‘Hello World’ program in a few representative languages.
Hello world in x86 assembly language3
; hello-DOS.asm - single-segment, 16-bit "hello world" program
;
; assemble with "nasm -f bin -o hi.com hello-DOS.asm"
org 0x100 ; .com files always start 256 bytes into the segment
; int 21h is going to want...
mov dx, msg ; the address of or message in dx
mov ah, 9 ; ah=9 - "print string" sub-function
int 0x21 ; call dos services
mov ah, 0x4c ; "terminate program" sub-function
int 0x21 ; call dos services
msg db 'Hello, World!', 0x0d, 0x0a, '$' ; $-terminated message
Hello world in C4
#include <stdio.h>
int main() {
printf("Hello World");
return 0;
}
Hello world in Python
print("Hello World")
What effect did all this abstraction and human readability have?
Higher level languages generally make code easier to write and easier to read. Easier to write means greater productivity. Easier to read means greater portability (of code) and greater participation (in the programming profession), and probably greater productivity, too.
High-level languages also usually make software more wasteful in terms of resources used to produce a given outcome, more bloated, and more prone to error. That’s generally a worthwhile tradeoff; Moore’s law has outpaced software inefficiency and code bloat for decades now, and the market seems to value the speed of innovation over reliability.5
Overall, then, high-level languages with a high degree of abstraction and a more human-readable syntax have yielded the following:
Elevated status of programmers (code-as-craft)
More productive programmers
More programmers
More innovation
Less efficiency
Less reliability
Prompting as Programming
The LLM prompt window basically abstracts away the entire programming language syntax, replacing it with a new syntax that is closer still to natural language.
Of course, the more precise you want your LLM output to be (whether the output is code or something else), the less natural your language will be. Prompt writing is still something of a dark art without well established best practices.
But it’s hard to miss what LLM prompts are in the evolutionary context of programming: a more abstract, more human-readable language.
And if that’s true, it’s hard to see why those outcomes listed above won’t continue with LLM-based programming.
Lorotta Rose Guarino. “The Evolution of Abstraction in Programming Languages” (Carnegie-Mellon University, 22 May 19780. 2.
K. R. Chowdhary. “On the Evolution of Programming Languages” (arXiv, June 27, 2020). https://doi.org/10.48550/arXiv.2007.02699.
For mission critical applications, like NASA embedded systems, a different set of coding practices can keep high-level languages efficient, compact, and reliable [PDF & backup].