Persistence ignorance and DDD reality

主宰稳场 提交于 2019-12-21 05:43:06

问题


I'm trying to implement fully valid persistence ignorance with little effort. I have many questions though:

The simplest option

It's really straightforward - is it okay to have Entities annotated with Spring Data annotations just like in SOA (but make them really do the logic)? What are the consequences other than having to use persistance annotation in the Entities, which doesn't really follow PI principle? I mean is it really the case with Spring Data - it provides nice repositories which do what repositories in DDD should do. The problem is with Entities themself then...

The harder option

In order to make an Entity unaware of where the data it operates on came from it is natural to inject that data as an interface through constructor. Another advantage is that we always could perform lazy loading - which we have by default in Neo4j graph database for instance. The drawback is that Aggregates (which compose of Entities) will be totally aware of all data even if they don't use them - possibly it could led to debugging difficulties as data is totally exposed (DAO's would be hierarchical just like Aggregates). This would also force us to use some adapters for the repositories as they doesn't store real Entities anymore... And any translation is ugly... Another thing is that we cannot instantiate an Entity without such DAO - though there could be in-memory implementations in domain... again, more layers. Some say that injecting DAOs does break PI too.

The hardest option

The Entity could be wrapped around a lazy-loader which decides where data should come from. It could be both in-memory and in-database, and it could handle any operations which need transactions and so on. Complex layer though, but might be generic to some extent perhaps...? Have a read about it here

Do you know any other solution? Or maybe I'm missing something in mentioned ones. Please share your thoughts!


回答1:


I achieve persistence ignorance (almost) for free, as a side effect of proper domain modeling.

In particular:

  • if you correctly define each context's boundary, you will obtain small entities without any need for lazy loading (that, actually becomes an antipattern/code smell in a DDD project)
  • if you can't simply use SQL into your repository, map a set of DTO to your db schema, and use them into factories to initialize entity classes.

In DDD projects, persistence ignorance is relevant for the domain model itself, not for repositories, factories and other applicative code. Indeed you are very unlikely to change the ORM and/or the DB in the future.

The only (but very strong) rational behind persistence ignorance of the domain model is separation of concerns: in the domain model you should express business invariants only! Persistence is an infrastructural concern!

For example without persistence ignorance (and with lazy loading) the domain model should handle possible exceptions from the db, it's complexity grows and business rules are buried under technological details.




回答2:


Personally I find it near impossible to achieve a clean domain model when trying to use the same entities as the ORM.

My solution is to model my domain entities as I see fit and ensure that any ORM entities don't leak outside of the repositories. This means that my repositories accept and return domain entities.

This means you lose "most of your ORM goodness" and end up "using your ORM for simple CRUD operations".

Both of these trade-offs are fine for me, I would rather have a clean domain model that I can use, rather than one polluted with artefacts from my DB or ORM. It also cuts down the amount of time I spend "wrestling with my ORM" to zero.

As a side-note, I find document databases a much better fit for DDD.




回答3:


Once you will provide persistence mapping in you domain model:

  • your code depends on framework. If you decided to change this framework, you want to change persistence layer and model layer source code - more work, more changes, more merging of code etc.
  • your domain model jar file depends on spring/nhibernate jars etc.
  • your classes become larger and larger how business code and persistence related code grows

I've to admit that I dont understand harder and hardest option.

We used separated interfaces and implementations for domain entities. Provide separated mapping files using Hibernate along with repositories.

Entities are created using factory (or repository later), identifier is generated within persistence layer, entity does not need it until it's being persisted.

Lazy loading is provided by special implementation of List once:

  1. mapping of an entity contains it
  2. entity/aggregate is fetched from persistence layer

The only issue is related to transaction as when you use lazy-loaded collection out of transaction scope, it fails.




回答4:


I would follow the simplest option unless I ran into a stone wall. There are also pitfalls such as this when you adopt pi principle.

Somtimes some compromises are acceptable.

public class Order {
    private String status;//my orm does not support enum

    public Status status() {
        return Status.of(this.status);
    }

    public is(Status status) {
        return status() == status;//use status() instead of getStatus() in domain model
    }
}


来源:https://stackoverflow.com/questions/18350605/persistence-ignorance-and-ddd-reality

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!