 An essay about the philosophy of computer programming? I knew that I was going to have to cover this on thunk, either now or later. It can be hard to put a start date on programming. The earliest binary code successfully stored and executed in an electronic computer was a factoring algorithm that ran on the Manchester baby in 1948. But electronic computers like Colossus were running hardwired programs by 1943. A hundred years before that, Ada Lovelace published an algorithm to calculate Bernoulli numbers intended to run on Charles Babbage's yet unbuilt mechanical computer, the analytical engine. And people have verified that it would have worked if she got to implement it. So maybe that's the first computer program. But why stop there? The word algorithm itself is a Latinization of the name Mohamed ibn Musa al-Khorizmi, a Persian mathematician from around 820 who published books detailing procedures for adding and subtracting Indian numerals on a dustboard, which is sort of a reverse chalkboard covered in sand, that is a silicon-based computation device. We can draw all sorts of arbitrary lines separating what does or doesn't count as actual programming, but there's a long historical tradition of humans creating rigorously defined stepwise algorithms to get from a set of starting conditions to a desired end state. Whether it's a Python script that calculates pi to 10,000 places, an ancient Egyptian multiplication method, or a recipe for cooking a tasty mammoth steak, humans are great at creating and following programs. And just like modern software, there's always been a lot that can go wrong with them besides it doesn't work. Even when it successfully produces the desired results, a program can still be inefficient, opaque, hard to adapt when circumstances change, fragile. If you've ever found yourself frustrated at some maddeningly Byzantine return policy or puzzled at a vaguely worded ballot measure, you're experiencing echoes of the pain computer programmers feel when they find code that technically works, but still sucks. We've talked about some of the things that can make code good or bad, whether it's literal code or programming in the broader sense of the word, but we haven't really asked what programming is exactly. What it is that programmers, flowchart makers, and legislators are trying to do. People who aren't familiar with the various ways functional code can suck sometimes treat it as a commodity, something you'd buy in bulk if you could, imagining that a coder who can produce 100 lines of operational code in a day is twice as productive as one who only writes 50 lines. They might understand the importance of planning and design, but at the end of the day, the more working code you can produce, the better, right? Well, if you ask Peter Nauer, one of the original computer scientists who kicked off this whole digital thing you and I are doing right now, functional code is an important part of what programmers make, but only part of it. His influential 1985 essay, Programming as Theory Building, lays out an interesting account of what good coders are really doing when they write code, and although that process certainly involves typing symbols that cause the computer to behave in certain ways. Nauer thinks the principal product of good programming isn't digital, it's mental. Let's imagine a hypothetical example program. Don't worry, I'm not going to subject you to any of my hideous actual code, we're just going to talk about how the program works, generally speaking. We're trying to make some software that will monitor the Thunk YouTube channel and nag me if I'm dragging my feet on uploading a new episode. An obvious solution that we might hack together in a couple hours is a dead man switch. If it monitors the Thunk YouTube channel for activity, then slowly counts down two weeks worth of time, resetting the clock if a new video gets posted. If the clock ever reaches zero, the program pushes a nagging notification to my phone. That'll work, right? But it could be better. I don't always upload videos at the same time of day. It seems a little unfair to buzz my phone at 3am because it's been exactly 336 hours since my last 3am upload, it's not like I'm going to get any work done in the middle of the night anyway. So we revise our dead man switch to be a little more sophisticated, rounding the time to the nearest day. It'll count down two weeks from the day of the last upload, then wait patiently for 9am when I'm up and have had my coffee before guilting me for not getting the latest episode done on schedule. But if you think about it, I sometimes upload little updates or announcement videos, stuff that shouldn't really count towards a timer reset. The algorithm needs to be able to distinguish proper episodes from other types of activity. Thankfully, I follow a pretty rigorous naming convention, so we can have it parse the title of any uploaded video and look for an episode number, then use that information to evaluate whether the clock is still ticking or whether I'm good for another two weeks. Now, if you compare this most recent program to the original thing we started with, you'll find that it's more sophisticated, sure. But it's also a much better description of the problem we're actually trying to solve. We've moved from a program that buzzes me every 336 hours unless the thunk channel posts any arbitrary video, to a program that checks to see if a full-length thunk episode is at least a day behind schedule, and if I haven't gotten around to uploading anything, nudges me when I'm ready in the morning to work on finishing it. Strangely enough, the updated program's coherence with the real situation it's built to manage gives it many of the qualities we recognize as desirable elements of software. It won't break if I upload a bunch of mini-update videos or a new series. It's easy to modify if we wanted to change something obvious about how it works, like maybe adding more reminders as the video gets later, or giving me some slack on holidays. If we picked variable names in a sensible way, it's also probably much easier for someone to pick up and understand what's going on. Looking at the code, they'll see stuff like Josh Awake Time and isThunkEpisodeEqualsTrue that give important clues as to what the program is intended to do without necessarily needing documentation. For now, this is an example of the essential activity of programming. Theory building. Our programmer isn't just punching symbols into a text editor. They're constructing and clarifying a picture of the world and the program's place in it. When we started, there was only a vague notion of what we needed to do and what stuff was important to do it, but as we progressed, that evolved into a detailed model of Josh nagging. Identifying the essential stuff that needs to be accounted for and categorizing the various elements and principles that should ultimately determine how a Josh nag ought to work. A more controversial claim might be that only part of the model lives in the program, an incomplete representation of the theory that lives in the programmer's mind, which unfortunately can't be reduced to the symbols and structure of the code. Nowhere's definition of theory comes from philosopher Gilbert Ryle, who asserts that a theory is the thing that allows people to give reasons for intelligent behavior. A robot vacuum cleaner might be able to intelligently vacuum every square centimeter of floor in your apartment by performing the same motions over and over again. But if you ask it to explain how it does that or why that pattern works, you're probably not going to get a great answer. If you ask the engineer who designed it on the other hand, you'll probably get an earful of theory, explanations, justifications, reasons that this algorithm or that pattern will reliably cover most floor plans. This theory of vacuum pathbinding is wholly dependent on a sort of deep understanding or insight, a recognition of the sorts of situations where it applies and where it doesn't. The engineer might recognize that the clever floor vacuuming pattern won't work in rooms with fewer than four sides or rooms with weirdly curved floors. These limits are probably obvious to them because their mind contains the theory of the vacuuming pattern, what makes it tick, and where it does and doesn't work. But we could never codify that sort of deep understanding in the vacuum itself. Is behaviorist intelligent? Sure, but even with the most sophisticated sensors and programming, it can't understand the theory. For Nowhere, the same is true of computer programs or any programs. A coder can easily explain why their code is written a certain way, how it's intended to mirror the world and how it can be modified or adapted to new situations, because all that time they've been sitting in front of their keyboard not typing. They've been constructing a theory of the world, the program, and its operation inside their heads. And only is the code incapable of capturing the entirety of that vision. It's not even a thing that can be dictated to other programmers. They have to build their own models. The deep intuitive understanding of the situation and how the program works can be gestured at, but never given away. You can explain how to ride a bike to someone, but the knowledge is really in the doing. If Nowhere's notion is accurate, it partially explains why handing a project from one coder to the next willy-nilly often results in bloated fragile spaghetti code. Each coder develops their own unique representation of the world and the program's operation. And those representations could all make perfect sense on their own, but be totally incompatible with each other. Programmers might agree on the overall architecture or design of the code and still find themselves bewildered by their peers' decisions, because they don't share the same theory. It also explains just how much is lost when a project loses a coder, or goes long enough that the coders who worked on it forget some part of their theory, even with the most meticulous, all-encompassing documentation of their work without the actual person and their model, you're always gonna be relying on the remaining coders to rebuild and piece things back together. Nowhere's essay has prompted many organizations that rely on good programming to spend time developing metaphors for their programs and what they're intended to do to facilitate the development of similar theories by everyone who's working on the project. It also has interesting implications for the non-computer-based programming the rest of us do. It emphasizes the distinction between intelligence and insight, how it's possible to get decent results by following a clever algorithm, but impossible to just absorb the theory necessary to create it, at least not without taking the time to build the theory yourself. Think about cooking an unfamiliar recipe for the first time. Even a really stellar cookbook that explains each step in detail is less valuable than cooking it a couple of times and scribbling notes in the margins, figuring it out in a way that would allow you to make substitutions, do things out of order for convenience, or adapt it for different purposes. It's not really code, but it is programming and really getting it still requires a bit of theory building or maybe a bite of theory building. Does Nowhere's theory of programming as theory building make sense to you? What do you think of his assertion that theory can never be transferred, only built in parallel? Please, leave a comment below and let me know what you think. Quick aside, this is a full-sized Styrofoam cup that has journeyed to the bottom of the Antarctic Ocean, courtesy of my sister, who is recently on an Antarctic research expedition, because that's what she does. Yup, so this is just gonna go right up here, I think, like something like right there. Precarious, I like it. Again, thank you very much for watching. Don't forget to follow us, subscribe, like, share, and don't stop thunking.