Dependency Injection with Doug the Goldfish 🐠
Tags: javascript, webdev, tutorial, typescript
Published: 2021-01-26 23:14:14

There are lots of great strategies to keep code manageable and extensible.  Today, let's learn about "Dependency Injection". 

# Dependency Injection

Imagine you're a goldfish named Doug (🐠), and you love bubbles.  So much so, that you bought a Bubble Machine with a programmable Typescript SDK.

You write a program to make bubbles when you wake up:

```typescript
import { Bubbler } from 'bubbler';
const initBubbler = () => {

  //  Instantiate
  const bubbler = new Bubbler({ id: "dougs-bubbler" });

  //  Start the Bubbler
  bubbler.bubble({ startTime: "7:00AM", endTime: "8:00AM" })
}
initBubbler();
```

Great, now you awaken to fresh, well-oxygenated water 💦

You tell your friend Mary (🐟), and she's so excited, she buys a bubbler too.

You update the code to initialize both bubblers:


```typescript
import { Bubbler } from 'bubbler';

const initDougsBubbler = () => {
  const bubbler = new Bubbler({ id: "dougs-bubbler" });
  bubbler.bubble({ startTime: "7:00AM", endTime: "8:00AM" })
}

const initMarysBubbler = () => {
  const bubbler = new Bubbler({ id: "marys-bubbler" });
  bubbler.bubble({ startTime: "7:00AM", endTime: "8:00AM" })
}

initDougsBubbler();
initMarysBubbler();
```

It works, but there's something... fishy... going on here...

Instead of duplicating the `initBubbler` function, you could have "hoisted" the instantiation step outside the function:

```typescript
import { Bubbler } from 'bubbler';

const dougsBubbler = new Bubbler({ id: "dougs-bubbler" });
const marysBubbler = new Bubbler({ id: "marys-bubbler" });

const initBubbler = (bubbler) => { 
  bubbler.bubble({ startTime: "7:00AM", endTime: "8:00AM" })
}

initBubbler(dougsBubbler);
initBubbler(marysBubbler);
```

Now, we only need the single `initBubbler` function, even if your friends Larry (🐙) and Barry (🐡) decide to buy Bubblers too.

The `initBubbler` function is no longer responsible for constructing a `bubbler` instance.  Instead, it's **injected** into the function from the outer scope.  This pattern is called "Dependency Injection" (DI).

>  Dependency Injection is a great way to keep your functions simple, modular, and re-usable by delegating responsibility to the caller.

### Inversion of Control
Further, because the "caller" is now responsible for initializing the Bubbler (instead of the `initBubbler` function), we say control has been "inverted".  Dependency Injection is a means by which to achieve "Inversion of Control" (IoC).

### IoC Container

The outer scope, responsible for instantiating the `bubbler` dependency, is called the "Inversion of Control Container" (IoC Container).

### DI Frameworks

You can use a "DI Framework" to make things even easier.  Instead of manually initializing the dependencies, a DI Framework acts as the IoC Container and does the work for you.

You just tell the framework which dependencies your function needs, and once they're initialized, the framework automatically invokes your function.

Angular and Nest are two popular tools that include DI Frameworks.  Both of these helped in the writing of this article and shaping my own understanding of DI:
- Angular:  https://angular.io/guide/providers
- Nest:  https://docs.nestjs.com/fundamentals/custom-providers

### Plugins

DI Frameworks are great for keeping code organized.  However, I like to go one step further and build a module for every "Feature" in my app. 

When the DI Framework initializes the "Feature Module", it "installs" itself by invoking dependency methods.  It then exports its own API for dependencies to install themselves.

We call call these modules "Plugins", because they inject functionality back into the app.

> By building apps as a "Tree of Plugins", feature code is centralized instead of being spread throughout the app. 

This makes it easy to mix and match features, build new features, and even open your app for extension by external developers (like Wordpress does).

To learn more about building apps as a tree of Plugins, check out my new package "Halia":

[Halia - Extensible TS / JS Dependency Injection Framework](https://github.com/CodalReef/Halia)

> Halia is a simple, lightweight, and extensible DI Framework.  It's not tied to a particular backend / frontend technology, and you can customize the framework by installing "Plugins".


## Conclusion
We hope your time spent as Doug has helped you see value in the DI Pattern and DI Frameworks.

If you'd like, you can stop imagining you're a goldfish and resume normal human function.

Or, you can imagine you’re a duck and learn how to build Pluggable Apps:

[Build Pluggable Apps with Lenny the Duck 🦆](https://dev.to/codalreef/pluggable-apps-with-lenny-the-duck-2oj3)

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/d860i5k7g5txl2ycrudr.jpg)

All thoughts and comments are greatly appreciated =)

Cheers,
CR

*For more articles like this, follow me on:  [Github](https://github.com/CodalReef), [Dev](https://dev.to/codalreef), [Twitter](https://twitter.com/CodalReef), [Reddit](https://www.reddit.com/user/CodalReef)*