4 ms·
I think maybe this comes down to the kind of injection. If you rely on variable or setter injection, you can easily create a kind of dark matter that invisibly
by jacques_chester 10y ago
I think maybe this comes down to the kind of injection. If you rely on variable or setter injection, you can easily create a kind of dark matter that invisibly warps the flexibility of the project.
I and others have generally found that using Constructor injection greatly decouples a design and simplifies testing.
And the Spring team have been saying so for at least as long as I've paid attention to the question[0]:
> Constructor-based or setter-based DI?
> ...
> The Spring team generally advocates constructor injection as it enables one to implement application components as immutable objects and to ensure that required dependencies are not null. Furthermore constructor-injected components are always returned to client (calling) code in a fully initialized state.
> ...
[0] https://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#beans-setter-injection https://docs.spring.io/spring/docs/current/spring-framework-...
- ivan_gammel 10y agoNope. There is no difference between injection types from the coupling perspective, simply because neither blocks anything bad from happening in your architecture. There are reasons to prefer constructor injection in many cases, but it has nothing to do with modularity or coupling.
- jacques_chester 10y agoI disagree. Constructor injection in Spring is more test-friendly; in turn that tends to allow us the liberty of more aggressively modularising the design. With other injection types either more bookkeeping is required to cleanly set up tests; or alternatively, "unit" testing becomes more integration-esque. It's a second-order effect felt in the many small decisions that lead one to the mudpit. That's why I used the analogy of dark matter. It's not directly observed, but it has gravity.
- twic 10y ago> Constructor injection in Spring is more test-friendly If you get in the habit of using the Spring test support, where classes under test get injected, then all kinds of injection are equally friendly, and the tests don't give you feedback on the weight of the dependencies because Spring does the heavy lifting. And, in my experience, where you do inject dependencies by hand, the design pressure is actually towards coarser-grained objects. Why? Because you need to have enough functionality to test; with fine-grained objects, you have to construct and assemble an object graph in the test, whereas with coarse-grained objects, you just new up one thing.
- EdwardDiego 10y ago> If you get in the habit of using the Spring test support, where classes under test get injected, then all kinds of injection are equally friendly, and the tests don't give you feedback on the weight of the dependencies because Spring does the heavy lifting. How do you handle the Spring context start-up time? In Spring projects I've worked on, across hundreds of unit tests it's non-trivial. But I don't make any claim to know if we were doing Spring right or not.
- jacques_chester 10y agoIf you're firm on constructor injection, you can typically test the object in complete isolation without necessarily using mocks, without Spring having to be involved. Or you can use mocks and Spring Boot's test annotations. But with field/setter injection, that choice isn't as easy.
- twic 10y agoThe context can be reused between tests. If you're not storing data in beans (which you normally shouldn't), this works well. There is a bit of subtlety in that the framework might have to create multiple context for different configurations, but each of them is reusable. Running a single test is a bit of pain, but running the whole suite is not a lot slower than if it didn't use Spring.
- EdwardDiego 10y ago> Constructor injection in Spring is more test-friendly These are my thoughts too. No reflection or @MoreAnnotations to inject dependencies. I have an aversion to setter/field based injection because it allows you to instantiate an object in an incorrect state.
- jacques_chester 10y ago> I have an aversion to setter/field based injection because it allows you to instantiate an object in an incorrect state. Oh yes. I recognise that JavaBeans had its reasons for being, but then you get to JPA and it's time for all the boggling.
- lazulicurio 10y agoMy personal pet peeve is bean validation. The goals of the API are laudable, but the fact that the implementation is annotation-driven drives me nuts. Annotations are fine for intra-project code contracts, but using them for external validation means that if you, say, deploy on a application server with an older version of Jersey, you're suddenly SOL when none of your validation logic is executed.
- spiralpolitik 10y agoWith Constructor based injection its easier to see layering and coupling issues as once your constructor gets more that 3-4 parameters then it starts becoming blindingly obvious that the class has too many dependencies and needs to be refactored. This helps keep the bad out of the architecture. The main reason to favor constructor based injection is that it stops objects becoming 'live' in an inconsistent state. I've seen actual production issues with setter based injection that can only be explained by the object being available for use before all the setters have been called.
- ivan_gammel 10y agoYour arguments are valid on why constructor injection should be preferred. However, what are you talking about is the human-made decision: "Stop adding more parameters to constructor". The tool does not force you to build high-quality architecture, it is your choice based on your experience and skills. Other people who are not yet aware about the consequences may still make wrong design decisions and they'll be ok with lots of parameters.
- twic 10y agoIf you want to see big balls of mud created using setter injection, you're welcome to visit any of the projects i worked on when i was at Pivotal!
- jacques_chester 10y agoI am guilty of this too. It's why I'm a bit of a constructorist these days.
- twic 10y agoAargh. I meant using constructor injection. It didn't save us.
- tigershark 10y agoThey are two different tools needed for two different jobs. Constructor injection is for mandatory dependencies, setter injection is for optional dependencies. If you are writing a plugin application and some modules are optional then you cannot use constructor injection because when the optional module is not present you cannot start your whole application. In 99% of the cases obviously constructor injection is the way to go.