Categories
Refactoring

JavaScript Refactoring — Functions and Classes

We can clean up our JavaScript code so that we can work with them more easily.

In this article, we’ll look at some refactoring ideas that are relevant for cleaning up JavaScript functions and classes.

Remove Assignments to Parameters

We should remove the assignment of values to parameters and assign parameter values to variables before working with them.

For instance, instead of writing the following:

const discount = (subtotal) => {
  if (subtotal > 50) {
    subtotal *= 0.8;
  }
}

We write:

const discount = (subtotal) => {
  let _subtotal = subtotal;
  if (_subtotal > 50) {
    _subtotal *= 0.8;
  }
}

We should do that because people may be confused if the parameter is passed by value or passed by reference.

In this case, it’s passed by value, but to make that clear, we should assign it to a variable before working with it.

Replace Method with a Function

We can turn a method into its own function so that all classes can access it.

For instance, instead of writing the following:

const hello = () => {
  console.log('hello');
}

class Foo {
  hello() {
    console.log('hello');
  }
  //...
}
class Bar {
  hello() {
    console.log('hello');
  }
  //...
}

We can extract the hello method into its own function as follows:

const hello = () => {
  console.log('hello');
}

class Foo {
  //...
}

class Bar {
  //...
}

Since the hello method doesn’t depend on this and are duplicated in both classes, we should move it out to its own function to avoid duplication.

Substitute Algorithm

We want to replace an algorithm with one that’s clearer.

For instance, instead of writing the following:

We instead write the following:

const doubleAll = (arr) => {
  return arr.map(a => a * 2);
}

We made our doubleAll function more concise by replacing the loop with array methods that does the same thing.

They both double each entry of the array and return it.

If there’s a simpler way to do something, then we should use that instead.

Move Method

We can move a method between classes to another so that it’s in the place that it’s actually used.

For instance, instead of writing the following code:

class Foo {
  method() {}
}

class Bar {

}

We can instead write the following:

class Foo {

}

class Bar {
  method() {}
}

We move methods so that it’s in the class that uses the method the most. The original class can call the method from the new class that the method is in.

Or it can just not be called if it isn’t needed.

Move Field

In addition to moving methods, we can move fields as well.

For instance, instead of writing the following:

class Foo {
  constructor(foo) {
    this.foo = foo;
  }
}

class Bar {

}

We can instead write the following:

class Foo {

}

class Bar {
  constructor(foo) {
    this.foo = foo;
  }
}

We can move it to the place that we need it the most.

Extract Class

If our class is complex and does multiple things, then we can move the extra function to the new class.

For instance, instead of writing the following:

class Person {
  constructor(name, phoneNumber) {
    this.name = name;
    this.phoneNumber = phoneNumber;
  }

  addAreaCode(areaCode) {
    return `${areaCode}-${this.phoneNumber}`
  }
}

We can write the following instead:

class PhoneNumber {
  constructor(phoneNumber) {
    this.phoneNumber = phoneNumber;
  }

  addAreaCode(areaCode) {
    return `${areaCode}-${this.phoneNumber}`
  }
}

class Person {
  constructor(name, phoneNumber) {
    this.name = name;
    this.phoneNumber = new PhoneNumber(phoneNumber);
  }
}

This way, we move the extra functionality that the Person class shouldn’t, i.e. manipulating phone numbers into its own class.

By doing that, both classes only do one thing instead of having one class do multiple things.

Conclusion

We can extract code from complex classes that does multiple things into its own class.

Also, we can move methods and fields around the place where it’s used the most.

Assigning values to parameter values is confusing, so we should assign it to a variable before working with them.

Categories
Refactoring

JavaScript Refactoring — Function Refactorings

We can clean up our JavaScript code so that we can work with them more easily.

In this article, we’ll look at some refactoring ideas that are relevant for cleaning up JavaScript functions and methods.

Extract Method

We turn some code fragment into a function that has its own name to explain what they’re doing.

Instead of writing the following code:

const logOwing = (name, amount) => {
  console.log('name', name);
  console.log('amount', amount);
}

We can instead move the log statements into their own function as follows:

const logName = (name) => {
  console.log('name', name);
}

const logAmount = (amount) => {
  console.log('amount', amount);
}

const logOwing = (name, amount) => {
  logName(name);
  logName(amount);
}

This way, we know what each statement is doing.

Inline Method

We can put the function’s body into the body of its callers and remove the function.

Instead of having a function that only returns the return value of one expression as follows:

const getRating = (isLate) => {
  return (isLate) ? 1 : 21;
}
const getDeliverPersonRating = () => {
  getRating(false)
}

We just move the expression of the getRating function into the getDeliverPersonRating function as follows:

const getDeliverPersonRating = () => {
  const isLate = false;
  return (isLate) ? 1 : 21;
}

The method is getDeliverPersonRating is clear from its name, so we don’t need another function doing the same thing, so we just move the expression in the getRating function into the getDeliverPersonRating function.

Inline Temp

We can remove variables that are assigned the return value of some function and combine it with the expression that uses the temporary variable.

For instance, instead of writing the following:

const getBasePrice = () => {
  return 2
}

const isHighPrice = () => {
  const basePrice = getBasePrice();
  return basePrice > 2;
}

We can remove the basePrice constant and just replace it with the getBasePrice call as follows:

const getBasePrice = () => {
  return 2
}

const isHighPrice = () => {
  return getBasePrice() > 2;
}

We can do that since the basePrice constant is just used in one place, so we don’t really need to assign it to a variable or constant and then reference it.

They just encourage longer methods.

Introduce Explaining Variable

If we have a complex expression, we should assign it to a variable so that we can see what the expression returns without looking at the expression itself.

For instance, instead of writing the following code:

const checkBrowser = () => {
  if (navigator.userAgent.toLowerCase().includes("mac") &&
    navigator.userAgent.toLowerCase().includes("ie")) {
    //...
  }
}

We can introduce some variables to check the user agent as follows:

const checkBrowser = () => {
  let userAgent = navigator.userAgent.toLowerCase()
  let ieIEMac = userAgent.includes("mac") && userAgent.toLowerCase().includes("ie")
  if (ieIEMac) {
    //...
  }
}

In the code above, we set the user agent string to the userAgent variable and then the ieIEMac is set to the boolean expression to check if the browser’s user agent string he 'ie' and 'mac' in it.

Now we know without looking at the long boolean expression that it’s checking if the user is visiting a site with IE on a Mac.

It makes reading our code easier.

Split Temporary Variable

We should make a temporary variable for each assignment if we’re assigning 2 different values to the same variable.

Instead of writing the following:

const getCircleDimensions = (radius) => {
  let temp = 2 * Math.PI.radius;
  const result = {};
  result.perimeter = temp;
  temp = Math.PI * (radius ** 2);
  result.area = temp;
  return result;
}

We write the following:

const getCircleDimensions = (radius) => {
  const perimeter = 2 * Math.PI.radius;
  const area = Math.PI * (radius ** 2);
  return {
    perimeter,
    area
  };
}

In the code above, we have the getCircleDimensions function, which calculates the perimeter and area of a circle with the given radius.

In the first function, we assigned the return value for the perimeter and area to the same temp variable, and then assigned each to as values of different properties of result .

In the refactored version, we set them each to their own constant and then return them in the object.

It’s both shorter and clearer. We want to refactor the function this way so that we can just look at the constant names to get what we’re doing.

Conclusion

There’re few ways to refactor JavaScript code. We can introduce temporary variable to make things clearer or we can remove them if the code is clear without it.

We can do the same with help functions.

Categories
Refactoring

Easy Things That Can Be Quick Wins for Refactoring

JavaScript is an easy to learn programming language. It’s easy to write programs that run and does something. However, it’s hard to write a piece of clean JavaScript code.

In this article, we’ll look at some easy things that can be refactored without much effort even with the ugliest code.

No Invariant Functions

Invariant functions are ones that always return the same thing given any kind of input.

Obviously, that’s pretty useless since it’s the function that always returns the same thing.

With invariant functions, either we should just assign the returned value as a constant, or change the function to return something different given different kinds of outputs.

For instance, if we have the following function:

const foo = name => 'name';

Then this should be refactored because the function always returns 'name' . We don’t want a function like that because the parameter is useless and the return value is constant.

A function that commits a side effect but always returns the same thing is also an invariant function.

For instance, if we have:

let name;
const setName = (firstName, lastName) => {
  name = `${firstName}, ${lastName}`;
  return 'name';
}

Then that’s also an invariant function since it returns the same thing. What it does before that doesn’t matter.

In this example, we should refactor our function so that it becomes a pure function.

For instance, we should rewrite the setName function to be a pure function and call it as follows:

const setName = (firstName, lastName) => `${firstName}, ${lastName}`

In the code above, we changed the setName function to a pure function by changing it to return the firstName and lastName parameters combined.

Now we don’t have an invariant function anymore since it doesn’t always return the same thing.

Also, now we can call it as follows:

let name = setName('jane', 'smith');

This is better than committing side effects unnecessarily.

Pure functions are easy to test and understand since the output is predictable given the input.

Keep the Default Clause of a switch Statement Last

The default clause of a switch statement should be last to following commonly accepted convention. This makes our code easier to read since it’s consistent and the pattern is predictable. Thus reducing the cognitive load on the reader.

Therefore, instead of writing:

const foo = (bar) => {
  switch (bar) {
    default: {
      return 1
    }
    case 'foo': {
      return 2
    }
    case 'bar': {
      return 3;
    }
  }
}

We should instead write:

const foo = (bar) => {
  switch (bar) {
    case 'foo': {
      return 2;
    }
    case 'bar': {
      return 3;
    }
    default: {
      return 1;
    }
  }
}

This is much easier to read for anyone as we stick to conventions that are accepted by most people.

Clean up Redundant Variables

Redundant variables are hard on our brains. Also, they take up more memory on the user’s computer as the browser or Node.js has to allocate more resources or each variable.

The cluttering of the code makes it hard to read and debug since they’re misleading. They look different but they actually are used for the same thing.

For instance, instead of writing:

const foo = (bar) => {
  switch (bar) {
    case 'foo': {
      const two = 2;
      return two * 2;
    }
    case 'bar': {
      const three = 3;
      return three * 2;
    }
    default: {
      const one = 3;
      return one * 2;
    }
  }
}

which has 3 constants that we don’t need. We can instead write:

const foo = (bar) => {
  let num;
  switch (bar) {
    case 'foo': {
      num = 2;
      return num * 2;
    }
    case 'bar': {
      num = 3;
      return num * 2;
    }
    default: {
      num = 3;
      return num * 2;
    }
  }
}

In the code above, we have the num variable, which are assigned in each case block and also the default block.

Then we can use the num variable the way we wish to after setting it. Now we only have 1 variable instead of 3, saving computer memory and also reducing the cognitive load on the reader.

Conclusion

There’re a few quick wins when it comes to refactoring. One is to remove redundant variables.

We also shouldn’t move the default block of a switch statement outside of its normally accepted position from the bottom.

Finally, we shouldn’t write invariant functions, even if they commit side effects.

Categories
Refactoring

JavaScript Refactoring Tips — Arrays and Conditionals

JavaScript is an easy to learn programming language. It’s easy to write programs that run and does something. However, it’s hard to write a piece of clean JavaScript code.

In this article, we’ll look at how to clean up conditionals with arrays, and use classList to manipulate class names.

Replacing Long Or Expressions with Array Checks

We can replace long or expressions with array checks easily. For instance, instead of writing:

if (fruit === 'apple' || fruit === 'orange' || fruit === 'grape') {
  //...
}

We can use some array methods to reduce the length of the conditional expression.

One way is to use the array instance’s includes method to do so:

if (['apple', 'orange' ,'grape'].includes(fruit)) {
  //...
}

As we can see, we checked if any one of them is the value of fruit by comparing the value of fruit in an array with includes .

The includes method returns true if the value we passed into the argument is included in the array instance and false otherwise.

Also, we can use the array instance’s some method to check the value:

if (['apple', 'orange', 'grape'].some(a => a === fruit)) {
  //...
}

The some method lets us check if there’s any array entry with the given condition in the callback exists.

It returns true if one or more exists and false otherwise.

We reduced the long conditional expression with arrays in the first example.

Using the classList Property in DOM Elements

The easiest way to check if a class exists in a DOM element and manipulate multiple classes is to use the classList property.

For instance, if we want to add multiple classes, we can write the following code:

const p = document.querySelector('p');
p.classList.add('foo');
p.classList.add('bar');
p.classList.add('baz');

This way, we can add multiple classes without manipulating strings. We just get the classList property of a DOM element object and then call add to add the classes by passing in a string with the class name into the the add method.

The rendered DOM element now has the foo , bar and baz classes.

Likewise, we can call the classList property’s remove method with a string with the class name to remove to remove the class.

For instance, we can write:

const p = document.querySelector('p');
p.classList.add('foo');
p.classList.add('bar');
p.classList.add('baz');
p.classList.remove('baz');

Then the rendered HTML only has the foo and bar classes since we called remove to remove the baz class.

To check if a class name exists in a DOM element object, we can use the contains method.

To use it, we can write:

const p = document.querySelector('p');
p.classList.add('foo');
p.classList.add('bar');
const hasBaz = p.classList.contains('baz');

In the code above, we called the contains method on the classList property to check if the baz class is rendered in the p element.

Since we didn’t add it in the HTML or with the add method, it should return false .

The classList property has the toggle method to toggle class names on and off. For instance, given the following HTML:

<button>
  toggle
</button>
<p>
  foo
</p>

We can use the button to toggle the bar class on and off as follows:

const p = document.querySelector('p');
const button = document.querySelector('button');
p.classList.add('foo');
p.classList.add('bar');

button.onclick = () => {
  p.classList.toggle('bar');
}

In the code above, we called the toggle method in the click handler to toggle the bar class on and off as we click the button. So we should see that in the HTML.

The clasList property has an array-like iterable object called the DOMTokenList object as a value. Therefore, we can use the spread operator to convert it to an array. This should convert it to an array of strings with the class names.

For instance, we can write the following code:

const p = document.querySelector('p');
p.classList.add('foo');
p.classList.add('bar');
const classArr = [...p.classList];

In the code above, we just used the spread operator to spread the classList property into an array.

Then we get that classArr is [“foo”, “bar”] .

Once we converted the DOMTokenList into an array, then we can use any array methods to manipulate the code.

The spread operator makes a copy of the original object and then spread it into an array, so we can still call the methods in the DOMTokenList to manipulate the class names as we want it.

Conclusion

Long boolean expressions with the || operator can be replaced with an array that checks if any of the items in the array matches the value that we’re checking for.

To manipulate multiple class names, we should use the classList property that’s part of a DOM element object. This way, we can add, remove, and toggle classes without having to manipulate strings and set it to the className property ourselves.

Categories
Refactoring

Cleaning Up Our JavaScript Code by Refactoring Them — Encapsulation

JavaScript is an easy to learn programming language. It’s easy to write programs that run and does something. However, it’s hard to write a piece of clean JavaScript code.

In this article, we’ll look at ways to refactor our code by encapsulating our API calls in their own React component, and use factory functions to provide polymorphism in our JavaScript code.

Encapsulate APIs in Our React Components

To decouple API calls from our components, we can call one API per component.

This way, if one API changes, it won’t break other components. It also keeps components simple because at most they use one API.

For instance, we can create components and use them as follows:

import React, { useState, useEffect } from "react";

const Person = () => {
  const [person, setPerson] = useState({});
  const getData = async () => {
    const res = await fetch("https://api.agify.io?name=michael");
    const p = await res.json();
    setPerson(p);
  };
  useEffect(() => {
    getData();
  }, []);

  return <p>{person.name}</p>;
};

const Dog = () => {
  const [dog, setDog] = useState({});
  const getData = async () => {
    const res = await fetch("https://dog.ceo/api/breeds/image/random");
    const d = await res.json();
    setDog(d);
  };
  useEffect(() => {
    getData();
  }, []);

  return <img src={dog.message} alt="" />;
};

export default function App() {
  return (
    <div className="App">
      <Person />
      <Dog />
    </div>
  );
}

In the code above, we have 2 components, each of which calls a single. The Person component calls one and Dog calls another. They only render something simple.

Then in App , we use them both at the same level. This way, we can combine them into one place without creating one large component.

If we have to share data between these components, then we can use some state management solutions like Redux or Mobx to share data in a centralized place in a way that’s decoupled from the component.

Replace Conditional with Polymorphism

Polymorphism is a provision of creating a single interface of entities to different types.

In JavaScript, there’re no interfaces, but we can still use this principle to let us create functions that returns objects of different class instances that have the same methods that we can call by calling one function instead of instantiating multiple classes ourselves and calling the methods ourselves.

For instance, we can create a factory function that instantiates multiple classes and return one by checking the arguments that we pass into the factory function.

Instead of writing:

const meow = (animal) => {
  //...
};
const bark = (animal) => {
  //...
};
if (animal === 'cat') {
  meow(animal);
}

if (animal === 'dog') {
  bark(animal);
}

We can instead create classes and instantiate them with a factory function as follows:

class Cat {
  speak() {}
}

class Dog {
  speak() {}
}

const Animal = (type) => {
  if (type === 'cat') {
    return new Cat();
  } else if (type === 'dog') {
    return new Dog();
  }
}

const cat = Animal('cat');
const dog = Animal('dog');
cat.speak();
dog.speak();

In the code above, we have 2 classes, Cat and Dog . They have the same speak method instead of the meow and bark functions.

Then we created an Animal class, which has the type parameter to let us specify the type of animal to instantiate. If the type is 'cat' , then we return a new Cat instance. If the type is 'Dog' , then we return a new Dog instance.

After that, we can use the same Animal function to create these 2 class instances and call the speak method on the returned object.

This way, we only have to depend on the Animal function rather than a bunch of different functions. So we don’t have to worry about anything other than Animal having breaking changes.

This is a commonly used principle to reduce coupling. We reduce the number of dependencies that we have to rely on to reduce coupling so that we have fewer chances of breaking our code when anything changes.

This makes our code more robust.

Conclusion

To keep our React components simple, we should break them up so that they only do one thing. One way to do that is to only have each component call a maximum of one API.

Polymorphism is also a good way to reduce coupling. We can create a factory function that instantiates classes for us and have the class include the same method names so that they implement one interface and we don’t have to worry about the implementation of those classes.

Even though JavaScript has no interfaces, we can still make sure that classes have the same methods included.