We like to say that programming is a young field and we’re kind of still learning how to do it right, but sometimes it feels like that’s a statement of a desire… or an excuse. Let’s be honest — regardless of language, a lot of new code still looks like we haven’t moved past BASIC and a lot of new inventions are just rediscovered or repackaged ideas from the previous decades, as Kevlin Henney (along with all the Z System people) likes to point out. And yet I love everything that challenges the very core of how I perceive programming, even if I might one day find a similar statement from the 60s.
Below you’ll find one of the most intellectually challenging talks I've seen so far, at least when it comes to programming (we'll get to other areas soon). What Michael Feathers talks about here is the kind of thinking outside the box that really flips your programming up side down. Or maybe "the right side up", depending on how you think about it...
As a word of warning, this post is going to be a kind of philosophical rambling stream of consciousness. It will also bring up some interesting ideas from physics, which I hope can blow your mind as much as they continue to blow mine.
Exceptions considered limiting?
So what's the point of the talk? Basically building more resilient code by not resorting to exceptions. I obviously encourage you to watch it in full, but the distilled version would go something like this:
Exceptions tell us where the boundaries of our domain are. When confronted with the need to raise an exception, we could instead think of whether these boundaries can be expanded to contain the "exceptional case".
What does that mean? The simplest example Feathers gives is the square root function. What happens if you pass a negative number into a sqrt function? Simple, you get an exception. Could the domain of the program be somehow expanded to contain this situation without blowing up? As it turns out, mathematicians have that all figured out: you just get a complex number.
Yet, as Feathers himself notes, we don't usually do this because of how it would affect the rest of the code, which would also have to support operations on complex numbers. Not to mention complex numbers are, let's say, of limited applicability to real world situations such as, I don't know, e-commerce.
That's why it's so challenging to even start thinking in this way. When I shown this talk to a friend, his immediate reaction was to ask "ok, cool, but how do I express that in the code? A callback of some sort?". And this reaction is about as natural as it is missing the point. We think in code. Feathers encourages us to entertain thinking in domain. It's a similar, if more dramatic, shift as the one I advocated in "Forget computers exist".
get(id: int, missing: Callable)), the NullObject pattern, None/NULL and exceptions are all ways to deal with encountering boundary conditions. What Feathers suggests is not even dealing with these conditions early on, but rather eliminating or pushing those conditions further, so you don't encounter them at all. It's interesting to look at how this kind of logic works elsewhere.
It reminds me of the way the human brain works. Listening to one episode of Sean Carroll's Mindscape podcast I was reminded of the plasticity of the brain. I found out that we don't have a hardwired map of our bodies embedded in our brains through DNA. To the contrary, that map is generated as a result of our brain's interaction with our body and it's very flexible and adaptable. To emphasise, it's not that the map comes from DNA and can be altered. It's built from scratch as we learn how many limbs we have and how they move. Which I find astonishing.
We can use VR to trick our brains into thinking we have 3 arms and, over time, the third arm becomes a part of the map. Moreover, it can be switched on and off. It also works the other way, as exemplified by dogs Faith and Duncan, each of which lacks two legs, front or back respectively, yet their mobility is (or, in case of Faith, was) not impaired at all. A less hardcore example, given by David Eagleman in that podcast, is riding a bike. That skill, just like everything else, also becomes a part of the physical structure of your brain as you learn it. Which, I'd argue, expands the domain of your "inner program".
Imagine, instead, that the brain was structured like a typical computer program. What would you expect to happen if you gained an arm or attached wheels to your legs, which is a way of saying tried to ride a bike or roller blades? You're probably thinking
WheelsException, but generic
TypeErrorsare actually much more likely. Along with your whole brain crashing. Or at least not using these limbs and means of mobility in any sensible way, because it's just ignored through exception handling.
You see, in order to throw an
ExtraArmError the programmer would've had to consider the possibility of such extension. So in a way, would've had to start the thought process which Feathers is proposing, but then go "I can't be bothered" and explicitly set the boundary of the domain right there and then. And that's the default programmer behavior — we name the borders, instead of trying to consider what interesting possibilities might lay on the other side. Yet they may be very, very interesting...
QM = GR
There are two scientists who had a huge influence on me: Leonard Susskind and Sean Carroll. Both have a very different style. Susskind is more of a "shut up and calculate" pragmatic kind of guy who helped invent the String Theory, while Carroll is the kind of physicist who slips the Everett Interpretation of QM into every conversation. I gravitate towards Sean's side, but maybe that's simply because I couldn't calculate anything in physics if my life depended on it…? In either case, it's amazing that both of them have recently been arriving at the same conclusion regarding reconciliation of general relativity with quantum mechanics:
The reason quantising gravity has never worked could be that gravity has always been embedded in quantum mechanics. As Susskind puts it: "gravity is the thermodynamics of entanglement".
Ok, but why am I mentioning this? Well, because this is an even more radical thought than the one we've started with, yet it's similar in some ways. Arriving at this conclusion required expanding, modifying or repurposing the domain of quantum mechanics and even reversing our thinking about certain things, which is what Sean Carroll likes to bring up.
If you start with the classical world and think of "quantising it", you may find yourself thinking that "points in space are highly entangled when they're nearby and more loosely entangled when they're further appart". And that tells you some useful things about the world, but it arguably doesn't bring you much closer to deriving quantum gravity. But if you flip that and say "points in space are nearby when they're highly entangled and further apart when they're more loosely entangled" you end up deriving physical distance from the most fundamental ideas in quantum mechanics. How cool is that?
Obviously, it took decades of work such as String Theory, holography, AdS/CFT, and ER = EPR to even consider this could make any sense whatsoever, but it's a great example of trying to find new ways of working with a domain and I find it inspiring.
In the talk, Feathers shows how the resulting code becomes not just more resilient, but also simpler. So you basically get two benefits at the cost of… rethinking your entire life, I guess. Still, it's not entirely obvious that would be the result. After all, we're building code that can, effectively, do more. It's unexpected for that to result in simplicity, but in some ways it does. Or at least it shifts the complexity elsewhere, which may or may not be what you want, but it's an interesting tool to have at your disposal.
Going back to physics, but also a little back in time, it's a similar story with the aforementioned Everett's interpretation of quantum mechanics, aka Many Worlds, although that name is kind of misleading — it's not about adding worlds, but about expanding the domain of QM and acknowledging the existence of these.
You see, in the beginning of QM people thought it should only work with particles. They had no reason not to, they've never seen a sandwich, let alone a human, get smeared all over reality, as the Schrodinger equation would suggest it should. So they came up with the "Heisenberg cut", which separated the QM world of wave functions from the classical world of dogs, cats, and coffee cups. You can read about it, but in programmer terms it meant doing this
qm.apply_to(humans) resulted in
ClassicalObjectError. And error handling was built around this:
try: quantum_mechanics.apply_to(object) except ClassicalObjectFound: classical_mechanics.apply_to(object)
Then Everett comes along and says: "if you just swallowed the idea that you can be in a superposition, you could get rid of that exception handling and it just looks like this":
Does this make the whole thing simpler? Yes and no. On one hand, we get 1 line of code here instead of 4, so that's arguably simpler. On the other, we get conundrums which don't necessarily exist in the Copenhagen interpretation, but the benefit is that we can flip our thinking more easily to quantum-first, which arguably helps when you're trying to derive all of reality from QM.
Currently, there's still a lot of edge cases and, as I said, it took decades to get here and will take decades more to finally be able to use QM with no error handling at all, but there's light in the tunnel. And it's a nice illustration of how this kind of thinking can lead to Unconditional Code (or unconditional theories), even if your deadlines may not allow you to apply this to that system you're currently working on ;) .
Where does that lead us? Hopefully to the conclusion that challenging the typical way of thinking about your domain, how you express it in code, and how you handle its boundaries can be useful. I don’t think any of us is going to abandon exceptions in anything more than toy examples, but it’s something to think about whenever you see a need for one. In the same way that you should always at least consider other options before expanding your codebase with another explicit IF or FOR, unless you want it to end up looking like Gilded Rose. And in the same way that you should lean towards parsing, rather than validation.
And in case you’re interested in hearing more about the QM stuff I’ve mentioned, I strongly recommend Sean Carroll’s book Something Deeply Hidden as well as the following talks: