DEV Community

Cover image for Stop! Put Down That Ternary, Lines Are Free
Simon Barker
Simon Barker

Posted on • Updated on • Originally published at careerswitchtocoding.com

Stop! Put Down That Ternary, Lines Are Free

Variable Names

We have all opened up code that looks like this:

const fds = (fda + fdb)/gtr;
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

or

const result = isAdmin ? "All Allowed" : isManager ? "Some Allowed" : isAlien ? "Run" : "Not Allowed";
Enter fullscreen mode Exit fullscreen mode

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";
}
Enter fullscreen mode Exit fullscreen mode

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.

Discussion (14)

Collapse
pjotre86 profile image
pjotre86

I'm not a js geek, but the isAdmin example:
I think the ternary version and your version are not the same. Imagine isAdmin and isManager are both true. You would get different results. You're missing the else.

Best proof that ternaries are sometimes not easily readable 😉

Collapse
andreidascalu profile image
Andrei Dascalu

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.

Collapse
pjotre86 profile image
pjotre86

I also like ternaries. With good formatting they're as readable as if-elses with a bit of experience. So the example is actually a good example of how to not format ternaries, yes.

Still, I wouldn't say the logic is the same. Proper unit tests would fail if you refactor it the way the author did.

Thread Thread
andreidascalu profile image
Andrei Dascalu

Definitely not, just hoped/attempted to, though it didn't come out.

Collapse
lowlifearcade profile image
Sonny Brown

I think you’re wrong.

Collapse
jayjeckel profile image
Jay Jeckel

No, pjotre86 is completely right.

If we have an alien manager as the admin, then the variable values are:

isAdmin = true;
isManager = true;
isAlien = true;
Enter fullscreen mode Exit fullscreen mode

The ternary version returns the correct result, "All Allowed", because our alien manager is an admin.

const result = isAdmin ? "All Allowed" : isManager ? "Some Allowed" : isAlien ? "Run" : "Not Allowed";
// result == "All Allowed"
Enter fullscreen mode Exit fullscreen mode

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.

let result = "Not Allowed";
if (isAdmin) { result = "All Allowed"; }
// result == "All Allowed"
if (isManager) { result = "Some Allowed"; }
// oops, the admin is also a manager, so now result == "Some Allowed"
if (isAlien) { result = "Run"; }
// oops again, the admin manager is also an alien, so now result == "Run"
Enter fullscreen mode Exit fullscreen mode

If the ternary is going to be converted into if statements, then they should be if-else statements.

let result = "Not Allowed";
if (isAdmin) { result = "All Allowed"; }
else if (isManager) { result = "Some Allowed"; }
else if (isAlien) { result = "Run"; }
// result == "All Allowed"
Enter fullscreen mode Exit fullscreen mode

Now our alien manager is rightly given their admin level permissions.

Collapse
pjotre86 profile image
pjotre86

Just to illustrate this. I found a ternary to if/else converter:
converter.website-dev.eu/
Here's what it would make out of the example:
example

Thread Thread
lowlifearcade profile image
Sonny Brown • Edited

Yeah. Check his code again. He’s right. You’re only kinda right.

EDIT: I see where his code is wrong now. My apologies.

Collapse
allthecode profile image
Simon Barker Author

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 😀

Collapse
thumbone profile image
Bernd Wechner

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.

Collapse
allthecode profile image
Simon Barker Author

Totally, not against ternaries - I just feel that have become a hammer for some people and being used too liberally 😀

Collapse
thumbone profile image
Bernd Wechner • Edited

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:

result = condition1 ? value1
       : condition2 ? value2
       : condition3 ? value3
       : condition4 ? value4
       : defaultvalue;
Enter fullscreen mode Exit fullscreen mode

It is extremely clear and uncluttered when used appropriately and easy to read.

Collapse
felherlla profile image
Felipe Hernandez

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

value = condition
              ? value1
              : value2
Enter fullscreen mode Exit fullscreen mode