Dependency Injection: Anti-Patterns

    Low coupling is often a sign of a well-structured computer system and a sign of good design. Wikipedia

    Dependency Injection (DI) is a collection of software development patterns and principles that allow you to write loosely coupled code. According to M. Fowler, DI is a variation of the more global principle of control inversion (IoC), also known as the “Hollywood Principle”.Meanwhile, the boundaries of the principles of dependency injection are quite blurred. It is impossible to draw a really clear line between this and other principles of writing high-quality object-oriented code. For example, the SOLID Dependency Inversion principle, which is often confused with Dependency Injection, seems to imply dependency injection, but is not limited to it.

    As with any patterns and principles, there are anti-patterns for DI. I will list them below (with a somewhat free translation of English names into Russian).

    Anti-pattern number 1. "Control Freak." Head addict.

    All dependencies are controlled directly. The opposite of the principle of inversion of control.
    The antipattern always occurs when we explicitly create a mutable dependency inside the class using the new keyword. A class that does not let go of its dependencies is Control Freak.

    An example of such a class is shown below:

    private readonly ProductRepository repository;
    public ProductService()
    {
        string connectionString = ConfigurationManager.ConnectionStrings["Context"].ConnectionString;
        this.repository = new SqlProductRepository(connectionString);
    }
    

    An option to avoid this anti-pattern: use Dependency Injection (preferably through the constructor). A valid example after refactoring that is not Control Freak is as follows:

    private readonly ProductRepository repository;
    public ProductService(ProductRepository repository)
    {
        if (repository == null) 
            throw new ArgumentNullException("repository");
        this.repository = repository;
    }
    


    Anti-pattern number 2. "Bastard Injection." Extramarital addiction.

    This clause implies multiple constructor overloads along with “default constructors” that are ubiquitous in .Net, including BCL. The main problem is that external dependencies are usually defined in other modules and similar constructors increase the system connectivity literally from scratch. Extramarital external dependencies should be avoided wherever possible, and the dependency resolution should be given to the DI container. An example of an anti-pattern is shown below:

    private readonly ProductRepository repository;
    public ProductService() : this(ProductService.CreateDefaultRepository())
    {
    }
    public ProductService(ProductRepository repository)
    {
        if (repository == null)
            throw new ArgumentNullException("repository");
        this.repository = repository;
    }
    private static ProductRepository CreateDefaultRepository()
    {
        string connectionString = ConfigurationManager.ConnectionStrings["Context"].ConnectionString;
        return new SqlProductRepository(connectionString);
    }
    

    As an option to avoid this anti-pattern, it is suggested to use Dependency Injection. It is desirable, again, through the constructor, because embedding dependencies through the constructor is the most correct way of DI.

    Anti-pattern number 3. "Constrained Construction". Limited build.

    An anti-pattern occurs if there is a requirement for all dependencies to have a “special” constructor. This requirement often stems from the desire to “create the same type through Reflection”. Something like:

    string connectionString = ConfigurationManager.ConnectionStrings["Context"].ConnectionString;
    string productRepositoryTypeName = ConfigurationManager.AppSettings["ProductRepositoryType"];
    var productRepositoryType = Type.GetType(productRepositoryTypeName, true);
    var repository = (ProductRepository)Activator.CreateInstance(productRepositoryType, connectionString);
    

    Avoid this anti-pattern, and use factories to create classes of the same type.

    Anti-pattern number 4. "Service Locator". Service locator.

    Anti-pattern occurs when granular receipt of individual services in different parts of the code.
    The author of the above DI anti-patterns admits that the issue of the service locator is debatable, however, he continues to consider the Service Locator as an anti-pattern, arguing mainly that business logic should not know about infrastructure things, one of which is the service locator and all dependencies must be thrown explicitly.

    A list of DI anti-patterns is given in the book “Dependency Injection in .NET,” by Mark Seemann.

    Also popular now: