# Wtf is dependency injection? (JavaScript edition)

# Introduction

Dependency injection.

You might be using it already.

It’s straightforward and a nice way to give more control to the consumers of the functions or classes.

Let’s take a look at an example. I’ll use both classes and functions in JavaScript.

# The problematic path

Let’s say we’ve a function that always does smoothies.

So far, it’s always done them using bananas and strawberries.

```javascript
// Using functions

function makeSmoothie() {
  let banana = getBanana();
  let strawberry = getStrawberry();
  // ...blend it all together...
  return `${banana} and ${strawberry} smoothie! Yum!`;
}

function getBanana() {
  // Imagine this function goes out to a Banana farm and gets a banana
  return 'banana';
}

function getStrawberry() {
  // This function, on the other hand, visits a berry patch.
  return 'strawberry';
}
```

```javascript
// Using classes

class SmoothieMaker {
  constructor() {
    this.banana = this.getBanana();
    this.strawberry = this.getStrawberry();
  }

  getBanana() {
    // Gets banana from a specific source
    return 'banana';
  }

  getStrawberry() {
    // Gets strawberry from a specific source
    return 'strawberry';
  }

  makeSmoothie() {
    return `${this.banana} and ${this.strawberry} smoothie! Yum!`;
  }
}

const mySmoothieMaker = new SmoothieMaker();
console.log(mySmoothieMaker.makeSmoothie()); // Outputs: banana and strawberry smoothie! Yum!
```

## The problems

The above examples may seem silly, but imagine we're working in a large codebase.

The functions and classes are larger. They're used in multiple places.

We have several issues here:

* **Hard to maintain:** The code isn't flexible. Imagine we want to create smoothies using other ingredients. It's gonna be painful.
    
* **Hard to test:** Let's imagine for a second `getBanana` function is an async function that fetches a specific type of banana. In our tests, it'd be easier to mock the `getBanana` function. But now we have no ability to do so.
    

# Dependency injection to the rescue

Here is the code after dependency injection:

```javascript
// Using functions

function makeSmoothie(fruit1, fruit2) {
  // ...blend it all together...
  return `${fruit1} and ${fruit2} smoothie! Yum!`;
}

const banana = getBanana();
const strawberry = getStrawberry();
console.log(makeSmoothie(banana, strawberry)); // Banana and strawberry smoothie! Yum!
```

```javascript
// Using classes

// Define functions for fetching ingredients
function getMango() {
  return 'mango';
}

function getPineapple() {
  return 'pineapple';
}

// The SmoothieMaker now expects two functions as its dependencies
class SmoothieMaker {
  constructor(getFruit1, getFruit2) {
    this.getFruit1 = getFruit1;
    this.getFruit2 = getFruit2;
  }

  makeSmoothie() {
    let fruit1 = this.getFruit1();
    let fruit2 = this.getFruit2();
    return `${fruit1} and ${fruit2} smoothie! Yum!`;
  }
}

// When creating a new SmoothieMaker, we inject the functions directly
const mySmoothieMaker = new SmoothieMaker(getMango, getPineapple);
console.log(mySmoothieMaker.makeSmoothie()); // Outputs: mango and pineapple smoothie! Yum!
```

Now, the code is much more flexible.

This is easier to maintain, test and use.

# Conclusion

Dependency injection may be a fancy word.

But we use this pattern all the time.
