The Anti-Robustness Principle

Thursday, July 16, 2020
By dreeves

This is another tech nerd post. Normal humans seek cover!

Abstract: Fail loudly and immediately.

(I sure hope all the normal humans took cover already because that sentence sure would sound different to them than to us! I also hope this isn’t all too obvious for actual programmers but I predict you’ll see it violated plenty and maybe this post will be useful to point people to.)

The Robustness Principle, also known as Postel’s Law, says to be conservative in what you send and liberal in what you accept. I don’t think I’m alone in opining that that principle makes web development a Lovecraftian nightmare. The misguided, myopic monition from Postel [1] is, ironically, the single biggest cause of me saying “this is why we can’t have nice things”. On the internet anyway.

What you should actually do is fail hard and loud and consistently and make everyone get with the program. Everyone (or thing) interacting with your program, I mean. It’s kind of the API version of the Anti-Magic Principle.

Code-philosophically, when a program gets input that’s slightly wrong but it’s easy to convert it to what you know the input was meant to be, it’s a Very Bad Idea to actually do that. Instead you should say “that input is Not Exactly Right so everything will break now”. It sounds crazy but is so, so true! Being forgiving leads to cruft and technical debt and baffling future bugs. Again, I’m not being particularly contrarian here. See the Criticisim section of the Wikipedia page on the the Robustness Principle.

“Make your code overly literal and punctilious and pedantic”

Now we come to the shameful part where we tell you how we’ve learned this the hard way. Actually we’ve learned and relearned it embarrassingly many times over. Keep code dumb, for God’s sake. I mean your future self’s sake. God can handle clever code just fine. For us mortals, it’s going to break in every imaginable and unimaginable way regardless and the dumber it is the easier it will be to debug.

And by dumb I mean simplistic. Exemplify every obnoxious nerd stereotype: Make your code overly literal and punctilious and pedantic. Even obtuse, in the sense of making zero assumptions, as the listener, about what the speaker intended.

Prof. Yorgey’s Anecdote

You may remember Brent Yorgey from such Beeminder blog posts as Beeminding All The Things and The Fifty Goals of Brent Yorgey. He’s amazing. Anyway, we were chatting with him about the Anti-Robustness Principle and he had an especially good example that he said we could share so we’re including it in this aside.

It started with yet another example of our own, about Ruby and our database being way too permissive (“you can’t assign an array to a float so we’ll just assume you want that float to be zero ok done”) and causing us all manner of heartache. Prof Yorgey is a serious Haskell expert, a language with static typing that prevents just such heartache. So we sheepishly pointed him to this example of how we’d reaped what we’d sown in not using Haskell. Here was his response:

The thing is, Haskell is way overkill for this. Even Java or C++ will prevent you from initializing a numeric variable with an array!

I should interject in Ruby’s defense that Ruby itself is not that idiotic either. Our problem involved the combination of Ruby and our database (Mongo). In any case, it was a seriously facepalmy violation of the Anti-Robustness Principle! But getting back to Prof. Yorgey:

I have no problem with dynamic typing per se. It’s this whole idea of refusing to throw type errors even at runtime that I don’t get. “I know, when the types of things don’t match, let’s have the runtime just silently convert to some default value, because it will be sooooo cute and convenient to be able to write things like while queue instead of while !queue.isEmpty and there’s definitely no way this will ever come back to blow off everyone’s feet!” When I’m teaching Python my students are constantly making mistakes like writing if blah == "y" or "Y" and are then mystified when that branch always runs no matter what they type. It makes me so angry when I have to explain how the string “Y” is getting silently converted to True.

Here’s a specific way we ourselves have violated this principle: The Beeminder API, if it gets a parameter it doesn’t recognize, silently ignores it. Anguished wail! That just means if you misspell something then everything will appear to be fine and later it will turn out to be mystifyingly not fine and unless you get lucky and spot the mistake you may end up heaving your computer out the window and that is expensive. It actually seems absurd to me that we didn’t know that back in 2012, but here we are.

Can’t we just fix it, you ask? Maybe not! And this is the real kicker with how awful the Robustness Principle is. Or how vital the Anti-Robustness Principle is. Since the Beeminder API is all nice and forgiving about unknown parameters, who knows which clients (including our own smartphone apps, though we could fix those ourselves, obviously) will break if we suddenly stop being misguidedly robust.

If you do the persnickety thing you can always change your mind later and be more forgiving. It’s much harder to go the other direction. Hence Anti-Robustness being an important guiding principle for writing code and us consecrating it as a blog post in hopes that we’ll be better about this ourselves.

Footnotes

[1] Who was this jerk, anyway? Oh, right, one of the creators of the internet. Fine, we’ll let his one bad idea slide. I’m sure it made sense at the time!

Image credit: Faire Soule-Reeves

Tags: , , , , , ,