DEV Community

Cover image for Preventing/Refactoring Conditional Chainings
Igor Duca
Igor Duca

Posted on

Preventing/Refactoring Conditional Chainings

One of the most common code smells when developing JavaScript applications is the excess of conditional chaining. In this article, I want to argue about how to prevent these cases through architecture and code.

Table of Contents

  1. Introduction
  2. Understanding Conditional Chains
  3. The Problem with Conditional Chains
  4. Refactoring Conditional Chains
  5. Preventing Conditional Chains through Architecture
  6. Best Practices for Front-end Development
  7. Conclusion

What is a conditional chain?

Excessive conditional chaining is a common code smell in JavaScript applications. This article explores how to prevent and refactor these cases through improved architecture and coding practices.

Conditional chains are excessive logical operators used to express conditions in functions or methods. Let's look at an example using a React application:

A code example that contains a conditional chain

As you can see in the example above, there is a chain of three conditions only to dictate the way this code should be rendered.
The conditions are:

  1. If the list of sports has elements, the default element should be rendered;
  2. If the loading state of the component is true, a loading skeleton should be rendered;
  3. If there is no element in the sports list, an empty state should be rendered.

In this code, there are two main problems:

  1. When we are checking the length of an array and using the "&&" operator, we are telling javascript that it should render the component if there is a value related to the array's length. If there is no array, this value should be null or undefined, but, if the array exists and its length is zero, the number zero will be rendered instead of the elements, because you're asking javascript to render the value linked to the array's length.
  2. There is no need to use a chain to control the rendering of these two elements. Adding a condition before the render of the "default" state of the component will be a more elegant way to work with this situation.

Refactoring

That being said, the refactored version of the code above is:

This code shows a refactored version of the poor code mentioned above on the first image

This is one of the many ways to deal with conditional chainings using JavaScript's logical operators. As you can see in the code above, I've used a non-common approach to solve the conditional excess of the code.

The !! operator in JavaScript is used to coerce a value to a boolean. It takes advantage of the fact that JavaScript has truthy and falsy values. The first ! operator negates the value, turning truthy values into false and falsy values into true. The second ! negates it again, resulting in a boolean representation of the original value. This is often used to convert values like strings, numbers, or objects into a boolean value (either true or false), based on their truthiness or falsiness.

For example:

!!"Hello" evaluates to true because non-empty strings are truthy.
!!0 evaluates to false because 0 is falsy.

Preventing it from happening through architectural decisions

You must not take this as a rule, but in most of the cases where conditional chains are created, the excess of conditions are trying to parse and handle dynamic values, because if you're dealing with static values, the implementation tends to be much simpler and straightforward.

When you're modeling a database, you must have some concerns about the software's dependencies.

People typically learn this kind of dependency study through their IT college studies, but I'll illustrate it.

There are two kinds of dependencies on software:

  1. Functional dependencies - these dependencies directly affect the user, since they are the features the users are interacting with, such as buttons, screens, inputs, forms, etc.
  2. Non-functional dependencies - these dependencies are not commonly noticed by ordinary users since they are mainly the back-end ones, such as error handling, conditions, rules of business, validations, etc.

Preventing front-end excess control

Your back-end must be responsible for all the logic parts of your system, so, the majority of your functional dependencies must be handled by back-end functions, not by front-end screens or user interactions.

When you start to develop a new feature and to understand what it needs to work, such as props, interfaces, and parameters, you must have in mind what will be required, what will be optional, and what mustn't be used.

A code showing a React component interface with only optional parameters

You must use the example above as an example of what not to do during your development sessions. As you can see, this interface has only optional parameters, but I doubt this component will only have "maybe" variables attached to it.

You need to understand how your component is supposed to work before developing it and pushing a lot of confusing code to your front-end application. Instead of dealing with a lot of conditions, it is easier if you just decide: what will be used by the component and what will not.

After considering it better, you will come up with something like this:

Refactored interface with required-only parameters

Now the interface only has required parameters that will certainly be used through the component's lifetime inside your app, not having a lot of optional parameters that could never be defined or used like the component from before.

Conclusion

Preventing and refactoring conditional chains leads to cleaner, more maintainable code. By understanding your component's requirements, shifting logic to the back-end where appropriate, and designing clear interfaces, you can significantly reduce the need for complex conditional chains in your front-end code.


Photo by Samsung Memory on Unsplash

Top comments (0)