DDD: Should Persistence Logic belong to Infrastructure Layer?
Asked Answered
T

4

9

Well my application follows DDD design principles. It is an ASP.NET MVC application with the MVC web application being the presentation layer(I moved controllers to application layer though). It also has Application Layer that is primarily application services, use cases, etc. Above the Application Layer is the Domain Layer where Domain Models reside. Then there is Infrastructure Layer, which sits on top of everything else, and is supposed to be dependent on no other layers.

But there is one problem I noticed, that if Persistence Logic goes into Infrastructure Layer as the DDD books suggest, the Infrastructure Layer will have dependency to Domain Layer. The Repositories, for instances, need to know the types of Domain Models(Entities) to create, with this knowledge they become dependent on Domain Layer. The original DDD principles however, suggest that Infrastructure Layer should have absolutely no dependency for anything.

So now I am confused, should Persistence Logic really, belong to the Infrastructure Layer? If so, it makes Infrastructure Layer dependent on Domain Layer. If not, then where should it be? Application Layer? Or maybe a separate layer between Application Layer and Domain Layer(as application services use repositories, repositories use domain models). What do you think?

Tobacco answered 15/10, 2016 at 4:2 Comment(1)
I would rather say, that no application/domain layer can depend directly on infrastructure, not other way around. You always implement repositories in this way, that they know about the domain model, otherwise how are they supposed to save it? From the domain and application layer depend on interfaces and inject implementation from the infrastructure layer.Bricebriceno
S
12

Types of Dependency

I think an important concept that might assist here is to distinguish types of dependency - specifically, a layer or component can be dependent on another layer because either:

  1. is defined in terms of concepts defined in that layer, or
  2. it uses the other layer - by delegating to that layer (aka calling methods on services in that layer)
  3. Or both the above

Inversion of Control and Dependency Injection make this distinction even more important. They guide that we should depend on abstractions rather than concretions.

This means that, for example, the domain layer can define and depend on an abstraction of a repository - e.g. an IEntityRepository interface.

However, the implementation (concretion) is then implemented in the infrastructure layer.

When the application layer wants to call on the repository, it depends on the abstraction (the interface), and the inversion of control system (IoC Container) supplies it with an implementation from the infrastructure layer.

In this case, the infrastructure layer depends on the domain layer - but only in order to know about the interface it is implementing, but it does NOT depend on any other layer in order to delegate to it - it is the last layer in the call stack.

This concept resolves the conflict you were concerned about, because the infrastructure layer doesn't depend on anything else to carry out it's function.

Onion Architecture

Once you start to incorporate IoC concepts into thinking about your architecture, a model that can become very helpful is the onion architecture pattern. In this view, we retain the layered approach, but rather than thinking of it as a stack, think of it as a layered onion, with the Domain in the centre and the interactions with everything outside the application on the edges.

The original DDD books didn't specifically reference this, but it has become a very common pattern for implementing DDD systems.

It is also known as the Ports and Adaptor pattern, or the Hexagonal Architecture.

The idea is that it models dependencies in terms of 'knowing about' in terms of an onion - outer layers know about inner layers but inner layers don't know about outer layers.

But it models delegation of application flow in terms of movement across the onion - from one side of the onion to the other.

To be more specific:

The outer layer (also known as a 'primary adaptor') is where the request enters the system. The adaptor has the responsibility for handling a specific API presentation (e.g. a REST api) and transforming it into a request to the Application services layer - the next layer in. This is often represented as the top-left of the onion.

The Application services layer represents a 'use case' of the application. Typically a method would use a repository interface to retrieve an instance of an aggregate, then delegate to methods on the aggregate root to execute the business logic that involves changing the state of the aggregate as required for the use case. The application services layer, then uses another interface to ask the infrastructure layer to 'save' changes (often using a unit of work abstraction)

Here we have the application layer delegating control flow to an 'outer layer' of the onion (otherwise known as 'secondary adaptors'). This is often represented as the bottom-right of the onion, and is analogous to the 'infrastructure layer' in your description.

And this is where IoC comes in. Because we have an inner layer delegating to an outer layer, it is only possible because the outer layer has implemented an interface defined in an inner layer (which it can do because it knows about the inner layer). However, the IoC container injects the actual concrete implementation which effectively permits the inner layer to delegate control to the outer layer without being dependent on it.

In this conceptualisation, the request has flowed from the top left to the bottom right without the inner layers knowing anything about the outer layers.

Sellers answered 16/10, 2016 at 9:41 Comment(2)
Nice explanation, thanks, but I am afraid you didnt understand my question really. I was saying that, in the traditional 4-layered architecture, infrastructure layer is the inner-most layer. According to this theory, domain layer depends on infrastructure layer, while infrastructure layer should be unaware of the domain. However, if persistence logic belongs to infrastructure layer, it will make infrastructure layer aware of domain models. Then it raises a question: Should persistence logic belong to infrastructure layer, if it depends on domain layer.Tobacco
@Lord i agree that this answer does not directly address your problem, but it has some useful insights. About your problem, the layered architecture you proposed may not be the best fit for implementing what you are doing (as strictly following it, would require you to violate its principles - domain knows infra and infra knows domain). Vaughn's book uses an identical scenario and it suggests that it is better to move the infra layer to the top and all the other layers provide just abstractions (interfaces), letting to infra the impls. This will lead you to learn about the hexagonal.Paedo
R
0

There are 2 options here

1) Work with DAO objects. then the infrastructure layer only needs to know about those DAO objects. Especially if you use Entity framework or something similar then this isn't a bad strategy to follow. You do gain some overhead from mapping but you can use an Automapper for that.

2) live with the fact that the infrastructure knows about your DDD model. But since everything in DDD revolves around your domain model this isn't that bad of a tradeoff. (Especially if your domain model is very well understood and thus doesn't change radically). Be very careful though not to let your domain model be influenced because of database design. It should always be the database who follows, never the domain model where you don't make a certain change because it's hard to migrate in the database.

Reticent answered 15/10, 2016 at 11:37 Comment(0)
D
0

Persistence Logic usually belongs in the Infrastructure Layer, which is in the outer layer of the onion, and since the outer layers of onions depend on the inner layers, and the Domain Layer is in the center, then yes the Infrastructure Layer depends on the Domain Layer.

Devan answered 20/2, 2017 at 18:0 Comment(0)
S
0

In DDD scope, the Persistence Logic should belong to Infrastrure Layer, as detailed persistence implementations are not the concern of Domain Layer.

However, as we think of the architecture of our projects differently, Infrasture Layer could either be dependent on Domain Layer or being depended on by it.

In a traditional layered architecture,
A linear dependency is suggested all the way passed from Presentation Layer, via Application Layer, Domain Layer to Infrastructure Layer.
In this case Infrasture Layer is deemed as an upperstream where both the interfaces and implementations of Persistence Logic are defined.
Domain Layer, as a downstream user, would follow the interface provided by Infrastructure Layer to fetch the entities, convert into domain objects, and then do the domain logic.

Typical codes in java:

// package com.xxxx.product.application
class ProductOrderApp {
    private ProductRepository repository;
    void orderOneProduct(String userCode, String productCode) {
        ProductEntity enitity = repository.getOneByProductCode(productCode); 
        // 1. convert ProductEntity to Product Object
        // 2. pass Product Object to Domain layer to do some logic   
        ...
    }
}


// package com.xxxx.product.domain
class Product { ... }


// package com.xxxx.product.infrastructure
interface ProductRepository {
    // does not depend on any domain concepts
    ProductEntity getOneByProductCode(String code);
}

class ProductRepositoryImpl implements ProductRepository {
    @Override
    ProductEntity getOneByProductCode(String code) {
        ProductEntity entity = ... // get entity from some database
        return entity;  
    }
}

In an onion architecture(as well explained in top answers),
Domain Layer is considered the upperstream, and all other downstream layers should follow the interfaces provided by Domain Layer.
Thus Infrastrure Layer depends on Domain Layer as in it implements the interfaces defined by Domain Layer. Domain Layer does not depend on Infrastructure Layer.

Typical codes in java:

// package com.xxxx.product.domain
class Product { ... }

interface ProductRepository {
    // other Domain Logic can easily call this method as it uses Domain Objects for interection
    Product getOneByProductCode(ProductCode code);
}

// package com.xxxx.product.infrastructure
class ProductRepositoryImpl implements ProductRepository {
    @Override
    Product getOneByProductCode(ProductCode code) {
        ProductEntity entity = ... // get entity from some database
        // persistence logic knows domain objects and do the convertion here
        return convertToProduct(entity);  // convert to domain objects
    }
}
Sierra answered 20/12, 2020 at 8:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.