Question

I was watching a presentation by Uncle Bob. In the end of that presentation (last 10 min), He argued that we should abstract everything (Even frameworks) from our business logic.

JAVA EE does a great job in doing so. UI is abstracted by JSF (and other technologies). The database is abstracted by the persistence layer (JPA), even IOC container (Framework) can be abstracted by using standard annotations (CDI).

So far so good, but some frameworks completely ignore CDI and introduce their own Annotations (Bad sign! they are trying to couple their framework to our code). How we can prevent it. Uncle Bob's advice is to limit the use of Dependency Injection in our code and use other patterns such as Factory method, ...

But I think it is not a feasible approach for example for Dependency Injection we need to implement Service locator pattern (re inventing the Well) we can't have the functionality that frameworks provide (life cycle callbacks, ...).

Any thoughts ??

Was it helpful?

Solution

The easiest way to avoid dependencies on a framework is to not use a framework.

Abstracting frameworks just doesn't work in practice. For example Microsoft tried creating an abstraction over their MVC Di framework and it caused way more problems than it solved. Abstractions add complexity, always. Therefore there has to be a benefit to that added complexity. An abstraction that stifles innovation (ie you regard introducing new annotations as a "Bad sign!"), panders to the lowest common denominator and - invariably - leaks implementation details of the "baseline" implementation isn't adding benefit.

Even the likes of Java EE, which has a good abstraction model, allowing more than one implementation to implement it, still heavily restrict you. If you adopt Java EE, you couple yourself to that abstraction; you still aren't free to do things another way easily. Java EE is still basically a framework and you still couple yourself to that framework once chosen.

So what can you do? Don't use frameworks, especially for things like DI. Use pure DI, inject factories as "Uncle Bob" suggest etc. Keep your DI model simple and you don't need a framework to handle it for you. Or if you must have a framework, view it like picking a programming language: go with one you like and stick with it until it no longer meets your needs, and don't fall into the trap of trying to create an abstraction around it.

OTHER TIPS

Since you tagged Spring I'll answer based on that, because I have no idea how much you can applied it to others framework but it's likely most of all is doable with others framework.

In Spring you can isolate the dependency management by instantiating your classes in the @Configuration classes. There you can instantiate yourself your beans in the configuration classes where you will wire all dependencies togethers. As such there will be absolutely 0 annotations in the classes that implements your business logic.

Also the old XML configuration can be seen as a way to keep them separate.

Finally, there is some times where you may need the ApplicationContext of Spring, you can just hide him behind a simple abstraction that answer just what you need. I don't bother to do it myself though, but it doesn't happens in my classes handling the businness logic. If you need events, create event handle that just catch the event and call the right services handling the business logic for it. As such you will not have your business logic directly wired to the event bus of your framework.

EDIT : Following what David Arno said, I'll add this to my answer.

If you understood it well, you will understand that in fact I'm not telling you really to abstract the framework but instead to have classes independant of your framework (where your business logic is implementend) and to have classes making the connection between the framework and your independant classes. As such I join David Arno on the claim that you don't abstract frameworks.

You can:

  • Separate domain logic from the framework. Use the ports and adapters architecture (aka hexagonal) where only the external part knows about spring. This can be enforced by using a several maven modules where only de outer module knows about the framework.

  • Inject dependencies by constructor (bonus if you make dependencies immutable).

  • Avoid the magical tags: @autowired, @value, etc. Configure dependencies y the configuration file. This will decouple your properties from the places where they are found. Instead of having a Service with @value("timeout.in.millis") you have a long timeoutInMillis that in the configuration file is get from this place. Avoid autoscan of dependencies.

  • You can still use the same classes ...but as a POJO. Spring Data for example has excelent classes.

As a nice side effect you will have a more testeable code

Licensed under: CC-BY-SA with attribution
scroll top