1

I recently asked this question: Should the domain layer be dependent on NHibernate?

I have read a lot of questions today, where answerers state that the Domain Layer should only contain Business Logic. This confuses me when I read about the Onion architecture, which states that the domain layer should contain all interfaces including services and repositories as described here: https://stackoverflow.com/questions/16861127/onion-architecture-business-services-interfaces-and-implementation

I understand that DDD is an approach that targets the domain layer only and Onion is an architecture for the entire system i.e. core, infrastructure etc.

Therefore should the domain layer contain domain logic only? If the answer is yes, then what design pattern do you use for the architecture design? (Onion will not be appropriate).

  • put repository interface in the domain layer and the concrete class in a seperate project. then your domain layer has no ref to the db and onion (or anything else) works – Ewan Oct 19 '17 at 13:20
  • @Ewan, thanks. What about Unit of Work interfaces? My Domain Layer does not currently access the repositories, however it could in the future if Domain Services are used. Domain Services are described here: zankavtaskin.com/2013/11/… – w0051977 Oct 19 '17 at 13:23
  • what about them? – Ewan Oct 19 '17 at 13:24
  • @Ewan, I am asking if unit of work interfaces should be included in the domain layer? – w0051977 Oct 19 '17 at 15:31
7

Domain Layer should only contain Business Logic. This confuses me when I read about the Onion architecture, which states that the domain layer should contain all interfaces including services and repositories

Business Logic is the core responsibility of the domain layer. However, if that was strictly all the domain layer knew about, it wouldn't be able to communicate with anything else.

What you're being prohibited from putting in the domain layer is knowledge of the volatile, concrete, happens to be what we're using today, details of NHibernate, or the web, the database, the file system, or whatever else they want to use tomorrow.

The domain should be communicating by using whatever is convenient for itself to use, a data structure, an object, a collection. It should not be flinging around result sets, json, row tables, or anything else that gives away what it's talking to.

Which means you need to translate result sets, json, etc into, or from, those convenient to use things in a layer outside the domain. That's part of the infrastructure. That's the adapter part of the ports and adapters in Hexagonal Architecture which honestly isn't all that different from Onion Architecture or Clean Architecture.

The interfaces/abstractions needed to talk to that infrastructure, or have that infrastructure talk to the domain, are what the domain will know about. The domain will own them and dictate when and if they can change. Nothing else gets to have a say in how they change.

Doing that is what "removes all knowledge" of those outside details yet still allows for communication.

  • Thanks +1. What about the Unit of Work interfaces? The Unit of Work interfaces encapsulate the NHibernate ISession object. Therefore I will have to add NHibernate as a Nuget package to the domain layer. Is this normal? – w0051977 Oct 19 '17 at 21:55
  • The fact that you need to do a "unit of work" is a business rule. It's ok to express that idea. It's not ok to reveal that you're using NHibernate to do it. Not in the domain. That noise should move out to the infrastructure layer. – candied_orange Oct 19 '17 at 22:22
  • Thanks +1. What about the Unit of Work interfaces? The Unit of Work contain methods that return the NHibernate ISession object and NHibernate ITransaction object - similar to this: codereview.stackexchange.com/questions/55127/…. Therefore I will have to add NHibernate as a Nuget package to the domain layer. Is this normal? – w0051977 Oct 20 '17 at 8:10
  • Again, no. You don't have to include what NHibernate needs in the domain layer. You do that in the infrastructure layer. In the domain you write interfaces that meet the domain's needs. You write adapters in the infrastructure layer that connect one to the other. That way when NHibernate changes versions or gets replaced only the adapters need to change. The domain continues to not care. – candied_orange Oct 20 '17 at 17:26
1

Therefore should the domain layer contain domain logic only?

Short Answer

No.

Medium Answer

The domain module (layer is idiomatic to a particular style) also contains descriptions of the services required to perform the domain logic.

Long Answer

A starting point for understanding the boundaries of the domain model is to look at the sample implementation of the cargo routing example. The original project page asserts

This project is a joint effort by Eric Evans' company Domain Language and the Swedish software consulting company Citerus.

If you look at the domain code, you'll see that most of the package references point to other components within the domain package. This is consistent with the idea of the onion design; the domain module sits in the core, without dependencies on other components.

But if you look carefully at the repositories, you might notice that they are interfaces; specifically, they are describing a contract without providing an implementation. The actual implementation (using Hibernate) is in the infrastructure module.

In other words, the infrastructure is providing a service that is defined by the model. If you think in ports and adapters: the domain module defined the port, and the infrastructure module provides an adapter that binds to the Hibernate api.

The routing service is done the same way; the interface is described in the domain module, the actual implementation is over in infrastructure.

If we just look at the dependency arrows, we have a domain model that knows nothing about the infrastructure, and we have Hibernate that knows nothing about the domain, and we have an infrastructure component that depends on both Hibernate and the domain to act as a bridge between the two.

Evans was writing in 2003, and using Java; in other words, he was working from a more limited toolkit than we have today. It is possible to further tease apart the expression of domain behavior from the specific in memory representations of state, in just the same way that the repository isolates the domain behavior from the persisted representations of state. So you can reduce the core of the domain to a bunch of data interfaces and some functions that describe domain behaviors in various use cases.

I've yet to see evidence that such separation is cost effective; in memory data models don't seem to change independently of the model often enough to justify the extra work.

  • Thanks +1. What about the Unit of Work interfaces? The Unit of Work interfaces encapsulate the NHibernate ISession object and ITransaction object - similar to this: codereview.stackexchange.com/questions/55127/…. Therefore I will have to add NHibernate as a Nuget package to the domain layer. Is this normal? – w0051977 Oct 20 '17 at 8:11
1

First things first, DDD and onion architecture are different things you can use one without the other. I almost always use onions, but almost never DDD... it is just overkill for most things in my opinion (and the opinion of its creator). Additionally, I feel their are other techniques that can be used instead of DDD, even in situations where it is useful.

The core of your onion (non-DDD) is your domain project. This contains business objects. They model the conceptual workings of your application, without regard for implementation details like persistence, or UI. There is no references to the database, or even classes that deal with the database!

Let's say your application is a proprietary tax application. The core of your onion, the business objects, would have classes like: IncomeEntry, ExpenseEntry, Building, Employee, TaxCalculator, ect. They would reference each-other, but never anything to do with the UI or DB.

The next layer of the onion, infrastructure, would have your repositories to save and recall. This project will reference your domain objects. Your IncomeEntryRepository will have methods like GetIncomeEntries that return IncomeEntry objects.

Next, you have your UI Project on the outside of the onion. It can make use of both the business objects and the repositories to show useful information to the user.

Everyone has been happy with your fast and efficient UI, but now the C levels come to you and ask you to make an API for some of the subsidiaries. They wan't to leverage the power of your application, but legal codes mean they can't have access to your data. This is where the power of the onion.

Simply, on the outer edge of the onion, add a Web API that allows the subsidiaries to input their own data and run Tax calculations on them. This web api will only need to reference the domain core

  • Thanks +1. What about the Unit of Work interfaces? The Unit of Work interfaces encapsulate the NHibernate ISession object. Therefore I will have to add NHibernate as a Nuget package to the domain layer. Is this normal? – w0051977 Oct 19 '17 at 21:56
  • @w0051977 1. I'd strongly recommend against using NHibernate, or any ORM at all. 2. If you do use NHibernate anyway, only use it inside your repositories. 3. This is a good tutorial for that, you can just pass a transaction token to your repositories. jasonwatmore.com/post/2015/01/28/… – TheCatWhisperer Oct 19 '17 at 22:29
  • Thanks. I assume you mean avoid using NHibernate in the domain layer rather than avoid it full stop? – w0051977 Oct 20 '17 at 5:56

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.