Dependencies in a Three Tiered Application
When people working on a multitiered application get asked to draw their architecture, often something like this emerges:
UI -> Domain -> Persistence
This is all nice until you start to wonder what the arrows actually mean.
Is it data flow? Probably not, except when you are working on an application that takes input, stores it somewhere but never retrieves it back.
Is it dependencies? Hopefully not, or everything depends on your persistence layer. You really don’t want that.
It might be calls: The UI gets triggered by the user in some way (say hitting a save button). The UI calls the domain logic tod do its stuff which in tern calls the persistence layer to store the stuff, load some other stuff and this gets returned up the stack until it gets displayed in the UI.
While this is valid information to convey it often isn’t what people think they are conveying. Instead they claim this are dependencies. And maybe they are. But if you want to document your dependencies your diagram should look like this most of the time:
UI -> Domain <- Persistence
The Domain should be the center of your architecture and there for at the center of your dependencies. Everything else, i.e. all the interfaces (in the general sense) should depend on the domain. Not the other way round.
You achieve that by defining interfaces (in the Java sense) inside your domain which then get implemented or used by the UI or the Persistence layer.
If you want you can have those interfaces in seperate layers you can:
UI -> Presentation Interface Persistence Interface <- Persistence Implementation
Just take care that the design of the Presentation Interface and the Persistence Interface is driven by the domain, not by some UI or Persistence technology.
As a side note: If you are using Hibernate / JPA with annotation based mapping you are either violating this design principle, because your persistence technology (JPA) bleeds into the domain logic (annotations on the domain classes) or you have to copy all the data from your entity classes into your domain classes which really is cumbersome and reintroduces the kind of boilerplate code we wanted to get rid of with tools like Hibernate in the first place.
How to resolve that issue is a topic for another day.






I don´t understand what the difference is between “A -> B” and “A depends on B” and “A.f() is calling B.g()”. [1]
To me, dependency means, that some code (A) cannot function without some other code (B). (Whether A knows a concrete B or just an abstraction like a B-interface, is irrelevant, I´d say.)
That said, I´m wondering if what you propose would really be an improvement.
What you´re saying is: The UI calling the Domain is ok. But the Domain should not call Persistence. The Domain should not know about any UI or Persistence interfaces. But the Domain as well as Persistence are allowed to know Domain interfaces.
This partial inversion would decouple Domain from Persistence, whereas Domain is already decoupled from UI today.
The Domain would gain the sovereignty for defining interfaces.
Although this seems to be better than today´s dependency patterns… I´m wondering, why stop there?
Why should any “component” depend on any other? Why should the UI need to know about a Domain interface to call or implement? Why should Persistence need to know or implement?
Sure, UI, Domain, and Persistence need to work together; they need to be “wired up” to form a whole. But does a UI need to know there are Domain objects providing some services? Does Persistence need to depend on such services?
Does a motor know about a fuel tank? No. Does a fuel tank know about a motor? No. Does a spark plug know about a cylinder? No. Does a cylinder know about a spark plug? No. Does a key on your keyboard know about the board it´s attached to or the other way around? No.
All these things – each serving a particular purpose – just have a form of their own. Some designer shaped those forms in a way so they fit together easily. But neither plug nor socket depend on each other.
This highly successful “principle of mutual oblivion”
to me needs to be applied much more to software. Instead of shifting around dependencies we should strive for getting rid of as many as possible.
—
[1] In order to be able to differentiate between dependency and data flow I switched from using “->” as the dependency symbol in texts to “-*”. So “A -* B” means “A depends on B”, and “A -> B” means “data flows from A to B”.
Being able to easily express both relationships is pretty powerful in design conversations.