There are many projects of the Simple Injector type for various programming languages โโthat allow, by the name of a class, interface or namespace, and sometimes a folder, to register a class or an entire group of classes united by this feature in some case. This is done for the purpose of automatically instantiating an object without explicitly specifying its dependencies. This registration of a group of objects by a common feature in the register for the purpose of further instantiation, I call automatic registration of dependencies.
If you explicitly instantiate a class when registering it in the dependency register, then this is not the topic of this article.
And what's wrong with that?
In this post, I will talk about my frustrations with projects that use automatic dependency registration. Let's go in order.
Runtime vs compile time
Using the automatic dependency registration tool, we are moving the check for completeness of registered dependencies to runtime. That is, if at the time of launching the program we do not have the implementation of the interface necessary for executing the code, we will find out about it at best at the start of the application, and at worst - already during the operation of the system and from users.
Here's an example. If in the project the registration of some classes occurred, say, by their namespace, and you at some point moved the class from it, then you will learn about the problem at runtime. The same will happen with automatic registration via the interface, with the only difference that moving will not be a problem, but removing the interface will lead to a problem, which you will learn about after starting the application.
Refactoring is much more complicated
Not only refactoring, but also learning the code becomes very difficult. This is because when using automatic registration of dependencies, access to the modern capabilities of development environments is lost, which would allow us to find out who is using this class in one click (find reference) and answer the following questions:
- Can I remove this class?
- Can I move this class to another namespace / folder?
etc.
In addition to the fact that we are deprived of the opportunity to check the completeness of the required dependencies during compilation, any refactoring is the hope that we have a runtime mechanism in the form of tests, verifications of dependency trees, and the like. And the hope is that it works. It should be noted that these mechanisms not only do not guarantee 100% that the composition of the code is correct, but also much slower than compilation.
Hiding the real complexity of the system
When manually instantiating classes and all their dependencies, you may be rather intimidated by the monstrosity of the file in which all this action will take place. Looking at thousands of lines of code for instantiating classes and comparing them to a dozen when using automatic dependency registration, I really want to succumb to the temptation and go to the "dark side".
But what are these thousands of lines of code for instantiating objects telling us? The fact that this module is complex, large, and we should think about either structuring it through the allocation of submodules (which themselves explicitly instantiate their dependencies), or dividing this module into several.
It may seem abstract, but removing such awkward moments as instantiating hundreds of objects from our eyes leads to the fact that the project size grows uncontrollably, and as a result, we miss the moment when it should be divided into several projects.
Extra dependencies
By registering dependencies and not controlling their use, sooner or later we come to a situation when at the start of the application significantly more classes are registered than are actually required. Simply adding to a folder or implementing an interface can result in this class being registered in the general case.
Summary
Is it possible to live with all these disadvantages and not notice them? Sure! But I believe that it develops the wrong development habits. The point is that compilation and typing of code are tools for checking the correctness of the system. Rejecting them, we come to the conclusion that the system becomes fragile, so developers are afraid to change anything in it. And the fear of developers to change the code already leads to the fact that the quality of the code base degrades, after which it becomes an expensive process to make changes to such code.
What is good about automatic dependency registration?
And really, what's good? I propose to discuss in the comments why this method has gained popularity. Surely he has fans among his readers.