0

I am new in a team working on a grown and complex Spring MVC application. The application context is widely wired using @Autowire annotated constructors. This seems to be the main reason for the issue I see with the application: there is no global structure of the application. If someone implementing a bean A needs a feature of another bean B, he/she adds this other bean to the constructor of A, regardless of the package of B or the categroy of B. If any bean A (let it be a simple helper) requires session data, HttpSession is injected (a session proxy of course). Instead of passing domain objects to helper objects via method arguments, the helper gets access to a service to fetch domain data on its own. Over time this has led to a huge dependency network. I even saw comparator implementations relying on Spring services. One cannot spot any layers or tiers or modules or hierarchy in the application like (controllers/services/dataaccess).

It is my gut feeling that this is not a good architecture but gut feelings is not sufficient to convince my team that there is an issue with this application. It could also turn out that everything is fine and my gut should shut up ;-) I tried to search the web for possible Spring application anti-patterns but could not find supporting facts. So my questions:

  • Is this issue known as some anti-pattern for Spring applications which expresses my concerns? As I said, I suspect the convenience of @Autowire as the main reason. It is too easy to make one bean depend on another.
  • Do you know a book / article which focuses on best practices for Spring application architecture? Most stuff on Spring focuses on technical details, not so much on how to design sound architecture.
  • Which problems will we get when continuing like described?
  • This gut feeling is called "violating the Tell-Dont-Ask priciple" – k3b Mar 21 '18 at 9:21
  • I suspect the convenience of @Autowire as the main reason. It is too easy to make one bean depend on another. Guns don't kill people. People do. Don't blame the tool. – Laiv Mar 26 '18 at 7:47
  • :-) this is not about @AutoFire – rainer198 Apr 13 '18 at 13:10
2

As usual, everything can be abused to some extend. @Autowired is not the cause of your complexity. It is just a simple an effective way to inject another object. No more, no less.

Apparently, your headaches comes from the fact that all kind of objects are injected all over. Even if they don't use @Autowired but instead factories/initializers or whatever, the global structure and dependency chaos wouldn't differ, it would solely add a layer of complexity on top.

Perhaps some simple refactoring would help, attempting to provide better identified layers and extracting chunks of code into separate libraries.

  • Yes, of course, @Autowire is not the single cause, it just makes it easier to ignore layer constraints. If you would have Spring configuration classes for the different layers instead (ServiceConfig, DataAccessConfig), then it would be more obvious if someone wires something which should not be wired. Nevertheless, what is the point for doing such a refactoring/layering? Testability? (Can still be fine with mocking) Maintainability? Readability? Maybe I am wrong and everything is fine with the app. Are my headaches justified in your opinion? – rainer198 Mar 20 '18 at 13:56
  • @rainer198 I don't know. The whole thing is very specific to your app. I can just say that your architecture issue is totally unrelated to @Autowired, or Spring for that matter. It's probably just the basics of loose coupling / high cohesion that are neglected. I don't know exactly what you're looking for. There is no silver bullet for that. – dagnelies Mar 20 '18 at 14:39
1

I've worked in a number of Spring / DI-dependent apps, and in many cases I've seen them become more complex than necessary due to people using DI without first thinking if they need to.

While a 'trained gut' can often point you in the right direction if something is a smell or not, I find a good approach is to use concrete examples. A common technique that I use is testability; what impact is the (supposed overuse) of DI having to the testability of a class? Are the unit tests nothing but Mockito statements? Do you have to construct reams of Spring webapplication contexts to test a small unit of code? What would it look like if it was designed differently?

Another idea would be to take a class affected by this problem, and refactor it to use a different approach, then compare and contrast the approaches with your teammates. Hands-on examples always trump theoretical/philosophical arguments, in my experience.

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.