Programming as Theory Building. Peter Naur.
A program is not just its source code. It is a shared mental construct that lives in the minds of the people that work on it. The code is merely a written representation of the program and is lossy.
In his seminal paper “Programming as Theory Building” published in 1985, Peter Naur set out to posit that a program is not its source code and cannot be reduced to it. A program is a shared mental construct (referred to as “theory of the program” by Naur) which lives in the minds of people who work on it. The code of a program is just a written representation of this theory, and is lossy. It’s lossy in the sense that theory of the program cannot be rebuild completely only from the code, documentation, and other artefacts, without the presence of developers who worked on the program. These artefacts are necessary but not sufficient. When you lose all the developers who had the theory, it is “the death of the program”. Naturally, for a new team member to gain this theory s/he has to work closely alongside the existing developers.
Naur’s primary motivation for proposing the building of shared mental construct is to give deeper insight into how it influences the modifications in any software — “A prominent reason for proposing the Theory Building View of programming is the desire to establish an insight into programming suitable for supporting a sound understanding of program modifications.”
Naur’s idea of “theory of a program” is influenced by idea of “theory building” and “theorising” from Ryle’s work in his book The Concept of Mind. I’m quite fascinated by the concepts of “theory”, “theory-building”, and “theorising”. I had read the paper earlier, but rereading it after having read “The Concept of Mind” presented it in a different light for me. Naturally, I’ll concentrate more on these meta concepts in this article. To have a better appreciation of Naur’s thoughts in his paper, I’ll also present some parts from Ryle’s book pertaining to the concepts of “theory” and “theorising” (or “theory building”).
Theory and Theory-Building
An intelligent act is different from an unintelligent one. While a task can be done well by just adhering to certain criteria or following a set of rules, like looking both ways before crossing a street, it doesn’t necessarily qualify as an intelligent one. One could precisely follow the intricate recipes of Reynold Poernomo and succeed in recreating his signature desserts, but that alone does not qualify as intelligent cooking.

Ryle analysed that an intelligent performance is more than just being able to do an activity well according to some criteria. A person able to perform an act intelligently would not only be able to apply the criteria, but also be able to identify and rectify errors, iterate and enhance accomplishments, gain insights from his own and others' experiences, and more.
“The well-regulated clock keeps good time and the well-drilled circus seal performs its tricks flawlessly, yet we do not call them ‘intelligent’. We reserve this title for the persons responsible for their performances. To be intelligent is not merely to satisfy criteria, but to apply them; to regulate one’s actions and not merely to be well-regulated. A person’s performance is described as careful or skilful, if in his operations he is ready to detect and correct lapses, to repeat and improve upon successes, to profit from the examples of others and so forth. He applies criteria in performing critically, that is, in trying to get things right.”
An intelligent behaviour transcends following rules of some kind. For if there are rules on how to perform an activity intelligently, there will have to be a set of rules on how to effectively follow the rules, and then another set of rules on how to follow the following of rules and so on. An infinite regression!
“Knowing That” is not the same as “Knowing How”
“What characterises intellectual activity, over and beyond activity that is merely intelligent, is the person’s building and having a theory, where theory is understood as the knowledge a person must have in order not only to do certain things intelligently but also to explain them, to answer queries about them, to argue about them, and so forth. A person who has a theory is prepared to enter into such activities; while building the theory the person is trying to get it.”
“Knowing that” is the knowledge of or knowing a theory. “Knowing how” is the ability to be able to apply the theory within the given context. “Knowing that” will be knowing Newton’s laws of motion, to be able to state them, to be able to write their equations fluently and to be able to derive them even. “Knowing how” or “having the theory” of Newton’s laws would be to have the ability to identify which category of reality belong to classical mechanics so as to be able to apply the laws of motion effectively. “A person having Newton’s theory of mechanics must thus understand how it applies to the motions of pendulums and the planets, and must be able to recognise similar phenomena in the world, so as to be able to employ the mathematically expressed rules of the theory properly.”
“Newton’s theories were used when correct predictions and retrodictions were made on the basis of them, when machines were designed in accordance with them, when the hope of building perpetual-motion machines was given up, when some other theories were abandoned, or else were codified with his, when books were produced and lectures delivered enabling students to grasp the whole or parts of his theories and, lastly, when some or all of his theory-building techniques were learned from his example and successfully applied in new investigations. To be a Newtonian was not just to say what Newton had said, but also to say and do what Newton would have said and done. ”
Frequently, the mastery of "knowing how" relies upon a foundation of "knowing that." Achieving proficiency in TDD, for instance, necessitates grasping the sequential red, green, and refactor steps. Yet, a mere grasp of these stages might prove insufficient, as true effectiveness in TDD requires an intellectual capacity to comprehend contextual criteria and significance at a higher level than others. It is one thing to be able to write tests and another to reason that we should not test private methods. It is one thing to learn how to mock and another to know when not to and use stubs instead. This transition from factual knowledge ("knowing that") to practical mastery ("knowing how") embodies the process of building a theory for oneself. Once one has his theory solidified, he attains a deeper contextual understanding, enabling him to apply the theory with discernment.
The Theory To Be Built By The Programmer
In terms of Ryle’s notion of theory, the developer has to build a theory about how certain aspects and functions of the real world are to be handled by the program that has to be written. Programming as a whole encompasses many activities, but not limited to, starting with understanding of the real world problem that the program is intended to map and solve, designing, implementation, deployment, maintenance and enhancement of the software.
Programming then, has to be about knowledge that is beyond just knowing how to write idiomatic code or knowing about different patterns of asynchronous communication in a distributed system. It must have the knowledge about the real-world use case, and how to map the business rules effectively in the code. It has to do with reasoning about how to design the system to be able to incorporate future modifications as they come, and more importantly also to be able to rationalise when a future extensibility is wishful thinking.
According to Naur, the knowledge possessed by the programmer by virtue of his/her having the theory of the program transcends any artefacts like the source code, documentation, diagrams etc. in at least the following three areas:
The programmer having the theory of the program can explain how the solution relates to the affairs of the world that it helps to handle. By far the largest part of the world aspects and activities will of course lie outside the scope of the program text, being irrelevant in the context. However, the decision that a part of the world is relevant can only be made by someone who understands the whole world. This understanding must be contributed by the programmer.
The programmer having the theory can explain decisions like why a certain approach was taken over the other, why a certain class or set of classes were designed in a way and not the other way, why synchronous communication was preferred over asynchronous and much more.
The programmer having the theory of the program is able to respond constructively to any demand for a modification of the program so as to support the affairs of the world in a new manner. Designing how a modification is best incorporated into an established program depends on the perception of the similarity of the new demand with the operational facilities already built into the program. The kind of similarity that has to be perceived is one between aspects of the world. It only makes sense to the agent who has knowledge of the world, that is to the programmer, and cannot be reduced to any limited set of criteria or rules, for reasons similar to the ones given above why the justification of the program cannot be thus reduced.
What Theory Is Not, Theorising Is
To get a real appreciation of why the theory of the program, held by the developers, has a primacy over other artefacts, we need to understand how we generally build our theories (or how we theorise) and then later describe our theories through some written or verbal discourse.
The transition from theorising to putting our theories in didactic fashion is a transition from non-linear thinking to a linear output, and is lossy. When we are theorising, we’re going through the process of assuming, hypothesising, criticising, conjecturing, proposing. This is mostly a non-linear process. When we later intend to explain our theories through verbal or written mediums we tend to linearise this vision. Imagine the transition between when you are brainstorming on a white board or making a mind-map — a non-linear representation, and then later when you summarise and put forth the outcome in some sort of documentation — a linear representation. This transition is bound to be lossy. When we whiteboard a systems design, we present our worldview of the problem statement, we put forth our knowledge, run through different scenarios and challenge each other's hypothesis. We can do our very best to capture these transitions, but it can never capture the theorising process in entirety.
Karl Weick argues that theories are a continuum and not a dichotomy. A software has very good reasons to keep undergoing changes. As a result, our worldview, understanding, and theory of it is forever changing too. Documentation only works up to a point and generally lags behind, if not missing completely, in capturing this changing worldview.
Documentations usually are after the fact; they are written after the developers have already built the theories in their minds. In this respect documentation serves as a mnemonic for what you already know, not as a tool for learning as Baldur Bjarnason puts it.
Program Life, Death, and Revival
Naur presents an interesting idea about the lifecycle of a program. Since theory of a program is built and held in the minds of the programmers and cannot be reduced to or expressed conceivably through other materials, the lifecycle of the program is dependent on the team’s changes and churn.
“The death of a program happens when the programmer team possessing its theory is dissolved.” The program may continue to serve its purpose long after the team is dissolved, the actual death of the program only becomes evident when there are changes to be made or the program needs to be extended. The new team, devoid of original theory, might still be able to make modifications but these modifications are bound to be divergent from the original theory, and the resultant modified program different from how the developers having the original theory would have done the changes. (** coughs 𝕏)
Naturally, the program’s life gets extended when new developers come in and get to build their theory of the program by working closely with the developers already having this theory. It is always insufficient for new developers to get onboarded efficiently through just reading documentation and getting familiarised with the source code. It is for this reason that onboarding of a new developer should be a team activity.
Revival of the program is to rebuild the theory of it by the new developer team. Naur suggests that since the original theory cannot be reconstructed through just the source code and documentation, it is better to rewrite the code. — “In preference to program revival, the Theory Building View suggests, the existing program text should be discarded and the new–formed programmer team should be given the opportunity to solve the given problem afresh. Such a procedure is more likely to produce a viable program than program revival, and at no higher, and possibly lower, cost.” This is one idea that I found myself heavily disagreeing with. Rewrite is always a bad idea in my opinion and should be avoided at any cost.
Closing Thoughts
In revisiting the paper after having read Ryle’s book, I had different takes from when I read the paper for the first time. In day to day of modern software development, we take pride in writing clean and idiomatic code, we write our documentation elaborately, we create story maps to layout the real world problem that the program is supposed to handle, we annotate our system design architecture quite well, we often record our design decisions in ADRs, we write tests to ascertain the scenarios our code is supposed to handle, and much more. All these artefacts are secondary to the shared mental construct of the team that is working on the software. They are necessary but not sufficient.
Although I still find myself disagreeing with the idea of a rewrite. Maybe I’ve not experienced the “death of program” as Naur mentions it. Maybe if you have, I’d love to know your thoughts and context in the comments below.