Unobtrusive Dependency Injection with JavaScript

Why and how?

about:nfroidure

Web Platform Architect @sencrop

 

Building softwares for Lille's innovative startups since JavaScript is a hot topic.

 

Almost passed the Rust compiler checks once.

 

Blog & Tweet randomly

is hiring

Frontend / Backend developers

Data scientists
Embedded software engineers

Definition

The Dependency Injection pattern aims to provide the states some code depends on from some external code.

 

That way, the actual code is completely decoupled from its own dependencies implementation / initialization.

 

Dependency Injection on Wikipedia

In JS please

// With Classes
class User {
  constructor(db, log) {
    this.db = db;
    this.log = log;
  }
  async delete() {
    const result = await this.db.query('DELETE FROM users WHERE id = $id', { id });

    if (result.deletedRows) {
      this.log(`User ${id} has been deleted!`);
    }
  }
}

// With functions
async function deleteUser(db, log, id) {
  const result = await db.query('DELETE FROM users WHERE id = $id', { id });

  if (result.deletedRows) {
    log(`User ${id} has been deleted!`);
  }
}

App Lifecycle 101

Dependency Injection flow

Opinion

The Dependency Injection pattern is the only one you will never regret to implement.

 

If you do it with OOP do not blame DI.

Why?

Testable

Easy unit testing thanks to mocks and stubs.

Configurable

One can easily replace a dependency per another with no effort.

Manageable

Reasoning on limited scopes helps decreasing the cognitive load.

Reusable

By being more independent and modular, services can easily be reused in different contexts.

Optimal

By automating the process initialization boilerplate, the injector guarantees best performances and reliability (parallelization, no dead lock).

Instrumentable

Since well defined and isolated, an application using DI is extremely customizable and maleable.  

Any downsides?

Debugging / tracing

It is simpler to debug a code that instantiate its own dependencies.

Static Typing

The injector creates dependencies dynamically so some advantages of static typing may fall apart.

Hands on!

Creating a simple CLI app from scratch

The problems

  • Cannot reuse the db / FTP services 
  • Testing would be a pain (mockery)
  • Cannot replace FTP per S3 easily
  • Any new service requires a refactoring
    of the boot sequence

⚠ Self Promotion ⚠ 

Knifecycle

The Dependency Injection banana without the gorilla nor the jungle and the rest of the world. 

Refactoring

  • Declare dependencies
  • Instantiate the injector
  • Run it with root dependencies

Alternatives

If you really want the gorilla, the jungle and the rest of the world, you may like to use the container-ioc library or the Angular and Nest frameworks that integrates their own DI systems. They fully rely on OOP and decorators fancy.

Going further

Autoload dependencies

Avoid boilerplate by automating the way your dependencies are loaded.

Generate graphs

Source: jsarch

Create a static build

Knifecycle offers the ability to create static builds. This is how we're bundling our serverless functions at Sencrop.

 

Creating a static build solves the DI downsides we saw earlier.

Build HTTP servers

Knifecycle were initially built for building HTTP servers and led to the Swagger HTTP Router project soon packaged in the Whook framework.

Ready to use services

Built with Knifecycle

Thanks! Questions?

Changes done

Summary of changes done during the talk: