5 Anti-Patterns to Avoid When Working With Collections in JavaScript
Tags: javascript, node, webdev
Published: 2019-12-07 16:15:31

Find me on [medium](https://medium.com/@jsmanifest)

Working with collections in JavaScript can become an appalling task especially when there is a lot going on in a function block.

Have you ever wondered _how_ some projects in code look much nicer than others? Or when a seemingly difficult project ends up being so small your mind just goes off in a wild ride wondering just how they were able to keep it simple and robust at the same time?

When a project is easy to read while maintaining good performance you can be ensured that there's likely pretty good practices applied to the code.

It can easily become the contrary when code is written like a mess. At this point it's easy to get in a situation where modifying small bits of code ends up causing catastrophic problems to your application--in other words an error thrown that crashes a web page from continuing further. When iterating over collections it can become scary to watch bad code run.

Enforcing better practices is about inhibiting yourself from taking short directions which in turn helps to secure guarantees. This means that it depends on _you_ to make your code as maintainable as possible in the long run.

This article will go over 5 anti-patterns to avoid when working with collections in JavaScript

A lot of the code examples in this article will embody a programming paradigm called [_functional programming_](https://en.wikipedia.org/wiki/Functional_programming). Functional programming, as _Eric Elliot_ explains it, _"is the process of building software by composing pure functions, avoiding shared state, mutable data, and side-effects."_. We will often mention side effects and mutation in this post.

Here are \_\_\_ Anti-Patterns in JavaScript to Avoid When Working With Collections:

## 1. Prematurely passing functions as direct arguments

The first anti-pattern that we will be going over is prematurely passing functions as a direct argument to array methods that loop over collections.

Here is a simple example of that:

```js
function add(nums, callback) {
  const result = nums[0] + nums[1]
  console.log(result)
  if (callback) {
    callback(result)
  }
}

const numbers = [[1, 2], [2, 2], [18, 1], [4, 5], [8, 9], [0, 0]]

numbers.forEach(add)
```

So why's this an anti-pattern?

Most developers especially those who are more into functional programming may find this to be clean, concise and performant at its best. I mean, just look at it. Instead of having to do this:

```js
const numbers = [[1, 2], [2, 2], [18, 1], [4, 5], [8, 9], [0, 0]]

numbers.forEach(function(nums, callback) {
  const result = nums[0] + nums[1]
  console.log(result)
  if (callback) {
    callback(result)
  }
})
```

It's seemingly much nicer to just throw in the name of the function and call it a day:

```js
const numbers = [[1, 2], [2, 2], [18, 1], [4, 5], [8, 9], [0, 0]]

numbers.forEach(add)
```

In a perfect world, this would be the perfect solution to work with all of our functions in JavaScript without ever having to break a sweat.

But it turns out that prematurely passing your handlers this way can cause unexpected errors. For example, lets go ahead and look back into our previous example:

```js
function add(nums, callback) {
  const result = nums[0] + nums[1]
  console.log(result)
  if (callback) {
    callback(result)
  }
}

const numbers = [[1, 2], [2, 2], [18, 1], [4, 5], [8, 9], [0, 0]]

numbers.forEach(add)
```

Our `add` function expects an array where the first and second indexes are numbers and adds them and checks if there is a callback, invoking it if it exists. The problem here is that `callback` could end up being invoked as a `number` and will result in an error:

![add function error crash](https://jsmanifest.s3-us-west-1.amazonaws.com/posts/5-anti-patterns-in-javascript-to-avoid-when-working-with-collections/add+callback+error+crash.jpg)

## 2. Relying on the ordering of iterator functions like `.map` and `.filter`

JavaScript's basic functions process elements in collections in the order they're currently at in the array. However, your code should _not_ depend on this.

First, the ordering of iteration is never 100% stable in every language nor in every library. It's a good practice to treat every iteratee function as if they are run concurrently in multiple processes.

I've seen code that do something like this:

```js
let count = 0

frogs.forEach((frog) => {
  if (count === frogs.length - 1) {
    window.alert(
      `You have reached the last frog. There a total of ${count} frogs`,
    )
  }
  count++
})
```

In _most_ situations this is perfectly fine, but if we look closely it's not the safest approach to take as anything in the global scope can update `count`. If this happens and `count` ends up being decremented accidentally somewhere in the code, then `window.alert` will _never_ be able to run!

It can get even worse when working in asynchronous operations:

```js
function someAsyncFunc(timeout) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve()
    }, timeout)
  })
}

const promises = [someAsyncFunc, someAsyncFunc, someAsyncFunc, someAsyncFunc]

let count = 0
promises.forEach((promise) => {
  count++
  promise(count).then(() => {
    console.log(count)
  })
})
```

The result:

![promises in count](https://jsmanifest.s3-us-west-1.amazonaws.com/posts/5-anti-patterns-in-javascript-to-avoid-when-working-with-collections/promises+with+count.jpg)

Those of you who are more experienced in JavaScript will probably know why we get _four_ number `4`'s logged to the console and not `1, 2, 3, 4`. The point is that it's a better to use the second argument (commonly referred to as the current `index`) that most functions receive when iterating over collections to avoid concurrency:

```js
promises.forEach((promise, index) => {
  promise(index).then(() => {
    console.log(index)
  })
})
```

The result:

![promises in native index](https://jsmanifest.s3-us-west-1.amazonaws.com/posts/5-anti-patterns-in-javascript-to-avoid-when-working-with-collections/promises+with+native+index.jpg)

## 3. Optimizing Prematurely

When you're looking to optimize what usually comes in between is your decision in choosing whether to prefer readability or speed. Sometimes it can become _really_ tempting to put more attention to optimizing your app's speed instead of improving the readability of your code. After all, it's a widely accepted truth that [speed in websites matter](https://www.cloudflare.com/learning/performance/why-site-speed-matters/). But this is actually a _bad practice_.

For one, collections in JavaScript are usually smaller than you'd think, and the time it takes it to process every operation is also faster than you'd think as well. A good rule to follow here is that unless you _know_ something is going to be slow, don't try to make it faster. This is called _Premature Optimization_, or in other words, attempting to optimize code that is possibly already most optimal in speed.

As [Donald Knuth](https://en.wikipedia.org/wiki/Donald_Knuth) puts it, "The real problem is that programmers have spent far too much time worrying about efficiency in the wrong places and at the wrong times; _premature optimization is the root of all evil_ (or at least most of it) in programming.".

In a lot of situations it's easier to apply some better speed where the code ends up being a little slower than it is having to stress out maintaining a fast working code in a tangled mess.

I recommend to prefer readability, and then proceeding to measure. If you use a profiler and it reports a bottleneck in your application, optimize that bit only because now you _know_ its actually a slow code, as opposed to _attempting_ to optimize code where you _think_ it could be slow.

## 4. Relying on state

_State_ is a very important concept in programming because it is a concept that enables us to build robust applications but it can also _break_ our applications if we don't watch ourselves enough.

Here is an example of an anti-pattern when working with state in collections:

```js
let toadsCount = 0

frogs.forEach((frog) => {
  if (frog.skin === 'dry') {
    toadsCount++
  }
})
```

This is an example of a [_side effect_](https://hackernoon.com/javascript-and-functional-programming-pt-3-pure-functions-d572bb52e21c), something definitely to watch out for as it can cause problems like:

- Producing unexpected side effects (_Really_ dangerous!)
- Increasing memory usage
- Reducing your app's performance
- Making your code harder to read/understand
- Making it harder to test your code

So what's a better way to write this without causing a side effect? Or how can we rewrite this using a better practice?

When working with collections and we need to work with state during the operation, remember that we can utilize certain methods that _provide you with a fresh new reference_ of something (like objects).

An example is using the `.reduce` method:

```js
const toadsCount = frogs.reduce((accumulator, frog) => {
  if (newFrog.skin === 'dry') {
    accumulator++
  }
  return accumulator
}, 0)
```

So what's happening here is that we're interacting with some state _inside its block_ but we also utilize the second argument to `.reduce` where the value can be newly created upon initialization. This is using a better approach than the previous snippet because we're not mutating anything _outside of the scope_. This makes our `toadsCount` an example of working with immutable collections and _avoiding side effects_.

## 5. Mutating Arguments

To _mutate_ something means to change in form or in nature. This is an important concept to pay close attention to in JavaScript especially in the context of functional programming. Something that is mutable can be changed while something that is immutable _cannot_ (or _should not_) be changed.

Here's an example:

```js
const frogs = [
  { name: 'tony', isToad: false },
  { name: 'bobby', isToad: true },
  { name: 'lisa', isToad: false },
  { name: 'sally', isToad: true },
]

const toToads = frogs.map((frog) => {
  if (!frog.isToad) {
    frog.isToad = true
  }
  return frog
})
```

We're expecting the value of `toToads` to return a new array of `frogs` that were all converted to toads by flipping their `isToad` property to `true`.

But this is where it becomes a little chilling: When we mutated some of the `frog` objects by doing this: `frog.isToad = true`, we _also unintentionally mutated_ them inside the `frogs` array!

We can see that `frogs` are now all _toads_ because it was mutated:

![mutating collections](https://jsmanifest.s3-us-west-1.amazonaws.com/posts/5-anti-patterns-in-javascript-to-avoid-when-working-with-collections/mutating+collections.jpg)

This happens because _objects in JavaScript are all passed by references_! What if we assigned the _same_ object around in 10 different places in code?

If we for example were assigning this reference to 10 different variables throughout our code, then mutated variable 7 at some point later in the code, _all_ of the other variables that hold a reference to this same pointer in memory will _also be mutated_:

```js
const bobby = {
  name: 'bobby',
  age: 15,
  gender: 'male',
}

function stepOneYearIntoFuture(person) {
  person.age++
  return person
}

const doppleGanger = bobby
const doppleGanger2 = bobby
const doppleGanger3 = bobby
const doppleGanger4 = bobby
const doppleGanger5 = bobby
const doppleGanger6 = bobby
const doppleGanger7 = bobby
const doppleGanger8 = bobby
const doppleGanger9 = bobby
const doppleGanger10 = bobby

stepOneYearIntoFuture(doppleGanger7)

console.log(doppleGanger)
console.log(doppleGanger2)
console.log(doppleGanger4)
console.log(doppleGanger7)
console.log(doppleGanger10)

doppleGanger5.age = 3

console.log(doppleGanger)
console.log(doppleGanger2)
console.log(doppleGanger4)
console.log(doppleGanger7)
console.log(doppleGanger10)
```

Result:

![mutating arguments bobby age](https://jsmanifest.s3-us-west-1.amazonaws.com/posts/5-anti-patterns-in-javascript-to-avoid-when-working-with-collections/mutating-arguments-bobby-age.jpg)

What we can do instead is to create new references each time we want to mutate them:

```js
const doppleGanger = { ...bobby }
const doppleGanger2 = { ...bobby }
const doppleGanger3 = { ...bobby }
const doppleGanger4 = { ...bobby }
const doppleGanger5 = { ...bobby }
const doppleGanger6 = { ...bobby }
const doppleGanger7 = { ...bobby }
const doppleGanger8 = { ...bobby }
const doppleGanger9 = { ...bobby }
const doppleGanger10 = { ...bobby }
```

Result:

![mutating arguments bobby age immutable](https://jsmanifest.s3-us-west-1.amazonaws.com/posts/5-anti-patterns-in-javascript-to-avoid-when-working-with-collections/mutating-arguments-bobby-age-immutable.jpg)

## Conclusion

And that concludes the end of this post! I found you found this to be valuable and look out for more in the future!

Find me on [medium](https://medium.com/@jsmanifest)