create account

CBAC #3a/Dependency Injection/ by jakipatryk

View this thread on: hive.blogpeakd.comecency.com
· @jakipatryk · (edited)
$64.47
CBAC #3a/Dependency Injection/
#### What Will I Learn?
- Dependency Injection as a pattern
- Dependency Injection in Angular

#### Requirements
- just previous parts of the course

#### Difficulty
- intermediate

___
# Dependency Injection
>"Dependency Injection" is a 25-dollar term for a 5-cent concept.
<sub>~<b>James Shore</b>, source: <a href="http://www.jamesshore.com/Blog/Dependency-Injection-Demystified.html">jamesshore.com</a></sub>

![image.png](https://res.cloudinary.com/hpiynhbhq/image/upload/v1516245353/zulishlnwegphqwhw1lc.png)

**You might have already heard the term Dependency Injection or briefly DI... and chances are you found it difficult. It turns out that DI as a pattern is really simple and its implementation in Angular doesn't harm developers.**
## Why?
Before I describe what DI is, let me tell you why do we need it. Look at this code:
```
class Rocket {
	private engine: Engine;
	private propellantTank: PropellantTank;
	constructor() {
		this.engine = new Engine();
		this.propellantTank= new PropellantTank();
	}
	startEngine() {
		this.engine.start();
		console.log('Engine has just started!');
	}
}
```
This class is bad and it doesn't use DI. The constructor knows exactly how to create all dependencies. That's bad. 

First of all, it makes a class **hard to test**. This approach causes it almost impossible to mock out the dependencies when writing your unit test.  All developers want to write easy to test code. 

You can also imagine what would happen if you wanted to create an object using this class, but instead of Engine, you would want to use a SuperEngine version of the engine. As long as all dependencies are created inside the class, you lose the possibility to do so. As you can see, our class is not only untestable but also **inflexible**.

What can we do then? There is a solution - the class should **ask for dependencies** it needs instead of creating them inside.

And here comes DI as a pattern.
## How?
Let's refactor the Rocket class:
```
class Rocket {
	private engine: Engine;
	private propellantTank: PropellantTank;
	constructor(engine, propellantTank) {
		this.engine = engine;
		this.propellantTank = propellantTank;
	}
	startEngine() {
		this.engine.start();
		console.log('Engine has just started!');
	}
}
```
Now we can create an object based on this class in order to test:
```
const testRocket = new Rocket(new MockEngine(), new MockPropellantTank());
```
or more powerful version of rocket using SuperEngine:
```
const falcon9 = new Rocket(new SuperEngine(), new PropellantTank());
```
As you can see, we told the constructor of this class that all it needs are three dependencies. However, our class doesn't know how they were created. We have moved the responsibility to create them to the outside world. And that's the pattern called **Dependency Injection**. Yeah, it's as simple as that!
## DI as a framework
We are happy because our Rocket class is now awesome. But we haven't really thought of its consumers yet. What if Rocket would require more dependencies to work? For developers, it would be complicated to create all of them each time they wanted to use new Rocket. And here comes **DI as a framework**.

It turns out that it can solve all of our problems - the Rocket class won't care how to create dependencies it needs and the consumer won't care how to create the Rocket. How? Imagine this code was real:
```
const injector = new Injector();
let saturnV = injector.get(Rocket);
saturnV.startEngine();
```
It would be definitely awesome if we could do that! 
## Services in Angular
We have already introduced DI both as a pattern and framework. Now it's time to take a look how to use DI framework built in Angular to inject services.

Let a fragment of TaskService be our example (note that the entire code is available on [Github](https://github.com/jakipatryk/angular-todo-list-tutorial/tree/tutorial-part-3), but the part which will contain explanation what is going on inside service's methods is gonna be in the next tutorial - 3b).
```
@Injectable()
export class TaskService {
  constructor(private afs: AngularFirestore, private afAuth: AngularFireAuth) {}
  getTask(taskId: string, userId: string) {
    return this.afs.doc<Task>(`users/${userId}/tasks/${taskId}`);
  }
}
```
As you can see, TaskService needs two dependencies, AngularFirestore and AngularFireAuth, but we moved the responsibility to deliver them to the external parts of the app. 

But how does Angular know that some external dependencies are needed to be injected into the constructor of a class? The answer is simple: **Angular doesn't know until we tell him**. How can we force the framework to look at the constructor and deliver us the required dependencies?

It turns out that Angular injects dependencies declared in the class constructor only if the class has a decorator, for example `@Injectable()` or `@Component()`. To prove I'm not lying and every class which has a decorator can have some dependencies injected into its constructor, look at the following AppComponent fragment:
```
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
  constructor(private taskService: TaskService, private authService: AuthService) {}
}
```
Ok, we now know that Angular somehow injects the dependencies from class constructor if the class has a decorator. But how does it know which instance of dependency should be injected? The answer is a bit tricky, and to understand what's going on I have to introduce **providers**. 

### Providers
I'm sure you have already heard about them. *Nah, @jakipatryk, I have not*. If you haven't, then go back to the [2nd part of the CBAC](https://utopian.io/utopian-io/@jakipatryk/cbac-2-at-the-beginning-there-was-chaos) where I told you that `@NgModule()` takes some configuration options. One of them was an array of `providers`, which I described as *a perfect place to put your services*.

I wasn't lying, `providers` array is really a perfect place to put some services. The interesting fact is that not only modules have such an option. We could also add services directly to the `@Component()`:
```
@Component({
  selector: 'app-root',
  providers: [TaskService, AuthService],
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
  constructor(private taskService: TaskService, private authService: AuthService) {}
}
```
What is the difference?  The place where you register a service is crucial.
In case you did it in `@Component()`, your service will have limited **lifetime** and **scope**. Its instance will only exist within the lifetime of a component. If you decide to put your service into `@NgModule()`, the instance of this service will exist within the lifetime of the app. 

But what are **providers**? One of the definitions is that provider describes how the `Injector` should be configured. To understand it better you have to realize that the providers array you saw earlier is just a shorthand syntax:
```
providers: [TaskService, AuthService]
```
is actually the same as this:
```
providers: [{ provide: TaskService, useClass: TaskService }, { provide: AuthService, useClass: AuthService }
```
Now it is more clear that injector whenever needs TaskService or AuthService have a point to go to check what it exactly needs to use. 

Also, services are **singletons** only within the scope of the injector. It implies that the scope of service depends on the place where it has been registered. I haven't mentioned yet that there is one **root injector** that is being created during the bootstrap of the app. However, there are also being created **injectors for each instance** of,  for example a component that has providers in its configuration options. 

## Summary
In this tutorial I have described Dependency Injection as a pattern and then as a framework. I have also touched on the Angular's own DI system and services. As always, more on these topics can be found in the references section.

## References:
**DI pattern:**
- [Angular documentation](https://angular.io/guide/dependency-injection-pattern)
- [Inversion of Control Containers and the Dependency Injection pattern](https://martinfowler.com/articles/injection.html#ServiceLocatorVsDependencyInjection) by Martin Fowler

**DI in Angular:**
- [Angular documentation](https://angular.io/guide/dependency-injection)
___
#### Curriculum
- [Setting up our project](https://utopian.io/utopian-io/@jakipatryk/community-based-angular-course-from-scratch-setting-up-our-project)
- [At the beginning there was chaos](https://utopian.io/utopian-io/@jakipatryk/cbac-2-at-the-beginning-there-was-chaos)

<center>
<p><sub>Do you like <b>S</b>cience, <b>T</b>echnology, <b>E</b>ngineering or <b>M</b>athematics? Check out #steemSTEM!</sub></p>
</center>

<br /><hr/><em>Posted on <a href="https://utopian.io/utopian-io/@jakipatryk/cbac-3a-dependency-injection">Utopian.io -  Rewarding Open Source Contributors</a></em><hr/>
👍  , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,
properties (23)
authorjakipatryk
permlinkcbac-3a-dependency-injection
categoryutopian-io
json_metadata{"community":"utopian","app":"utopian/1.0.0","format":"markdown","repository":{"id":24195339,"name":"angular","full_name":"angular/angular","html_url":"https://github.com/angular/angular","fork":false,"owner":{"login":"angular"}},"pullRequests":[],"platform":"github","type":"tutorials","tags":["utopian-io","steemstem","angular","programming","javascript"],"users":["Injectable","Component","jakipatryk","NgModule"],"links":["https://res.cloudinary.com/hpiynhbhq/image/upload/v1516245353/zulishlnwegphqwhw1lc.png","https://github.com/jakipatryk/angular-todo-list-tutorial/tree/tutorial-part-3","https://utopian.io/utopian-io/@jakipatryk/cbac-2-at-the-beginning-there-was-chaos","https://angular.io/guide/dependency-injection-pattern","https://martinfowler.com/articles/injection.html#ServiceLocatorVsDependencyInjection","https://angular.io/guide/dependency-injection","https://utopian.io/utopian-io/@jakipatryk/community-based-angular-course-from-scratch-setting-up-our-project"],"image":["https://res.cloudinary.com/hpiynhbhq/image/upload/v1516245353/zulishlnwegphqwhw1lc.png"],"moderator":{"account":"manishmike10","time":"2018-01-18T13:52:29.628Z","reviewed":true,"pending":false,"flagged":false}}
created2018-01-18 03:36:06
last_update2018-01-18 17:00:51
depth0
children2
last_payout2018-01-25 03:36:06
cashout_time1969-12-31 23:59:59
total_payout_value45.756 HBD
curator_payout_value18.709 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length9,058
author_reputation14,313,610,947,295
root_title"CBAC #3a/Dependency Injection/"
beneficiaries
0.
accountutopian.pay
weight2,500
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id30,308,880
net_rshares9,626,285,536,502
author_curate_reward""
vote details (57)
@manishmike10 ·
$0.07
Thank you for the contribution. It has been approved.
* Please remove the banner at the bottom and all the mentions in the post to avoid rejection.
You can contact us on [Discord](https://discord.gg/uTyJkNm).
**[[utopian-moderator]](https://utopian.io/moderators)**
👍  
properties (23)
authormanishmike10
permlinkre-jakipatryk-cbac-3a-dependency-injection-20180118t135312318z
categoryutopian-io
json_metadata{"tags":["utopian-io"],"community":"utopian","app":"utopian/1.0.0"}
created2018-01-18 13:53:12
last_update2018-01-18 13:53:12
depth1
children0
last_payout2018-01-25 13:53:12
cashout_time1969-12-31 23:59:59
total_payout_value0.052 HBD
curator_payout_value0.013 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length265
author_reputation20,399,732,899,016
root_title"CBAC #3a/Dependency Injection/"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id30,399,466
net_rshares8,210,498,984
author_curate_reward""
vote details (1)
@utopian-io ·
### Hey @jakipatryk I am @utopian-io. I have just upvoted you!
#### Achievements
- You have less than 500 followers. Just gave you a gift to help you succeed!
- You are generating more rewards than average for this category. Super!;)
- Seems like you contribute quite often. AMAZING!
#### Suggestions
- Contribute more often to get higher and higher rewards. I wish to see you often!
- Work on your followers to increase the votes/rewards. I follow what humans do and my vote is mainly based on that. Good luck!
#### Get Noticed!
- Did you know project owners can manually vote with their own voting power or by voting power delegated to their projects? Ask the project owner to review your contributions!
#### Community-Driven Witness!
I am the first and only Steem Community-Driven Witness. <a href="https://discord.gg/zTrEMqB">Participate on Discord</a>. Lets GROW TOGETHER!
- <a href="https://v2.steemconnect.com/sign/account-witness-vote?witness=utopian-io&approve=1">Vote for my Witness With SteemConnect</a>
- <a href="https://v2.steemconnect.com/sign/account-witness-proxy?proxy=utopian-io&approve=1">Proxy vote to Utopian Witness with SteemConnect</a>
- Or vote/proxy on <a href="https://steemit.com/~witnesses">Steemit Witnesses</a>

[![mooncryption-utopian-witness-gif](https://steemitimages.com/DQmYPUuQRptAqNBCQRwQjKWAqWU3zJkL3RXVUtEKVury8up/mooncryption-s-utopian-io-witness-gif.gif)](https://steemit.com/~witnesses)

**Up-vote this comment to grow my power and help Open Source contributions like this one. Want to chat? Join me on Discord https://discord.gg/Pc8HG9x**
properties (22)
authorutopian-io
permlinkre-jakipatryk-cbac-3a-dependency-injection-20180118t153739597z
categoryutopian-io
json_metadata{"tags":["utopian-io"],"community":"utopian","app":"utopian/1.0.0"}
created2018-01-18 15:37:39
last_update2018-01-18 15:37:39
depth1
children0
last_payout2018-01-25 15:37:39
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length1,583
author_reputation152,955,367,999,756
root_title"CBAC #3a/Dependency Injection/"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id30,420,789
net_rshares0