Skip to main content

In defense of understanding the theory of the program

Posted on August 8, 2026

This post is a critique on some Programming as Theory Building related points in Sean Goedecke’s post In defense of not understanding your codebase. I was sent a link to it by Valeri Karpov, who wanted to hear my thoughts on it.

Goedecke’s post was an interesting and thought provoking read. What he writes is not wrong per-se, but I think the perspective in his post to what Peter Naur writes about theory building is flawed in some ways. Specifically, there are two points I don’t agree with:

  1. Goedecke suggests that Naur is wrong when he says that a theory of a program cannot be recovered
  2. He also suggests that theory building is something you have to sometimes entirely skip

While I think Goedecke makes good points about issues in large-scale software development in general, the way he connects these to Naur’s theory building seems like a type of a misunderstanding. I’ll attempt to show how in the rest of this post, by arguing that recovering the theory is a more philosophical concern than usually understood, and that theory building is not only a source-code level issue, but instead involves many higher level software development practices as well, and as such, cannot be skipped if you wish to deliver software.

This post discusses points around Peter Naur’s “Programming as Theory Building”. If you’re unfamiliar with it, I wrote about it here before: You should read Programming as Theory Building. This post will be easier to follow if you have read Naur’s original text.

Recovering a theory is a philosophical concern

Let’s first talk about the idea of recovering the theory of a program. Goedecke writes:

[Naur] says that the theory should not be reconstructed from the code. According to Naur, you’re better off scrapping the program entirely and having a new team rebuild it from scratch, building up a new theory in the process:

reestablishing the theory of a program merely from the documentation, is strictly impossible … [therefore] the existing program text should be discarded and the new-formed programmer team should be given the opportunity to solve the given problem afresh

Anyone who’s been an effective software engineer at a large company knows that Naur is dead wrong about this. There are at least two reasons.

The two reasons he offers are as follows: It’s unrealistic to rebuild a very large-scale system from scratch, and that abandoned systems get revived all the time (revived - that is, an unmaintained project gets new maintainers). As statements about software development, both are absolutely true. But in context of programming as theory building, I believe they are examples of a common misunderstanding, or perhaps a difference of perspective.

It is true that you can take a codebase which you’ve never worked on, and figure it out. In practice, you can say you have built a mental model of how the program works. But this doesn’t mean you’ve recovered the theory of the program. I believe Naur’s perspective on this was more philosophical: It is actually impossible to recover the original theory from the source code, or from any other byproduct that has been derived from the theory, because the full theory cannot be represented.

I previously wrote about my learnings from reading The Concept of Mind, which is one of the books Naur refers to in his text. In this book, Gilbert Ryle explains theory building, with one important point about practical knowledge which I think applies when we talk about recovering a theory. Ryle explains that practical knowledge cannot be distilled down into sets of rules. This means recovering the theory from source code (or other byproduct) becomes impossible, because there can be no representation of the thought processes which went into writing it. These thought processes are what distinguish understanding a program from simply copypasting code around, and as such, are important results of having a theory of a program.

I believe this is what Naur meant when he wrote that you cannot recover the theory: It isn’t possible to learn these original thought processes and what led to them from purely reading the code. He did not mean that it’s impossible to learn a codebase you never worked on before.

The second part of what Naur says about this, that it would be better to rewrite the program from scratch, I think we can attribute to a question of quality. I don’t think anyone can argue that the quality of the program would not be improved if it was written from scratch, and I think this is the intended perspective of Naur’s claim as well, as he writes:

For a program to retain its quality it is mandatory that each modification is firmly grounded in the theory of it.

[…]

The new programmer is likely to feel torn between loyalty to the existing program text, with whatever obscurities and weaknesses it may contain, and the new theory that he or she has to build up, and which, for better or worse, most likely will differ from the original theory behind the program text.

That is, if you’re “recovering” a program, its source code will inevitably contain hacks, and the way it represents its domain could be inaccurate. So you’re either building a theory which takes these flaws into account, or you could build a new better one from scratch.

Of course, it is often not practical to do a full rewrite, as Goedecke rightly points out. This doesn’t change the validity of what Naur says, but his view does seem extremely idealistic in context of today’s large scale software. It might be that we should be applying Naur’s principles on a smaller scale, perhaps on a component, module or microservice level. If we consider these smaller scale artifacts as programs with theories, I think Naur’s ideas about rewriting could work a lot better. It’s possible Naur included larger functions as part of what a “program” was in this context, given they are sometimes called “subprograms”, although it seems the term has fallen out of use.

Theory Building is not only a source code level activity

The second point Goedecke makes is that theory building is something you may have to forgo because other things may take priority over it:

Like most things in software, “maintaining a theory of the codebase” is one value among many. Sometimes it’s the most important value and you sacrifice other values for it; other times you trade it off for speed, or legal compliance, or for political reasons.

I think the flaw in this statement is that it would appear Goedecke sees theory building as a source code level activity only, and even then, he excludes some code-related aspects from the theory for some reason. For example, he suggests implementation of accessibility or data protection features would make it harder to maintain the theory of the program. I’m not entirely sure why. Programming accessibility features seems like a fundamental part of the theory of the program - “this program takes the following accessibility concerns into account” feels like a very important aspect that guides how work on the program must proceed, and must be a part of the theory the programmer understands in order to actually do the work.

Other examples Goedecke mentions are upgrading software versions and adding new dependencies. Theory Building when it comes to programming, like Naur describes it, is not only about the source code. It’s not the theory of the codebase, but the theory of the program. Which software versions it requires and which dependencies it has are, like accessibility, important considerations the programmer must understand to be able to work on the program.

Goedecke also writes:

However, at work you are paid to do a job. In other words, they pay you money to adopt their set of engineering values. It’s hopefully well-understood that however much you might personally care about performance, sometimes you have to write slow code at your job (for instance, to get a project done on time, or to accommodate some awkward requirement). Maintaining a theory of the codebase is the same kind of thing.

I think this again shows that Goedecke’s perspective is more on the source code level. If we look at it from there, his comments make sense, but I don’t think this is an accurate view of Naur’s theory building. Real-life considerations, like having to take a shortcut and writing some less than ideal code to quickly deliver a feature, are parts of the theory just the same as anything else is. Hacky code is something the programmer knows exists, and knows how to take it into account when working on the program.

Theory building in my opinion encompasses much more than just these types of source code level activities. That chat you had with your coworker about the feature you’re implementing? Yep, theory building. That time you were thinking about your microservices architecture during lunch? Yep, theory building. You cannot build a program successfully unless you understand these higher level considerations as well, so they would seem parts of theory building, and looking at only writing code doesn’t give you the full picture.

In closing

It seems Goedecke’s main point is that it’s okay, and perhaps occasionally necessary, to not fully understand a particular codebase. I agree with this, as especially in large scale systems you will have a varying level of understanding of the different parts that make up the whole. But the way he connects his points to Naur’s theory building, and uses it to justify the perspective, is in my opinion flawed, as hopefully my explanations here have shown.

Much of what Goedecke writes touches on parts of Naur’s theory building that I’ve been thinking about. I’ve been working on collecting my full thoughts on some parts of it into a post in the future, and some of what I wrote about here includes things I still want to expand upon - so hopefully this made sense, even though some of the thoughts might’ve been slightly incomplete at this stage.

There is one thing I’m not quite sure of my position on regarding what Goedecke writes: He states that in sufficiently large systems, everyone has an incorrect theory of the program. This is a very good point, because holding massive systems in your head seems impossible, and it makes me wonder about how the theory of a program scales. It also makes me wonder is the term “incorrect theory” is accurate - if your theory lacks detail, is it incorrect, or is it incomplete? Or is it a theory just the same, but a “high level theory” compared to a “low level theory”? This is something that I found interesting but I don’t have anything to add to it at this time.

One final interesting thing with regards to theory building Goedecke mentions is he quotes Naur in the footnotes:

Naur says: “Lest this consequence may seem unreasonable, it may be noted that the need for revival of an entirely dead program probably will rarely arise, since it is hardly conceivable that the revival would be assigned to new programmers without at least some knowledge of the theory had by the original team.”. If only!

I think this is another good example of how Naur’s perspective is not expressed as clearly as it could be. I’ve worked in plenty of codebases that I never saw before, but I still think Naur’s claim above is true. The key reason is how Naur says “at least some knowledge of the theory had by the original team” - For example, if I look at a project on GitHub that I’ve never seen before, I already have some knowledge about its theory. If we say for sake of this example that the project is a web app, well, I know a lot about web apps, so that gives me a fairly solid fundamental theory of how the program operates. As a programmer, you will almost always have at least an inkling of an understanding of the program, and its theory.

Comments or questions?

If you have any comments or questions about this post, feel free to email me to jani@codeutopia.net, or use any of the other methods on the contact page.