The languages we use to drive computers are often Turing Complete. This means they are highly expressive, that they are deterministic, yet buried beneath them there can also ambiguities. Some are accidentally put there by programmers; some are just intrinsically embedded.
I saw a post about a bug caused by one of the newer configuration languages. It was mistaken in the type of its data and made a really bad assumption about it. That is a deliberate ambiguity.
We choose implicit typing far too often just to save expression, but then we overload it later with polymorphic types, and we sometimes don’t get the precedence right. To be usable the data must be typed, but because it is left to the software to decide, and the precedence is incorrect, it forms an ambiguity. The correct data type is unknown and cannot be inferred. Mostly it works, right up until it doesn’t. If the original programmers forced typing, or the precedence was tight, the issue would go away.
My favorite ambiguity is the two generals’ problem. It sits deep in the heart of transactional integrity, plaguing distributed systems everywhere. It is simple: if one computational engine sends a message to another one and receives no response, you can never know if it was the message that disappeared or the response. The information needed to correctly choose just doesn’t exist.
If the message was an action, you can’t know right away if the action happened or not.
It is the cause of literally millions of bugs, some encountered so frequently that they are just papered over with manual interventions.
What makes it so fascinating is that although you can never reduce the ambiguity itself, you can still wire up the behavior to fail so infrequently that you might never encounter the problem in your lifetime. That is some pretty strange almost non-deterministic behavior.
Ambiguities are one of the great boundaries of software. Our code is limited. We can endeavor to craft perfect software, but can never exceed the imperfections of reality. Software isn’t nearly as soft as we would like to believe, it is always tied to physical machines, which so often mess up the purity of their formal mechanics.
Sometimes to build good software you have to have both a strong understanding of what it should do, but also a strong understanding of what it cannot do. That balance is important.
Ambiguities are one of the great boundaries of software. Our code is limited. We can endeavor to craft perfect software, but can never exceed the imperfections of reality. Software isn’t nearly as soft as we would like to believe, it is always tied to physical machines, which so often mess up the purity of their formal mechanics.
Sometimes to build good software you have to have both a strong understanding of what it should do, but also a strong understanding of what it cannot do. That balance is important.
No comments:
Post a Comment
Thanks for the Feedback!