5

I'm getting my head around DDD and how to build up an C# Project structure for an .Net Core WebApp. I searched quite a bit around the web, for example How to structure a Domain Driven Design in an Onion Architecture?, https://github.com/zkavtaskin/Domain-Driven-Design-Example and several Pluralsight courses.

What bogs me is the fact, that this HelloWorld-examples don't seem to work very well in the real life: Let's say we build the propagated onion structure of Application, Domain and Infrastructure. Application would in this case be the WebApi-part, Domain the Domain-Services, Entities, Value Objects etc. and Infrastructure the implementation of the Interfaces defined in the Domain-Assembly.

So far so good, but with this approach, I'd need to define every bit of helping code in the Domain-Layer. For Services, Handlers, etc. I could define just the Interfaces and let the implementation inject from the Infrastructure-layer. But as soon as I started coding like this, I had folders like Attributes, Handlers (low level services for REST, Files etc.) and a ton of other technical stuff in my domain-layer. For the sake of testing, I tried to revert the dependency, so the Domain targets the Infrastructure. This allows to move all the supporting code and low-level handlers to the Infrastructure, but makes communication awkward: Since the entities and value objects are still in the Domain, the Infrastructure doesn't know them anymore, so I'd need to map them to DTOs, adding another mapping layer just for this communication.

From reading Eric Evans book, I took the idea, that the Domain-Layer should be written in the ubiquitous language, be technical agnostic and be the communcation platform with the domain experts. But I can't find a good solution to have the both of best worlds. Am I missing something crucial here?

12
  • 1
    How could you have REST specific code inside the domain layer? Commented Jul 26, 2017 at 20:59
  • 1
    It sounds like you're treating DDD as a coding methodology. The third D in DDD means "Design," not "coding." Example: The "Ubiquitous Language" is merely a mechanism that helps stakeholders and developers communicate; it has nothing to do with coding. Commented Jul 26, 2017 at 22:05
  • 1
    @MatthiasMüller I don't understand how a domain object (aggregate or entity or even a service) would load/need something from the infrastructure (by an IO operation). As far as domain is concerned, all objects are in memory at the time of the execution. Commented Jul 27, 2017 at 9:40
  • 1
    @MatthiasMüller That service should be in the application layer. The service calls a command method on TFS-Workitem, the TFS-Workitem (I suppose that this is an Aggregate) perform state mutation according to the business rules then the app service gets the TFS-Workitem (or a DTO) and pass it to the Infrastructure to perform the REST call. Commented Jul 27, 2017 at 12:32
  • 1
    @RobertHarvey "it has nothing to do with coding" - it has to do, the names of tokens (methods, classes, variables, parameters) should be chosen from the UL Commented Jul 27, 2017 at 12:34

3 Answers 3

10

I think that we often out-think ourselves when we are trying to learn a new way of doing things. Instead of boiling the problem down to the smallest thing that can possibly work, we think about things that aren't important right now. Onion architecture and DDD work together to provide a way of letting you define that simplest way of doing things.

What's really your domain?

That's the question you need to be asking yourself. The most core concepts are:

  • How domain objects interact with other domain objects
  • How domain objects interact with primary services

Everything else is completely outside the domain. Whether you use a Repository pattern for persistence or something else is beside the point. There will be points where your domain object needs to interact with a service. That's OK.

  • Stub your services using interfaces and domain terminology

And stop. You can have a fully unit tested domain driven design with these two concepts.

Services from the inside out

In an Onion architecture, the implementation of your services are done at a layer outside of your domain model. That keeps the domain clean, and separated from the concerns of your service.

One example would be using a SQL database for persistence. If you need to change that in the future, or add other types of databases (graph, search, etc) to facilitate your system, you can localize those changes behind the service you defined in the domain model.

Common things that are not central to the domain:

  • Authentication
  • Persistence
  • Rendering (i.e. REST services, full web application, desktop app, etc)
  • Internationalization
  • Messaging

That is not a full and exhaustive list.

Your domain may have users, and those users have roles... but how the user is authenticated and those roles supplied are things that will change over time.

Modes of messaging may change over time, as well as specific content, but the types of messages and triggers that kick them off are related to the domain.

Feel free to apply the same concepts to implementing your services as you did for the core domain. The only difference is the domain for a persistence service is different than for your core application.

Project Structure

It really depends on how granular you want to go, but at the very least you should have one library as your core domain model. You can have service implementations in separate projects, or group some things together.

+ Solution
  + Project.Domain (or Core if you prefer)
  + Project.Domain.Test
  + Project.Persistence.Service
  -- etc.
  * WebAPI

Don't be overly religious about your project organization. It only needs to be reasonably clear where to look for things. Your core domain library has the domain objects and interfaces for services as necessary. The only rule I'd recommend is to have a clear hierarchy of project dependencies. Project.Domain shouldn't depend on anything outside of your standard library for the language you are using.

0

Are you familiar with Ports and Adapters? I think it might help you get the dependencies sorted out. This article is a good starting point.

http://www.dossier-andreas.net/software_architecture/ports_and_adapters.html

It's important to learn the distinction between primary and secondary Ports and Adapters if you want to apply this pattern successfully.

The links at the bottom of the article are worth reading.

1
  • Thanks, I even disagree 180% with the author: I think Infrastructure should be mostly known by the Application-Layer, while the Domain-Services should only need to know the Repository-Interfaces.I went ahead and renamed the Services.Domain.Infrastructure to Services.Domain.Data to reflect this idea. I will have a look, how fare I can get with this idea. Commented Aug 7, 2017 at 10:08
0

Interfaces are declared in the Domain layer when they need to be used by the domain. From your second link :

Put your infrastructure interfaces in to Domain Model Layer. Your domain will use them to get data, it doesn't need to care how, it just knows there is an interface exposed and it will use it.

Where I seem to differ with the author is : not all infrastructure objects will be like this. I usually have many infrastructure services used only by the Application layer and don't define their interfaces in the domain.

Not the answer you're looking for? Browse other questions tagged or ask your own question.