Dependency Injection

Inversion of Control

Dependency Inversion

Problems

  • Coupled Instances
  • Coupled Globals/State
  • Inability to create new instances
  • Dependency on Concretions

Coupled Instances

class JSON { /*...*/ }
class DbQueryBuilder { /*...*/ }

class ApiController {
  getUsers() {
    const db = new DbQueryBuilder();
    const users = db.query("SELECT * FROM USER;");
    return JSON.stringify(users);
  }
}

Coupled Globals/State

const jsonFormatter = JSON;

class DbQueryBuilder { /*...*/ }
const db = new DbQueryBuilder();

class ApiController {
  getUsers() {
    const users = db.query("SELECT * FROM USER;");
    return jsonFormatter.stringify(users);
  }
}

Inability to create new instances

class XMLFormatter { /*...*/ }
const jsonFormatter = JSON;
const xmlFormatter = new XMLFormatter();

class DbQueryBuilder { /*...*/ }
const db = new DbQueryBuilder();

class ApiControllerJSON {
  getUsers() {
    const users = db.query("SELECT * FROM USER;");
    return jsonFormatter.stringify(users);
  }
}

class ApiControllerXML {
  getUsers() {
    const users = db.query("SELECT * FROM USER;");
    return xmlFormatter.buildStringFrom(users);
  }
}

Depending on Concretions

// class ApiControllerJSON {
    return jsonFormatter.stringify(users);

// class ApiControllerXML {
    return xmlFormatter.buildStringFrom(users);
const formatter = YamlFormatter // will this work?

What is a Dependency

  • A collaborator
  • Some dependencies are Object-Oriented
  • Some dependencies are packages/libraries/frameworks
  • Some dependencies are language based, or system based (eg: this software depends on Mac)

Collaborators

  • Something an object needs to do a job "it depends on something"
class JSON { /*...*/ }
class DbQueryBuilder { /*...*/ }

class ApiController {
  getUsers() {
    const db = new DbQueryBuilder();
    const users = db.query("SELECT * FROM USER;");
    return JSON.stringify(users);
  }
}

OO Dependencies

  • Some dependencies are Object-Oriented
  • When writing code, we're usually talking about OO problems, but we can apply the lessons into the other problem areas.

Package Dependencies

  • Some dependencies are packages, libraries, or frameworks
{
  "name": "one-time-secret",
  ...
  "scripts": {
    "test": "TZ=UTC jest spec",
    ...
  },
  "engines": {
    "node": ">=10.0.0 <11.0.0"
  },
  "description": "Store secrets for one-time-access.",
  "dependencies": {
    "@types/winston-syslog": "^1.0.0",
    "typescript": "^3.2.2",
    ...

Platform Dependencies

  • Some dependencies are language based, or system based (eg: this software depends on Mac)
{
  "name": "one-time-secret",
  ...
  "scripts": {
    "test": "TZ=UTC jest spec",
    ...
  },
  "engines": {
    "node": ">=10.0.0 <11.0.0"
  },
  "description": "Store secrets for one-time-access.",
  "dependencies": {
    "@types/winston-syslog": "^1.0.0",
    "typescript": "^3.2.2",
    ...

What is injection?

  • Simply give the dependency to the object that needs it.
class JSON { /*...*/ }
class DbQueryBuilder { /*...*/ }

class ApiController {
  constructor(db) {
    this.db = db
  }

  getUsers() {
    const users = this.db.query("SELECT * FROM USER;");
    return JSON.stringify(users);
  }
}

function main() {
    const db = new DbQueryBuilder();
    const apiCtrl = new ApiController($db);
    return apiCtrl.getUsers();
}

Object Techniques

  • Property Injection
  • Method Injection
  • Constructor Injection

Object Techniques

  • Constructor Injection
class ApiController {
  constructor(db) {
    this.db = db
  }
}

const db = new DbQueryBuilder();
const apiCtrl = new ApiController($db);

Object Techniques

  • Method Injection
class ApiController {
  attachDatabase(db) {
    this.db = db
  }
}

const db = new DbQueryBuilder();

const apiCtrl = new ApiController();
apiCtrl.attachDatabase(db)

Object Techniques

  • Property Injection
class ApiController {}

const db = new DbQueryBuilder();

const apiCtrl = new ApiController();
apiCtrl.db = db;

Package Techniques

  • Acyclic Dependencies Principle (ADP)
  • Stable-Dependencies Principle (SDP)

Acyclic Dependencies Principle (ADP)

  • There can be no cycles in the dependency structure
  • When an incremental release is made, developers can adopt it without a reworking the entire project.

Stable-Dependencies Principle (SDP)

  • Package design needs to support change.
  • Difficult to change parts of the code should not have volatile dependencies.

Containers

  • Uses
  • Instances
  • Factories
  • Magic
  • Graph interception

Containers

  • Uses

Containers

  • Instances

Containers

  • Factories

Containers

  • Magic

Containers

  • Graph interception

Complex Situations

  • Depending on multiple instances
  • Not using IoC, finding your dependency graph
  • Nested and Scoped dependencies

Complex Situations

  • Depending on multiple instances

Complex Situations

  • Not using IoC, finding your dependency graph

Complex Situations

  • Nested and Scoped dependencies

Testing

  • Test contracts of dependencies
  • Test Behaviours of classes

Testing

  • Test contracts of dependencies

Testing

  • Test Behaviours of classes
    • Don't mix test cases with prod code

Refactoring

  • Factories are a nice way to move towards DI without a container
  • Factories that preserve an instance
  • Alter constructors or use method injection if needed.

Refactoring

  • Factories are a nice way to move towards DI without a container

Refactoring

  • Factory with a provider that preserves an instance

Refactoring

  • Alter constructors or use method injection if needed.

Mistakes

  • Massive DI file
  • Not depending on Interfaces
  • Not keep dependencies per class low
  • Injecting some things but not others
  • Circular dependencies
  • When you don't get an advantage from it
  • Decorators Everywhere
  • Large apps, no lazy-instances.
  • DependencyInjectable base class

Mistakes

  • Massive DI file

Mistakes

  • Not depending on Interfaces

Mistakes

  • Not keep dependencies per class low

Mistakes

  • Injecting some things but not others

Mistakes

  • Circular dependencies

Mistakes

  • When you don't get an advantage from it

Mistakes

  • Decorators Everywhere

Mistakes

  • Large apps, no lazy-instances.

Mistakes

  • DependencyInjectable base class

Interviews

  • What is Dependency Injection?
  • Provide an Example
  • Difference between DI and IoC ?

Dependency Injection

By Brian Graham

Dependency Injection

  • 574