1

Robert C. Martin in his book "Clean Architecture: A Craftsman's Guide to Software Structure and Design" mentions that a good architecture allows to delay decisions about details. One of those he mentions is:

It is not necessary to adopt a dependency injection framework early in development, because the high-level policy should not care how dependencies are resolved

What is a proper work methodology to achive that? How can you start developing in an efficient way without a particular dependency injection framework?

Juan
  • 2,024
  • 3
  • 17
  • 36

1 Answers1

1

How can you start developing in an efficient way without a particular dependency injection framework?

The short answer is:

Just like you did before those DI frameworks exists!

Even those frameworks have a lot of benefits it's a quite good idea to start without them to write your code in a framework independent way. This addresses the code smell immobility.

Let's assume you want to setup a controller, a use case and repository.

 +------------+         +----------+        +------------+
 | Controller |  --->   | Use Case |  --->  | Repository |
 +------------+         +----------+        +------------+  

Just use standard constructors and setters.

 Repository repo = new RepositoryImpl();
 UseCase useCase = new UseCaseImpl(repo);
 Controller controller = new ControllerImpl(useCase);

Note: I don't prefer the Impl ending. It's just to distinguish between interface and implementation in this example.

The piece of code I showed above is just the same as what a DI framework does.

If you want to use a DI framework you can then wrap the code above in method that the DI framework uses. In java spring we would call such methods factory methods. E.g.

@Bean
public Controller controller(){
    Repository repo = new RepositoryImpl();
    UseCase useCase = new UseCaseImpl(repo);
    return new ControllerImpl(useCase);
}

Maybe the UseCase should be a singleton and therefore should be placed in a separate factory method.

@Bean
public UseCase useCase(DataSource ds){
    Repository repo = new RepositoryImpl(ds);
    repo.setCacheEnabled(true);
    return new UseCaseImpl(repo);
}

@Bean
public Controller controller(UseCase useCase){
    ControllerImpl controller = new ControllerImpl(useCase);
    SomeConfig c = ...;
    controller.setSomeConfig(c);
    return controller;
}

The main point is that the controller, use case and repository in my example only tell what they need and not where it come from. It's a good idea to separate the setup code or bootstrap code from the other.

René Link
  • 48,224
  • 13
  • 108
  • 140
  • The process of rewriting the code to finaly introduce a di framework is not equivalent to the rewriting done if you are commited to a particular framework at the beginning of development? – Juan Dec 15 '21 at 21:16
  • You can commit to a framework at the beginning. Some developers argue that a framework will never be exchanged so why should they make the effort keep away from it. But this thinking often leads to code that is tightly coupled to the framework. This often reduces easy and/or fast testability, because you need to bootstrap the framework first. I think that the testability is at least worse the effort. – René Link Dec 16 '21 at 07:21