Principle of Least Astonishment
wiki.c2.com
wiki.c2.com
> Everyone has an individual background. Someone may come from Python, someone else may come from Perl, and they may be surprised by different aspects of the language. Then they come up to me and say, 'I was surprised by this feature of the language, so Ruby violates the principle of least surprise.'
> Wait. Wait. The principle of least surprise is not for you only. The principle of least surprise means principle of least my surprise. And it means the principle of least surprise after you learn Ruby very well. For example, I was a C++ programmer before I started designing Ruby. I programmed in C++ exclusively for two or three years. And after two years of C++ programming, it still surprises me.
[1] https://makandracards.com/makandra/46939-ruby-a-small-summar...
'//'.split('/') # => [] instead of ['', '', '']
'/'.split('/') # => [] instead of ['', '']
''.split('/') # => [] instead of ['']
'//'.split('/', -1) # => ['', '', '']
'/'.split('/', -1) # => ['', '']
''.split('/', -1) # => [] instead of ['']
In comparison: "".split("/") # => [""] in javascript
"".split("/") # => [""] in python'//'.split('/') => [ '', '', '' ] '/'.split('/') => [ '', '' ] '',split('/') => [ '' ]
so they indeed produce what parent expected.
As a field, we would benefit greatly from learning more cognitive science.
A core suggestion of John Osterhout's book A Philosophy of Software Design is to have well-named modules with 'thin' interfaces which accomplish a reasonably-deep set of responsibilities. But...why?
Working Memory -- Humans have limited Working Memory.
If you give a function:
- A clear name.
- Few simple parameters.
- No side-effects not in the name.
- No GOTOs or exceptions.
then a human can glance at it, put the name and parameters into working memory, and carry on.
But if you split up a namable responsibility across multiple files, then a human reading the codebase to understand data flow would need many more open editor windows or to hold much more info in working memory.
Too often you see code with a generically-named function/variable, and a comment next to it describing what it does. Why not just name the function/variable correctly?!
There's a strong cargo-cult idea that "real" programmers use short/abbreviated names, and yet there's absolutely no value to using "idx" over "index", or a more appropriately named "last_name_index".
torque_aux_motor_braking_only_safety_threshold_nm is a good variable name, but I wouldn't want to let them get much longer than that.
The coercion rules were a big surprise to me when I first started to work in JS. Sometimes codes were obvious but the underlying interpretation is a surprise call.
Javascript is convenient for many use cases, but it definitely violates POLA on many levels, in many situations!
In what language (other than a RPN based language like Lisp) would this expect to return something meaningful?
To be fair, is there any mainstream language other than Python where that expression makes sense at all?
And even Python had to make explicit, syntactical support for it, and IMO it's a pretty non-obvious language hack. I mean, there's an invisible AND in there, that's pretty astonishing to me at least :-)
That said I find comparison chaining rather confusing and unexpected so I make a point of avoiding its use. Typing it out as two comparisons hardly saves any effort in any case.
? (< 0 1 2)
T
? (< 0 -1 2)
NIL
user=> (< 0 1 2)
true
And user=> (< 0 -1 2)
falseThe developer replied, mostly tongue in cheek to be fair:
Well, it doesn't astonish me
In Java : http://java-performance.info/throwing-an-exception-in-java-i...
In C# : https://docs.microsoft.com/en-us/dotnet/standard/exceptions/...
In C++ : https://pspdfkit.com/blog/2020/performance-overhead-of-excep...
There's no real reason you can't have a compiler that converts exception-throwing-code into error-code-returning-code. That'd basically cost you the performance of a couple if-statements per function call return, which doesn't seem too excessive to me.
Of course most languages don't implement exceptions this way and I'm sure there's a good reason for it but you can still choose -- as a language implementor -- to have cheap exceptions.
It's slower but only adds 0.01 s as compared to the a version not using exceptions. This was about 3 orders of magnitude slower (probably more under load would be my guess)
+1 for all the extra work to prove to himself that he had taken the right approach.
-10 For refusing to listen, ignoring data and cherry picking articles on C about exception handling (Of course they're not going to use exceptions, they don't exist)
Also, in my experience, one of the major holes that mediocre devs have is that they struggle to look at things from a different perspective (either the perspective of a user or the perspective of another developer). This principle is fully based on putting yourself in someone else's shoes and thinking about what they would expect, which is exactly what these devs struggle with.
In my imagined best case result, you and your coworker are now having a conversation about your backgrounds and perspectives to try to understand where the mismatch is that led to your astonishment. One possible outcome there is that you establish a new, common basis for understanding, and less future astonishment thereby.
... this is what gives me an opportunity to describe the principle :-)
and for those who know it - they already know what I mean.