Variable Names
We have all opened up code that looks like this:
const fds = (fda + fdb)/gtr;
and wondered if the original author hated the universe, was a genuine genius or was somehow allergic to typing. There is nothing in that code to indicate what those variable relate to or how fds
might be useful in the future.
The variable names are meaningless to our brain and remembering these letter groupings while tracing their use through the code adds a huge amount of cognitive load.
Fortunately we have, in the main, moved away from this type of variable naming. It was ripe in the Fortran and early C days but now we use more descriptive names that show the intent of the code and it is much easier follow along. If a variable is called maxWidth
it is much easier to understand and remember than mW
. It's the different between holding a group of letters in your head vs the concept of what it represents, are brains are pretty terrible at the former but excellent at the latter.
Ternaries and Destructuring
Whilst we have clearly improved when it comes to naming variables there is an area of coding that we are going backwards in, and that is the desire for smaller and smaller files - even at the cost of legibility.
Small composable blocks of code is a great ideal to aim for, having 45 tabs open in a code editor isn't always ideal but it probably is better than 3 files of 2,000+ lines each. However, I would rather have those 3 big files to wrangle than dozens or hundreds of the following:
const { data: { header: { personId, storeId, locationId, stockUnit } } } = msg
or
const result = isAdmin ? "All Allowed" : isManager ? "Some Allowed" : isAlien ? "Run" : "Not Allowed";
In isolation the above examples are reasonably understandable (I've chosen fairly simple examples) however, amongst a full application, surrounded by other business logic and less straightforward variable names, both of these can be written in a longer, more understandable manner. Let's take that ternary:
let result = "Not Allowed";
if (isAdmin) {
result = "All Allowed";
}
if (isManager) {
result = "Some Allowed";
}
if (isAlien) {
result = "Run";
}
The above is considerably longer but much easier to read. The added vertical space is a more than worthwhile tradeoff in the aid of readability to me.
We should be striving to write code that is understandable to the newest and least experienced members of the team. Business logic is where the complexity should lie in code, not in the syntax itself. When a new developer or new team member is reading unfamiliar code they should be focussing all of their efforts on understanding the what the code does and not the exotic structures used to save a few lines.
The rise of ternary
Ternary operators have always been a bit of syntactic sugar to make very simple if/else
statements shorter. I would agree that an if/else
that takes up only 5 lines and is very simple should be simplified, however the rise in ternary in the Javascript world over the last decade is starting to get out of hand. I'm starting to see multi level ternaries with map
and find
in them where that all important :
of the ternary becomes impossible to spot.
I think this has happened thanks to React, more specifically JSX, and it's liberal use of ternary statements for conditional rendering. I don't want this to become a rant on JSX (which at worst I would say I am ambivalent on) but let's not let JSX practices bleed in to JS/TS and other best practice.
Take Away
Code for legibility and not brevity. We moved away from terse and incomprehensible variable names, let's not regress with the equivalent with syntax.
If you want a selfish motivation then I ask: would you rather new team members just understand the code you wrote or spend the rest of your days in that company answering questions about it?
Update
As some awesome people have highlighted in the comments below, I got this code wrong and the ternary to if/else
is wrong. I wrong this code specifically for the article, didn't test it properly and only thought about one of the variables was true, in which case a switch statement on an enum would have been better. I still stand by multi-level ternaries being worse than a correct if/else equivalent however in this case I choose a poor example.
Top comments (10)
Thanks @pjotre86 , @jayjeckel , @andreidascalu for the awesome analysis of the code in the post. Totally right, I borked the example and didn't fully think it through. I've added an update to the post but I've left the code in place so people can see your corrections. Thanks for pulling me up on this one 😀
I'm a full on proponent of coding for clarity rather than brevity or even efficiency and have lobbied for that for decades, and refactored plenty of code to that effect. But I am equally fond of and a proponent of prudent use of ternaries ... encapsulating a single idea completely and elegantly aids comprehension and clarity IMHO.
Totally, not against ternaries - I just feel that have become a hammer for some people and being used too liberally 😀
Admit I don't read a lot of foreign code so don't know, and to be honest even if I did (read a lot of foreign code) I would be very wary of sampling bias before I drew any broad industry wide conclusions. But for my part I love this construct and use it a lot:
It is extremely clear and uncluttered when used appropriately and easy to read.
Well, I disagree with the last statement. The code didn't try to translate ternsries to ifs, it tried to rewrite the same logic.
I'd say the author misinterpreted the desired outcome trying to force his point home (or failed to understand the logic altogether).
Personally I would rather follow a ternary down 4-5 levels than if/else, but also depends on language. In PHP for example it's disallowed to write multi level ternaries without marking the boundaries with ()
Else if statements quickly go out of bounds with indentation and increase cyclomatic complexity.
You can also indent ternsries breaking at the ? to improve readability which dramatically improves it.
Personally I really like the ternary operator but not when readability is compromised.
Having one inside another makes the code difficult to read. Bernd Wechner made a good point on this with a code layout I had never seen before.
I find the following syntax quite clear and removes a lot of the boilerplate code that is required in, for example Java
Yeah. Check his code again. He’s right. You’re only kinda right.
EDIT: I see where his code is wrong now. My apologies.
Definitely not, just hoped/attempted to, though it didn't come out.
I think you’re wrong.
No, pjotre86 is completely right.
If we have an alien manager as the admin, then the variable values are:
The ternary version returns the correct result, "All Allowed", because our alien manager is an admin.
However, the offered serial if statements return the wrong result value, "Run", treating our manager as a low permissioned alien instead of a high permissioned admin.
If the ternary is going to be converted into if statements, then they should be if-else statements.
Now our alien manager is rightly given their admin level permissions.