Start United States USA — software Don’ t Overdo the ''Principle of Least Astonishment'' Cargo Cult Don’ t...

Don’ t Overdo the ''Principle of Least Astonishment'' Cargo Cult Don’ t Overdo the ''Principle of Least Astonishment'' Cargo Cult

244
0
TEILEN

The Principle of Least Astonishment isn’t written in stone. Developers should be surprised from time to time, if only grow and learn new best practices.
As we all agree, GOTO is evil, right? Relevant XKCD.
Or even funnier: New Intern Knows Best .
Of course, somewhere deep down in our professional selves, we know that GOTO isn’ t evil, it’s just a very basic processor instruction that was available in the early days of assembly code. GOTO is everywhere. Take the following Java code, for instance:
The bytecode that is generated from the above logic is this:
There are two jumps. Byte code (like assembly code) doesn’ t know anything about local scope nesting. There’s just a stream of instructions and we’ re jumping around them. If GOTO were possible in Java (the keyword is reserved, so who knows about a future Java…?) , we could write this:
Of course, the if-else construct is more readable and less error prone. Some of the biggest problems we’ ve had with true GOTO instructions in the past are that they tend to lead to spaghetti code. In particular, notice how we’ re not jumping from the “args block” to the “end block”. We’ re just “falling through” like in a “bad” switch statement:
If you will, the switch statement is very similar to a set of GOTO instructions.
The case against “classic” GOTO is a case in favor of correctness.
These days, however, we don’ t have to squeeze our code into 16KB of RAM anymore, these problems are problems of the past. So we’ ve started “engineering” our code (whatever that means;) ) according to “best practices, ” most of which involve more humans than machines. We don’ t really need “GOTO” anymore, since we have higher forms of control flow abstractions.
Java has “GOTO” in the form of labeled blocks and break and continue statements. For instance:
Jumping forward:
In bytecode:
Jumping backward:
In bytecode:
Just recently, I’ ve blogged about labeled blocks making a case against extracting everything into a method. Why? Because a labeled block is a (slightly unusual) way of creating a local “method.” Squint really hard for a moment and let your imagination run wild with this:
So, if we admit the above, then labeled blocks in Java are almost like one-shot local methods (oh how I wish Java had actual local methods) . There’s no risk of doing things wrong like with GOTO. There’s no risk of any accidents in jumping to the wrong location because we still have a locally nested scope and everything is well-defined. So, there’s no correctness argument against using labeled blocks.
Why aren’ t they used more often? Probably because we rarely write such complicated imperative code where labeled blocks become really useful. I do from time to time, especially inside jOOQ’s parser logic. Labeled continue is especially useful to break out of an inner loop, continuing the outer loop.
Remember the analogy with methods? Break is the same as return. Every time you want to return early from a method, you could break early out of a block. Why not? Does it have to be a new method every time? Certainly not. Sometimes, jumping to a method is more distractive than jumping locally (again, as long as Java doesn’ t have local methods) .
The important thing here is that simplicity and readability, just like beauty, are in the eye of the beholder. We’ re in an area where we cannot clearly say that something is correct or wrong. Better or worse. Because again, unlike GOTO, breaking out of labeled blocks yields no correctness risk.
So, people start arguing in favor of the “principle of least astonishment” (especially in the comments of the DZone version of my post) . Sure. Labeled breaks are a bit harder to read because we hardly ever see them in our code. That doesn’ t mean they’ re bad. We hardly ever use synchronized these days (with JDK library support having become much better) , but that doesn’ t mean synchronized is bad and shouldn’ t be used. It’s rare, and thus we might get astonished. We don’ t usually use exceptions as control flow signals, but why shouldn’ t we? It is important to remind ourselves that the principle of least astonishment is a general guideline that allows for exceptions.
After all, astonishment is what makes us stop and think a bit more thoroughly about code. We might even learn something new, like the fact that we can break out of labeled blocks.
I like Ryan James Spencer’s way of putting it:
I wouldn’t have learned vim if I was a dogged slave to the principle, I’d look at it more like a heuristic https: //twitter.com/lukaseder/status/887206134934896640 …
Learning vim… It has become a joke that programmers don’ t know how to exit vim:
I’ve only restarted my Mac 3 times in the past 6 months, each time was to exit Vim safely.
(Of course, it’s simply “: q!”, how hard can it be;) )
In order to be productive, we shouldn’ t be astonished constantly. We should mostly be in our technical/infrastructure comfort zones because most of us write business logic, and we want to spend our precious time and brain cells on that, not on the infrastructure logic. Everyone likes SQL. No one likes working around funky JDBC edge cases.
Another interesting reply by Chris Martin:
I think the idea is astonishments ought to be selected and worthwhile, not a constant onslaught of random novelty https: //twitter.com/lukaseder/status/887206134934896640…
Absolutely. That was the point of my previous article. Breaking out of labeled blocks is cool every now and then. It might be astonishing if you don’ t write complex algorithms (like parsers) every day. It is not at all astonishing if you do.
So, please. Be open. Stop cargo culting. Use labeled blocks and break out of them. Every once in a while. When you think that makes your code clearer.

Continue reading...