February 21, 2023

Hide complex conditional details

Extracting a function is a great way to improve reusability of your code—you see a piece of code repeated throughout the codebase, you create a function with that common code, and then you replace all repeated code with that function call. But it’s not the only reason to extract a function.

Another reason to extract a function is to give a block of complex code a name to reveal the intent of that code—to make it easier to read.

A common place for this complex code is conditional—sometimes you have multiple &&s and ||s to check for something before running some other code. Extracting that conditional to a well-named function will make your code easier to read and understand.

Example

In this example, I have a function that adds a product to the user’s shopping cart. The shopping cart accepts the product as an object with some specific fields—like name and price.

addProductToShoppingCart(user, product) {
  let price
  if (
    user.totalOrders === 0 ||
    (user.shoppingCart.length > 5 && product.price >= 50)
  ) {
    price = product.price * 0.8
  } else {
    price = product.price
  }

  const productToAdd = {
    name: product.name,
    date: Date.now(),
    price: price
  }

  // ...
}

The if statement above checks if the user can have a discount for that product. Reading the details for that conditional is not necessary unless you want to modify it.

So, I can hide these details by extracting the conditional to a function with a name showing its intent.

addProductToShoppingCart(user, product) {
  let price
  if (canGetADiscount()) {
    price = product.price * 0.8
  } else {
    price = product.price
  }

  const productToAdd = {
    name: product.name,
    date: Date.now(),
    price: price
  }

  function canGetADiscount() {
    return user.totalOrders === 0 ||
    (user.shoppingCart.length > 5 && product.price >= 50)
  }

  // ...
}

Since I have defined that function inside addProductToShoppingCart, I can access all of its data without passing any parameters—which would make it shorter and clearer.

To make the code even easier to read, I can reformat that part using the ternary operator—it wasn’t a good idea before because the conditional logic was very long.

addProductToShoppingCart(user, product) {
  const price = canGetADiscount() ? product.price * 0.8 : product.price

  // ...
Stay up-to-date on the latest projects and articles from me