Categories
Refactoring

JavaScript Refactoring — 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 classes.

Inline Class

We start with 2 classes and roll them into one. It’s the reverse of the previous refactoring.

For instance, instead of writing:

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

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

We roll the code for the PhoneNumber class back into the Person class as follows:

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

We may want to do this if the class that we separated out isn’t that complex.

In the code above, we have the PhoneNumber class that has no methods, so we can just roll it into the Person class since phoneNumber is a property that a Person instance can have.

Hide Delegate

We can create methods on the client class to hide the underlying implementation of the code by filling the method class with code that gets the value we want directly.

This reduces the coupling of our code for getting the item that we want.

For instance, instead of writing the following:

class Department {
  constructor(name, deptHead) {
    this.name = name;
    this.deptHead = deptHead;
  }

  getDeptHead() {
    return deptHead;
  }
}

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

  getDept() {
    return this.dept;
  }
}

const deptHead = new Person('jane');
const dept = new Department('customer service', deptHead);
const employee = new Person('joe', dept);
const manager = employee.getDept().getDeptHead();

which requires us to get the department first before getting the department head as we did on the last line.

We can write the following:

class Department {
  constructor(name, deptHead) {
    this.name = name;
    this.deptHead = deptHead;
  }
}

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

  getDept() {
    return this.dept;
  }

  getDeptHead() {
    return this.dept.deptHead;
  }
}

const deptHead = new Person('jane');
const dept = new Department('customer service', deptHead);
const employee = new Person('joe', dept);
const manager = employee.getDeptHead();

All we did was to add the getDeptHead method to person to get the department head from the department directly.

Then we don’t have to get the department first to get the department head, which reduces coupling between the Person and Department class.

Introduce Foreign Method

We can add a foreign method to a class that we can’t modify directly by adding methods to it with Object.assign .

For instance, we can write the following:

class Foo {
  //...
}

const mixin = {
  bar() {
    //...
  }
}

Object.assign(Foo.prototype, mixin)

In the code above, we added the bar instance method to Foo by calling Object.assign , given the Foo is a class that we can’t modify.

Introduce Local Extension

In addition to adding new methods to a class directly, we can create new class with extra methods that we want to call by making a class with the methods a subclass of the class that we can’t modify directly.

For instance, we can write the following:

class Foo {
  //...
}

class Bar extends Foo {
  bar() {
    //...
  }
}

In the code above, we created a subclass of Foo that has the methods that we want to call, where Foo is a class that we can’t change.

Now we don’t have to modify Foo by adding things to its prototype.

Self Encapsulate Field

We can add getters and setters methods to a field that we access directly so that we can encapsulate it.

For example, instead of writing the following:

class Counter {
  inRange(arg) {
    return arg >= this._low && arg <= this._high;
  }
}

We write:

class Counter {
  inRange(arg) {
    return arg >= low() && arg <= high();
  }

  get low() {
    return this._low;
  }

  get high() {
    return this._high;
  }
}

This lets us encapsulate fields and we can also apply other operations to it without access to the high and low fields and applying operations to them directly.

Conclusion

We can move members in classes that don’t do much into another class so that we can remove the class that doesn’t do much.

To reduce coupling between classes, we can methods to directly get what we want instead of having to do that in a roundabout manner.

We can encapsulate fields so that we can get a value and do something before it before the value we returned.

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.