2

If one wants to comply with the clean architecture principle 100%, they must not annotate the entities in the entities layer with database-specific annotations (like Hibernate, Neo4j, etc.). So, two options remain:

  1. Creating a corresponding entity in the outer layer for each entity of the entities layer and putting annotations on them: This option may introduce many new classes and boilerplate code and also for each new database type we may need to create all of them once again. Thus, this option may do more harm than good.
  2. Using XML-based mappings instead of the annotation-based ones. Although, this may work for e.g., hibernate, it seems to me that XML-based mappings are not widely supported. For example, I could not find a good way of declaring mapping in XML for Neo4j OGM or Spring Data.

So, according to what I mentioned above, can it be concluded that most developers just ignore the principles of the clean architecture in this case and use annotations on their entities? (If they used the second option shouldn't have we seen a strong support for XML-based mappings? Even, according to what I have seen, there may be some objections to using XML-based mappings).

So, can I just annotate the entities without worry? If not, what is the best solution?

  • 2
    There's no right or wrong answer. The best/better solutions are often those that best meet your needs and requirements -now, today- in the most easy way possible. Even if they go against dogmatisms. Allow me to make you a couple of questions Why Clean Architecture? Why implementing an architecture (#1) you disagree with because is prone to boilerplate code? Why implementing an architecture just to violate its principles from the very beginning? Why buy a car when all you need is a bike? – Laiv Oct 28 at 8:28
  • But sometimes there are best practices that may help. – Shayan Oct 28 at 9:10
  • @Shayan If you're implying that the "clean architecture" is somehow best practice, I would like to strongly disagree. There is virtually no use-case where the clean architecture makes any sense. – Robert Bräutigam Oct 28 at 9:25
  • @RobertBräutigam some arguments of the post's author against the C.A and its premisses are arguable too. But yes, a dogmatic and strict approach to C.A eventually lead us to a place where code is no OO. Then you might or might not agree with the fact that at the boundaries, Applications are not objected oriented. If you relax the OOP when you reach these boundaries, the code becomes fairly simpler than it would be in a dogmatic OO approach. Matter of trade-offs (as usual) – Laiv Oct 28 at 9:43
  • @RobertBräutigam No. I'm saying that there may be a best practice for using databases while keeping core and database layers decoupled. – Shayan Oct 28 at 9:53
4

You basically answer your own question.

Strictly following the "clean architecture" dogma leads to "many new classes and boilerplate code (...) this option may do more harm than good."

If following some rule or principle leads to worse (more complex, less maintainable) code, then it is a bad principle and should be ignored. Or to be more charitable, the principle may be helpful in the right context, but here it is stretched beyond its usefulness.

The idea is sane enough. Business entities should not be tightly coupled to persistence concerns. But using an ORM like Hibernate mean you already have this taken care of. Storage specific annotations is in principle violating complete separation, but is on the other hand a very simple and clean way to provide the information. And simple beats dogma.

There may be particular cases where a complete separation is meaningful. Let's say you are developing some application which is deployed to multiple clients and should be able to run on several different database engines. In that case the mapping obviously need to be completely separate from the business entities, and it might even make sense to use XML-based configurations so you can add new mapping ad-hoc.

Some argue that even if the application is only running on a single database engine, it should be written in such a way that the engine can be transparently replaced. But if this affects overall maintainability negatively, it is a really bad trade-off, since the whole codebase will probably be rewritten more often than the database engine will be replaced.

  • 1
    Agreed. It's important to give value to the simplicity over other factors of the development. C.A proposes some good ideas we can adopt in different grades of compliance. For example, the principle of stable dependency and abstractions, the port/adapter architecture, business-centric designs instead of framework-centric, etc... – Laiv Oct 29 at 6:04
-1

Clean architecture tells business should not depend on infrastructure. One of the most important reasons why your business should not depend on infrastructure is (unit test) test-ability.

If your business depends on infrastructure, then you can not unit test your business code with out the infrastructure.

Now when your business objects are annotated with persistence annotations, then with out reference to the persistence jar files you can not compile. Now to get the business code compiling we need to reference the persistence jars. So clearly there is a dependency of business code in infrastructure at compile time.

However when you business objects are annotated with persistence annotations, then you can unit tests the business with out referencing the persistence jar files at run time. When java loads the your business objects and doesn't find the definition of the annotations it does not throw class not found exception. More details here. This is true only for annotations, if the business is using anything but annotations then you will have class not found exception. So when you annotate your business objects. There is a compile time dependency but at runtime the dependency becomes optional. So in a sense there is no dependency on infrastructure when you annotate. (This is true for both C# and java).

If you really want to strictly stick to not referencing the annotations, then you would have to translate all the persisted entities to business objects in repository layer. This translating code would be boring and of course it needs to maintained. But on the positive side there is no reference to infrastructure in packages. You could choose your approach depending the experience of the team.

I would choose to annotate when my teams is quite experienced. I would choose to translate when my team is not so experienced.

  • I disagree with your premise. Unit testing is not a reason that should impact your design. Yes, non-testable code is a good indicator that the design is probably wrong. However, it doesn't really imply anything more. "Testable" code may still be unmaintainable. And there is no relation in the other direction, meaning "good" or "bad" code, or even code that depends on some of the infrastructure can all be either well testable or not, depending on the exact design. – Robert Bräutigam Oct 28 at 14:54

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.