One of the books Peter Naur cites in his Programming as Theory Building essay is Thomas S. Kuhn’s “The Structure of Scientific Revolutions”. This book seems to be regarded as an important entry under the topic of history of science, but what does this have to do with programming?
Kuhn’s book sounded interesting so I read it to find out, and in this post I’ll make an attempt at applying what the book is about into programming, and hopefully we can also find some value from doing so.
Basic ideas from Structure of Scientific Revolutions
The Structure of Scientific Revolutions tries to describe what science really is. Kuhn suggests that how we typically see science, and how we learn about science, misleads us into thinking that science, and scientific progress in particular, functions in a certain way, when it in fact works very differently.
We typically think that science is a linear and cumulative process, where one discovery leads to the next, which leads to another, and so on. Previous work builds directly on top of what was learned before. Kuhn challenges this idea, suggesting that it’s not so straightforward. Instead, he says that typically scientists aren’t even looking for any novel discoveries, and revolutionary discoveries often cause research to be discarded, because it’s no longer relevant. As a result, while scientific ideas might build on previous ones, scientific progress itself is not as cumulative or linear as one might think.
Phlogiston theory is an example of this that particularly caught my attention because of its funny name. “Phlogiston” sounds like a made up scifi/fantasy term, but it’s actually an older theory relating to oxidation, predating the discovery of oxygen. The theory suggested a substance, called phlogiston, was released when something was burned, and this theory was considered sound for nearly a hundred years. After oxygen was discovered, much of what phlogiston theory was about had to be discarded because it made no sense in context of the new findings.
Applying Kuhn’s ideas to programming
I think the parts of Kuhn’s ideas that we can apply to programming are Scientific Paradigms and Normal Science. These are concepts he introduces in the book to explain how scientific progress typically works.
A scientific paradigm is a particular area or field of science, and the knowledge related to it. All the collected research and background information that you would have when working in a particular field of science, the typical research methodology, literature, etc. The paradigm is important in letting scientists pursue deeper knowledge in their particular field, because it defines the fundamental knowledge, upon which scientists can do further work without having to reinvent everything from scratch.
Normal Science is the typical mode of operation for scientists working within a particular paradigm. I mentioned earlier that Kuhn suggested scientists aren’t looking for novel discoveries, and the definition of Normal Science explains why. Most scientific work is done to further the knowledge within a particular paradigm. This means there’s a certain set of expectations, rules and methods that are being used. These constrain the work, and limit what the typical scientist does. If we use Phlogiston theory as an example, it was the dominant paradigm at the time, and typically a scientist working within this paradigm would not have been looking for something completely different (such as oxygen).
The book discusses both of these in length, including some later critique on the ideas, but these summaries should be sufficient to talk about how these could be applied into programming and software development.
Programming Paradigm
You might’ve heard of the term Programming Paradigm in reference to things like Object-Oriented Programming and Functional Programming. This term has its origins in Kuhn’s text - Robert Floyd introduced the term Programming Paradigm in 1978, inspired by Kuhn’s definition of Scientific Paradigm.
However, it seems Programming Paradigm is used in a different way than Kuhn uses Scientific Paradigm. Kuhn uses paradigm to describe the background knowledge and methods used in a field, whereas Floyd’s paradigm seems to be more about achieving a specific goal in a particular way. For example, an object-oriented language uses objects to structure code, but it doesn’t specify much anything else.
If we look at Kuhn’s usage of paradigm more carefully, we could use it to describe an individual program. We could define a Program Paradigm or Paradigm of a Program, or something along those lines - Something which defines the background knowledge of a particular program, constraints in its design, and the typical ways problems are solved in its codebase. I think this type of approach mirrors Kuhn’s paradigm more closely.
A project typically has some foundational technology, like the language, libraries or other tools used. It probably has some internal libraries which are used to build the program’s features. There is typically also some domain-specific knowledge, and not just programming skills, which the developer has to understand to work well in the project. This is similar to a scientific paradigm providing foundational knowledge and tools the scientist can work with.
A program usually has constraints to it, based on things like how it might be deployed, what performance requirements it has, and other such things, which limit the possible solutions the programmer has. Again similar to science, where the paradigm constrains which problems are considered valid.
I think what makes this interesting is that programs aren’t usually considered from this perspective. Have you ever thought about a program having a particular set of knowledge it requires to work with, in order to fully understand it? For example, when you’re learning new codebases or perhaps onboarding new developers to a project. You might discuss the language used, the tools used and perhaps general architecture, but it’s very easy to overlook other accumulated knowledge, the kind which is often not even written down anywhere. There’s often lingo from the business domain embedded in the code, or certain patterns of how the code is written, which are easy to overlook. But if we look at this from the perspective of a “paradigm of a program”, we can use it to help recognize these types of knowledge better.
Normal Programming
Similar to Kuhn’s Normal Science, we could say that most programming is “Normal Programming”. We work within certain constraints the program has, and we try to solve problems that exist within the specific requirements of the program. Normal Science is done in context of the Scientific Paradigm, and we could say that Normal Programming is done in context of the Program’s Paradigm.
After we’ve established the program’s paradigm by choosing the language, tools and libraries, and we’ve created the foundation that we can build on, much of our work becomes what could be described as similar to Kuhn’s Normal Science. We start improving the program, by solving feature requests and other problems coming from the users. The established tools and other code we’ve written also function as constraints to how we can approach solving problems.
If you think about the phases of a programming project, we usually need to do a bunch of exploratory work first. This is where we figure out what language to use, what tools to use (like a database, framework or libraries), based on the requirements we have. But once we’ve made our selection, we move into a style of work where we work within the boundaries of this initial work. When we work within these boundaries, we usually stop looking for new ways to solve problems, because we’ve established the paradigm, and we’re now doing “normal programming”, just like Kuhn describes how a scientific paradigm is established, and how it enables normal science.
For example, when we modify code, we’re usually not going to completely redo it from scratch - instead, we’re working within the established standards and practices of the codebase. We use the language we have, the libraries we’ve selected, and write the code according to the style of the rest of the codebase. We use certain established ways of solving problems. This is similar to Kuhn’s Normal Science, where the scientist works within the established norms of their particular paradigm.
Thinking of programming in this way makes it clear there’s usually two types of programming that occur in most projects: Normal, and let’s call it Exploratory. I think the longer a project has been going on, and the more established it is with users, the more the work leans towards Normal Programming. More exploratory changes have a higher risk of introducing bugs, and with established users, you’d want to avoid that. But this also means the longer you have been working on something, the more you might do Normal Programming simply by habit even when unnecessary.
I’ve seen a question about this type of Normal Programming come up on Reddit or such from time to time: Isn’t it boring? Typically this is in context of someone working on CRUD-style business applications, or building websites in an advertising agency. I’ve always thought you can find interesting problems to solve even in these types of more limited projects. In the book, Kuhn describes Normal Science as puzzle-solving, quite similar to this. When doing research, you often know the problem and what the result is going to be, so the fun in the work is figuring out the complete puzzle and the steps to get to the result. I think this is exactly the same even in more “mundane” programming projects.
In closing
Naur only referenced The Structure of Scientific Revolutions in one paragraph or so in his text, so compared to The Concept of Mind, there’s not so much here that directly relates to the Programming as Theory Building text. But I think there’s still an interesting angle if you consider how something like a program’s paradigm could be seen to be a part of the theory of a program. One of the key questions about Naur’s theory of a program is what constitutes the theory? What’s included in it? I think the program’s paradigm, or whatever would make up the paradigm, is a good example of something that the theory of a program would include.
Looking at the knowledge contained in a program from the paradigm standpoint is interesting especially because it makes us think of things which are easy to ignore: The specific ways certain things are approached in this specific program’s code, or the specific “methods” used. For example, if we were to create documentation of a program, we would often discuss architecture, libraries or maybe bug-triaging steps if we’re really detailed, but we probably wouldn’t look at how we approach solving problems. By solving problems, I mean day to day things like “if we need to accomplish task X, which functions should we use?” or “What is the correct way to create an extension of this class?” - and things like this are important to understand if we are to write good code within the program’s context. If we think of it from the perspective of the paradigm, which explicitly includes methodologies, it makes these types of questions more explicit as well.
The idea of Normal Programming has less bearing on Naur’s text. However, I think it’s interesting in that it shows there are two “modes” of programming, exploratory and normal, if we use the terms I used before. The two modes have different goals and constraints, so maybe we should approach them with a different mindset, and identifying them could be helpful in improving the usual workflows. Is splitting into two modes too coarse? Hard to say.
Finally, some other points I found interesting:
- Kuhn mentions that revolutionary ideas usually come from scientists newer to a particular field. Interestingly it seems this also applies to programming: When you work on a particular codebase long enough, you get used to how it works. You know how to deal with its quirks, and they might not bother you much. This means you might stop thinking of ways the code could be improved, and you might become reluctant to change it because it could cascade into multiple new problems.
- Similar to science, software development is not cumulative. You often end up throwing away a bunch of code as part of refactorings or for other reasons, similar to what can happen when scientific revolutions occur.
- Kuhn also mentions that many scientists cannot properly explain the fundamentals of their own fields. I think it’s similar in programming: There’s a lot of principles that people try to follow, like YAGNI or SOLID or whatever, but can you explain them properly off the top of your head? Probably not, unless you’ve specifically studied them in detail. I’m not sure if I can, not very well anyway.
If you’ve read this far, there’s another Kuhn-related article series you might find interesting: Kuhn! At the Software Industry, where the author applies Kuhn’s ideas from a more software testing oriented perspective.
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.