TL;DR: Don’t surprise your fellow developers.
Yesterday I learned – or realized again, don’t know – that one can add
@CompenenScan to all Spring components and not only to
TIL A @ComponentScan on a @Service class in #Spring actually works and contributes to the application context. 🤯
— Michael Simons (@rotnroll666) May 16, 2019
I see several issues here, the dilution of concern’s being my primary. I can get a quick overview of all services of an application with my IDE looking for
@Service or whatever. The same with configuration. That helps me a lot not to have to think about things.
I spent a considerable amount of time yesterday helping a friend debugging a weird
@SpringBootTest. He wanted to exclude some services from being started and only test some. The first impression was: He tried this by specifying them on the
classes attribute of
@SpringBootTest. That’s not what that attribute does. That attribute is used to point the test context to configuration classes.
To include or exclude components from being started, one uses
@ContextConfiguration, also from the test package. It has
So we added this and removed the classes from
@SpringBootTest attribute. And: Nothing worked anymore. Wtf? After some digging it turned out, that those services mentioned on that attribute – while clearly named and annotated service – also configured more component scanning and the module did not have a
@SpringBootApplication, so the test context couldn’t figure out about the components without being explicitly told to.
Given the fact that the project in question was just a bit older than a year, I think it’s already legacy and not in a good sense: A new developer joining that team would be have a super hard time figuring out what’s happening and why? Things are being named in one way and do something else or something in addition.
Go figure what happens next: It’s always Springs fault, of course.
Well, this time I’d say it’s quite dangerous indeed that all components contribute to the application context and not only
Imagine a library, containing some cool services. When you add this library via a custom starter, you would be hopefully aware, that the starter can add many things to your context. You could however be explicit and write down your own
@Configuration and return
new AwesomeLibraryService() from within a
@Bean method. The
AwesomeLibraryService could be annotated with an arbitrary
@ComponentScan and scan the kitchen sink, the JDK and all the rest, including a blockchain mining library. Probably not what you want.
Anyway, we all are responsible developers, everyone does DDD and writes nice, clean micro services.
My impression of real world projects, especially in big cooperates, is a another. I always stumble upon the same issues:
- Issues with dependencies
- Incompatibile versions
- Cargo cult: A configuration hacked together from various sources is passed on all the time
People are gonna reuse the stuff the find somehow working in projects, whether it’s good or bad.
It’s a seniors developers responsibility to make sure that things have well defined concerns. I am sure that it is impossible to prevent cargo cult, but one can make it a bit safe.
Title photo by Franck V. on Unsplash.