2

Given a layered architecture, where the business logic is isolated in a package from all other layers, like persistent storage, user interface, interfaces for various (vendor) remote services, etc, I am thinking to manage dependencies in the following way:

Within the library, all dependencies are injected manually via the constructor. This has the advantage (which in my opinion is big) that it makes tests more explicit, increasing their value as a documentation source.

For the other layers and plugins, I am thinking to inject manually only one object used for dependency lookup, which would make mocking easier. I doubt there would be only one object for all subsystems, I am merely thinking about really specific, small interfaces, and factory instances which implement one or more of those interfaces. How many interfaces such a factory implements is an implementation detail, I guess I would start with only one factory implementing all interfaces, and as the system evolves, I would pull out other factories and refactor accordingly (YAGNI). The interfaces (i.e. the signature of the constructors) would stay as they were before refactoring, thanks to interface segregation.

The business library gets its commands from outside via commands (think DDD).

  1. What do you think about this? Other advantages and disadvantages are welcome!
  2. Which other strategies for dependency management do you prefer in which situations and why?
2

You're going for something akin to (but not similar) Spring's ApplicationContextAware, where you pass ApplicationContext (which is a BeanFactory) via a setter, so it later can get beans it needs.

Generally it is a bad idea, if you only need to inject dependencies:

  • It is not explicit about dependencies it uses. So, it is actually harder to mock, not easier, because you're not sure what needs to be mocked unless you look into the whole code of a class and probably the whole code of its' super- and subclasses, if inheritance happens.
  • It is not type safe if you query dependencies by string keys, with all negative consequences of that. However, if you say you'll have specific interfaces to deal with that (like UserRepositoryFactory which has a method like getUserRepository, I guess), it will be type safe, but I don't see the benefit in this solution, because it seems much easier to just inject dependencies without medium getter/wrapper/injector-objects. I think it would be just duplication of DI functionality.

If I would make a plugin system, I would go with "stupid" plugins, which just implement some SomethingPlugin interface, and expect it's dependencies to be injected (via constructor or setters, which doesn't really matter) by the system, without any prior knowledge of anything outside.

Example:

public class UserRatingPlugin implements GenericPlugin,
        UserRepositoryAwarePlugin, PostResositoryAwarePlugin {

    // here are dependencies
    private UserRepository userRepository;
    private PostRepository postRepository

    @Override // from UserRepositoryAwarePlugin
    public void setUserRepository(UserRepository ur) {
        userRepository = ur;
    }

    @Override // from PostResositoryAwarePlugin
    public void setPostRepository(PostRepository pr) {
        postRepository = pr;
    }

    @Override // from GenericPlugin
    // this should be required to make this class a plugin
    public void doPluginMagic() { /* ... */ }
}

Then you register this plugin (via config file, I imagine), then somewhere in a "system level" code you instantiate this class, set dependencies (this part can be automated by Spring's or similar DI-container) and invoke doPluginMagic().

This way you still have small specific interfaces, but now as parts of a plugin API, which I think simplifies the whole thing. You can see what plugin can access by just looking on its' type declaration, and no additional "factories" have to be crafted.

  • I do prefer DI at construction time over setters, because it avoids putting the object in an invalid state. In an ideal world, an object has no setters (one-liner methods which just set a field), just methods which do business-relevant things (and maybe also set a private field as part of it). However, your answer has once again confirmed my fears. Thanks. – Flavius Apr 18 '15 at 11:45
  • I agree that setters have disadvantages. You can go with constructor injection as well (at least I'm sure I can do that with some DI-containers I know, e.g. AutowireCapableBeanFactory), interfaces would be of no use then. – scriptin Apr 18 '15 at 11:50
  • Also, I have to note that object can be put into invalid state even with constructor injection, since nulls can be passed into constructor, so you have to check (at runtime). You can deal with invalid state by providing a method afterDependeciesSet in GenericPlugin interface which checks that all dependencies are set properly - again, at runtime. In the end of a day, those two approaches are not so different as it might seem. – scriptin Apr 18 '15 at 11:54
  • That's a language-specific issue, not an architectural one. – Flavius Apr 18 '15 at 11:54
  • I don't quite understand. It is indeed language-specific (if Java had no nulls, constructor injection would be better), but why does it matter? – scriptin Apr 18 '15 at 12:01
3

Your dependency lookup looks very similar to service locator pattern, except that often, service locator is static.

The benefits of such dependency lookup when compared to ordinary dependency injection are that:

  • You won't find constructors which take dozens of (often mandatory) arguments if they need many dependencies. This makes your code shorter and easier to read and write.

  • You don't need to change the definition of the constructor when the object needs to rely on an additional dependency (or don't need a previously used dependency). This means less code changes over time.

There is however a drawback:

  • The dependencies are out of control. When dependencies are injected through the constructor, by looking at the constructor, you immediately know which dependencies the class needs. If the only thing there is a lookup (or a service locator), you only know that the class relies on one to N dependencies, with no additional information.

    This also makes it difficult to use those classes. Imagine you're in a context of a unit test. Which objects, in the lookup, should be mocked? The problem exists already for dependency injection (since the tested method don't necessarily have to use every dependency requested by the class), but with a lookup, it becomes larger, with more dependencies which can be potentially used.

    Pass-through (that is when a class A requests a dependency in order to pass it to another class B it calls) can make this task even worse, since you have no visibility on which dependencies are used by the class B if you pass the lookup to it.

  • I avoid static like hell. Can you rephrase some parts of your answer to frontally answer my questions? It's not quite obvious what are you getting at in respect to my questions. Otherwise, it's a nice answer. – Flavius Apr 18 '15 at 10:50
  • @Flavius: Static makes somehow sense in a case of service locator pattern, but yes, it looks weird and is avoided by many developers. As for frontally answering the questions, I believe I did for the first one by listing the benefits and the drawbacks. I haven't answered your second question because its subjective aspect ("I use DI most of the time because of the drawback above" is not that interesting as an answer.) – Arseni Mourzenko Apr 18 '15 at 13:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.