All Projects → vanilla-manifesto → vanilla-di-manifesto

vanilla-manifesto / vanilla-di-manifesto

Licence: other
We love DI, but we don't use any DI libraries. Why?

Programming Languages

javascript
184084 projects - #8 most used programming language
swift
15916 projects
typescript
32286 projects
F#
602 projects
C#
18002 projects
java
68154 projects - #9 most used programming language

Projects that are alternatives of or similar to vanilla-di-manifesto

di speed
Speed comparison of Dependency Injection Container
Stars: ✭ 18 (-83.33%)
Mutual labels:  dependency-injection
redi
💉 A dependency injection library for TypeScript & JavaScript, along with a binding for React.
Stars: ✭ 29 (-73.15%)
Mutual labels:  dependency-injection
movie-booking
An example for booking movie seat, combined of Android Data Binding, State Design Pattern and Multibinding + Autofactory. iOS version is: https://github.com/lizhiquan/MovieBooking
Stars: ✭ 80 (-25.93%)
Mutual labels:  dependency-injection
NetteAdapterForSymfonyBundles
[DEPRECATED due to only 20 downloads per 2 years] Read an article about this idea
Stars: ✭ 15 (-86.11%)
Mutual labels:  dependency-injection
BetterVanillaGenerator
This plugin not only provides better terrain generators for Nukkit, you can also customize your world by modifying the configuration.
Stars: ✭ 26 (-75.93%)
Mutual labels:  vanilla
func-dependency-injection-go
Dependency injection example using higher order functions
Stars: ✭ 26 (-75.93%)
Mutual labels:  dependency-injection
tobii
An accessible, open-source lightbox with no dependencies
Stars: ✭ 132 (+22.22%)
Mutual labels:  vanilla
Griffin.Container
Inversion of control container with (almost) zero configuration
Stars: ✭ 13 (-87.96%)
Mutual labels:  dependency-injection
sirius-kernel
Provides common core classes and the dependency injection microkernel powering all SIRIUS applications
Stars: ✭ 30 (-72.22%)
Mutual labels:  dependency-injection
ThunderboltIoc
One of the very first IoC frameworks for .Net that has no reflection. An IoC that casts its services before thunder casts its bolts.
Stars: ✭ 40 (-62.96%)
Mutual labels:  dependency-injection
linker
Dependency Injection and Inversion of Control package
Stars: ✭ 33 (-69.44%)
Mutual labels:  dependency-injection
AzureFunctions.Extensions
This provides some useful extensions for Azure Functions.
Stars: ✭ 81 (-25%)
Mutual labels:  dependency-injection
graphql-server-typed
Using typescript and gql-code-gen for easy graphql setup
Stars: ✭ 32 (-70.37%)
Mutual labels:  dependency-injection
inject
A simple Kotlin multi-platform abstraction around the javax.inject annotations.
Stars: ✭ 42 (-61.11%)
Mutual labels:  dependency-injection
common-injector
Heavily influenced by Angular and it's dependency injection. Inspired by Angular and Indiv.
Stars: ✭ 18 (-83.33%)
Mutual labels:  dependency-injection
BESTV
Android TV App powered by TMDb. It is a easy way to find the best TV content, the top movies, series... all of that in your TV.
Stars: ✭ 49 (-54.63%)
Mutual labels:  dependency-injection
rodi
Implementation of dependency injection for Python 3
Stars: ✭ 42 (-61.11%)
Mutual labels:  dependency-injection
pulp
Scala library for guiceless dependency injection
Stars: ✭ 26 (-75.93%)
Mutual labels:  dependency-injection
Slice
Slice - a framework which simplifies Sling/AEM development by using dependency injection pattern and mapping Sling resources into Java objects
Stars: ✭ 64 (-40.74%)
Mutual labels:  dependency-injection
vue-ioc
IoC and DI for Vue powered by InversifyJS and inspired by Angular Module syntactic sugar.
Stars: ✭ 39 (-63.89%)
Mutual labels:  dependency-injection

Vanilla DI manifesto

CircleCI

Vanilla DI is one of the implementation approaches for Dependency Injection. And also, Vanilla DI is an approach for design.

This approach has the following pros:

Pros
  • Extremely simple
  • Extremely easy to use
  • Dependency-free
  • Good debuggability
  • Good readability for beginners
  • Good portability for most languages
  • Good way to layered architecture

But it is not a silver bullet, so this approach has the following cons:

Cons
  • Maintainability highly depends on design skill

So, Vanilla DI may not work well if you work on a huge project. But using Vanilla DI is still a good choice for many situations.

Code Examples

We provide examples for the languages:

However, we always welcome to add examples for other languages above. Feel free to send a pull request.

Concept

This approach is extremely simple; Inject depended components via constructors (this approach is known as Constructor Injection).

You can achieve it by writing code like the following for each dependent components:

// These are depended components.
class X {}
class Y {}

// This is a dependent component.
class Z {
  constructor(dependency) {
	const {x, y} = dependency;
	this.x = x;
	this.y = y;
  }

  doSomething() {
    // Do something with this.x and this.y.
  }
}

// All dependency should be injected when
// the dependent component is constructing.
const z = new Z({
  x: new X(),
  y: new Y(),
});

z.doSomething();

That's all.

Refactoring Guides of Typical Smells

If you felt something hard to write constructors or tests, Vanilla DIer should find several design smells.

Because the most important part of Vanilla DI is keen sensitivity of design smells. Vanilla DI does not hide any design smells, but DI containers can hides often them.

Huge Arguments Lists

Number of arguments of Vanilla DI component should be less as possible.

Ideally, all components should know only few others (in other words, direct dependencies should be few as possible). You can see a huge arguments list if your code violates the principle. The following code is an example of huge arguments lists:

// PROBLEM: This is huge arguments lists.
class SomethingGreatService {
  constructor(foo, bar, fooBar, baz, qux, quux) {
    this.foo = foo
    this.bar = bar
    this.fooBar = fooBar
    this.baz = baz
    this.qux = qux
    this.quux = quux
  }

  // ...
}

Understanding the component is hard but also understanding an user of the component is hard (typically you can face it when writing a setup phase of test code):

const service = new SomethingGreatService(
  new Foo(),
  new Bar(new Corge()),
  new FooBar(new Grault(new Garply())),
  new Baz(new Waldo()),
  new Qux(),
  new Quux(new Plugh())
);

The huge arguments list says that; some abstraction is needed for depended-on components.

Vanill DIers should try to encapsulute several depended-on components into an abstraction. The abstraction may be a Dependency Bag describing the next section.

Fragile Constructors

Arguments of Vanilla DI components should not be affected by dependent components changes.

One of a reason to avoid Consructor-Injection is parameters modifications upward call hierarchy. For example:

// NOTE: Child class needs to depend on GreetingService.
class Child {
  constructor(fooService, /* TODO: greetingService */) {
    this.fooService = fooService;
    // TODO: this.greetingService = greetingService;
  }

  // ...
}



// PROBLEM: But Parent class does not have GreetingService.
//          Should we add GreetingService to the constructor?
class Parent {
  constructor(fooService) {
    this.child = new Child(fooService);
  }

  // ...
}



// PROBLEM: But also GrandParent class does not have GreetingService.
//          Should we add GreetingService to the constructor too?
class GrandParent {
  constructor(fooService) {
    this.child = new Parent(fooService);
  }

  // ...
}


// ...

You can handle the situation by parameter modifications, but it is boring.

Instead, you can achieve it by adding a dependency bag object:

// APPROACH: Wrapping several components necessary to instantiate Child into PersionFactoryBag.
class Child {
  constructor(personFactoryBag) {
    const {fooService, greetingService} = personFactoryBag;
    this.fooService = fooService;
    this.greetingService = greetingService;
  }

  // ...
}



// GOOD: The arguments list of Parent does not affect.
class Parent {
  constructor(personFactoryBag) {
    this.child = new Child(personFactoryBag);
  }

  // ...
}



// GOOD: The arguments list of Parent does not affect.
class GrandParent {
  constructor(personFactoryBag) {
    this.child = new Parent(personFactoryBag);
  }

  // ...
}


// ...

But should not abuse dependency bags. Abuse of dependency bags lead to violate Interface Segregation Principle.

FAQ

X is the de facto library of Y language. So we should use it, right?

Yes and no. It completely depends to your situation.

For example, you should use a DI container if it is already used in your project. For another example, you should not use any DI container if the project is across many languages and project members are not expert for each languages.

It means, using a DI container is not always the best solution. Don't be afraid to be away from DI container.

What difference between Vanilla-DI and Constructor Injection?

Vanilla DI = Constructor Injection + Phillosophy

The phillosophy is emphasizing design smells; Facing something hard to inject means a design smell.

Contributing

Any suggetions are welcome. Feel free to open issues to discuss about Vanilla DI.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].