In order to handle complexity in our code, we tend to divide it into different modules or layers, which we assemble and compose to solve the problem we are addressing. Oftentimes, we refer to these as dependencies that need to be provided to a certain module, so that it can perform its tasks.
Dependencies can be modeled as a protocol which accepts different implementations. We can supply, for instance, one instance for production and another one that we can control for testing.
In this section of the documentation, different techniques for dependency management are presented:
These techniques are isomorphic to each other; that is, you can use them interchangeably. However, each one of them provides different ergonomics:
|Partial application||Simple to use, just passing parameters.||Difficult to scale. Difficult to pass transitive dependencies.|
|Constructor-based||Hides internal dependencies inside a module.||Dependencies become implicit and hinder local reasoning.|
|Reader||Highly composable.||Difficult to work with many dependencies if they are not handled carefully.|