There Is No Knowledge
All models are wrong but some are useful.
— George Box
There is a long and rich history of scientists and theoreticians warning us about the limits of our ability to generalize knowledge.
- David Hume’s
A Treatise of Human Natureintroduced the Problem of Induction and fundamentally calling into question the validity of human knowledge.
- Phil Anderson’s
More is Differentwarned us about the risk of taking an overly-reductionist view and forgetting essential complexity.
- The statistical variant of the
No Free LunchTheorem goes so far as to eliminate the possibility of a probabilistic resolution to the problem of induction, leaving us with the conclusion that Science only works as well as it does because the Universe, on balance, follows Occam’s Razor.
The vast majority of human “knowledge” that we qualify as Science actually rests on a rickety epistemological basis, but in spite of the fact that we “know” virtually nothing, we have managed to build skyscrapers, connect the world, go to space, and eliminate diseases.
These achievements rest on a multitude of models, all of which fail to mirror the total complexity of the real world in some way, but which are nonetheless useful.
Words as Models
Though we may not recognize it, most of the words and ideas we use on a daily basis are models. They take concrete things, like the two slices of bread with peanut butter and jelly I have in front of me, and generalize them into something we call a sandwich.
The empirical power of models can be illustrated when I ask you to imagine a sandwich, and what pops into your head will likely look similar to what almost everyone else is picturing in their head. It’s useful to be able to say this arbitrary collection of sounds and have mostly the same idea replicate in someone else’s mind.
The incorrectness of models can be illustrated, however, when I ask you whether or not a cheeseburger counts as a sandwich. Some of us may ascribe to the Cube Rule and say yes, while others may be ingredient purists and say no. Who is right? Who is wrong? And does it matter?
The fact is, this kind of argument can be played out for virtually any word in any language. Many human arguments are effectively spent arguing over what is the “right” definition of a word, instead of spent on the more important question of whose model is more useful for the problem at hand?
The next time someone hits you with “that’s not a real sandwich”, remember Box’s aphorism. There are no normatively correct models, and it doesn’t really matter if your counterparty’s definition of a sandwich matches yours - you have something you’re trying to communicate, and if you have to list concrete examples and generalize it to “foobar” - then that’s how you’ll explain that graham crackers with a toasted marshmallow and chocolate bar “foobar-ed” in-between taste incredible (because who cares if it’s a sandwich or not?).
If you consider the word “Species”, it could just as easily be defined as “Genetic Levenshtein Distance” instead of “Viable Sexual Reproduction”. It so happens, however, that when we try and group individual animals together into “Species” to make generalizations like “Giraffes have tall necks” or “Zebras have black and white stripes”, the “Viable Sexual Reproduction” definition has resulted in the ability to make remarkably good generalizations on a consistent basis. This definition of “Species”, for example, results in the grouping of some individual fish into a class like “Chinook Salmon”.
Again, this is not some normatively correct class - it’s an arbitrary line we’ve drawn between some individual fish and others, but it so happens that the fish within this class display all sorts of other similarities (such as how they taste) that are usefully correlated to the class generated by our definition of Species. It is precisely the presence of many such useful correlations that makes “Viable Sexual Reproduction” a useful definition for the term “Species”.
In the perfect twist of fate (illustrating Box’s aphorism), we later found out that this was insufficient when asexual and other forms of life were brought into the Tree of Life. Though perhaps the real question is… what is “Life”?
Models in Programming
There are only two hard things in Computer Science: cache invalidation and naming things.
— Phil Karlton
Our source code, along with our carefully chosen names, exist only until our compilers blast it all away in favor of more compact arrangements of 0s and 1s the machine will interpret. The reason source code is kept after delivery is so that it can be changed, and our names are ultimately communication with other engineers who will read the code we wrote.
We struggle to name for the same reason that we fight over what a sandwich is: Names ultimately represent models, and reality is that there are no normative definitions. Everyone’s mind is filled with our own versions of every model in the world, and the names in our code are no different.
When we write code, most of the entities we name don’t have some magical definition that everyone can just intuit from the name - they are ultimately a manifestation of the model that exists in the author’s mind. There are some exceptions, such as externally standardized concepts like “Country”, but the essence of good communication is largely in our ability to synchronize the model in our mind with the model in someone else’s.
Let’s consider an example:
I’m working at a financial services company, and I need to integrate with a variety of different banking partners around the world, so I’ll want a software entity to represent these Partners (perhaps I need to process statements, contracts, etc.).
What do I call them? “Bank”? “BankingPartner”?
At this moment in software development, instead of documenting a list of examples, describing their similarities, and providing a suitably explicit definition, we (understandably) forge ahead with something like “BankingPartner” because it “sounds about right”. New developers who must later add functionality to this code generally have three major cues to work with:
- The name
- What it does
The crux of the problem is that the model that a name provides is much less detailed than what the existing code describes. Maybe you’ve called it a “BankingPartner”, but the only function it fulfills is to act as the deciding mechanism for which integration is used to fulfill a particular order, then it’s fairly likely for someone to introduce something like “Barclays”, “BarclaysV2”, and “BarclaysNew” as instances - because in this scenario its structural functionality was as a Router.
Even if it was your intent for the “BankingPartner” to exist separately from “Routing”, without separate reinforcement of what the model should be, the cue of your name is overwhelmed by the cue of how the entity is used.
Indeed, naming proves to be hard precisely because of how often we discover functionality that needs to be pulled apart as we address more use cases. Getting a name “right” typically amounts to creating a concept that doesn’t need to meaningfully evolve throughout the lifespan of your software - a very tall order indeed.