1

It is my first time in DDD. In company we don't have "domain master". I have only read about DDD I need to implement domain with DDD aproach.

So, I know that in domain there are no place for Database features. But if I would use my domain with Entity Framework and NOSQL database. With EF i need to make collections virtual and in constructor alloce as new. This is bad in DDD?

My code:

 public abstract class Merchant : AggregateRoot
{
    public Company Company { get; set; } // Entity

    public string CIF { get; set; }
    public string NIP { get; set; }
    public string Status { get; set; }

    public Address Address { get; set; } // Entity
    public Group Group { get; set; } // Entity
    public virtual ICollection<Brand> Brands { get; set; } // Brand is entity

    protected Merchant()
    {
        this.Brands = new List<Brand>();
    }
}
Nerf
  • 938
  • 1
  • 13
  • 30
  • Why is the class abstract ? – guillaume31 May 11 '16 at 12:46
  • 2
    Yuu don't **implement** something with DDD, you **identify** the domain model (abstraction) with DDD and that gets implemented. Coding(including design) starts after DDD ends. – MikeSW May 11 '16 at 13:09
  • As a caution: if you don't have access to a domain expert, it's not clear that the project is important enough to your business to justify a full blown DDD approach. "We use domain driven design in areas where our organization derives competitive advantage". (Greg Young, 2001) – VoiceOfUnreason May 12 '16 at 15:32

2 Answers2

4

There are multiple shades of opinion about that issue in the DDD space.

To me, the primary measure of "persistence ignorance" is :

Will a change in my database break things in my domain layer, forcing me to open up the domain model and modify stuff to fix it ?

If we look at your example, the answer is clearly no.

It would have been the case if you had for example data annotations in your entity class referring to table or column names, or if you relied on mapping by convention and changed the Merchant table name to Reseller in the DB. But having a default constructor and virtual property doesn't make your domain class more fragile in the face of database changes.

Then you have a secondary question, a less critical one IMO :

Is the ORM a hindrance in my implementing domain entities just the way I want and as DDD-compliant as they need to be ?

This one is a bit more challenged. It might be, if the ORM forces you to add operations that can leave the domain object in an inconsistent state. I wouldn't consider a parameterless constructor as prone to that though, since it can be private and thus impossible to shoot yourself in the foot with. Same with setters.

Some consider that small traces such as the need for virtual and parameterless constructor violate DDD, because your entities are not pure any more, they contain oddities caused by the presence of an ORM. Therefore, you should create a second "persistence" model to leave the domain model untainted. I don't. I think most of the time it's not worth the tradeoff in terms of complexity - you can live with the small quirks as long as the first rule of persistence ignorance holds.

guillaume31
  • 13,738
  • 1
  • 32
  • 51
  • private setters and non-public default constructor is fine. They are never an issue. Child aggregates on the other hand. They should not be exposed in a world where we embrace encapsulation (to make sure that the root aggregate is in control of it's state). That however is a challenging task with ORMs as they typically need a property. A non-public property is in my eyes a code smell. Thoughts? – jgauffin May 11 '16 at 13:12
  • 1
    You mean child entities, right ? Yes, it is a code smell that shows us that some ORM vendors could do a better job. I'm not sold on the other interpretation to that code smell that requires introducing a whole new layer of indirection to solve it. – guillaume31 May 11 '16 at 13:26
  • Or to be more precise, the interpretation to that code smell that considers that we failed to identify a "persistence model". – guillaume31 May 11 '16 at 13:36
  • Isn't the aggregate already "opened up" (as you call it) by providing public setters and a modifiable collection interface? In my opinion, the aggregate in the example is far to permissive to communicate how it should be properly used. **And I suspect the reason for this is EF compatibility.** I know you have a different opinion on the topic than me, so I'm interested in your view on that :-) – theDmi May 11 '16 at 15:17
  • I meant "physically" open up, as in *open the Domain layer module in your code editor*, don't know if that came across well. My English sometimes fails me ;) – guillaume31 May 11 '16 at 15:32
  • But yes, admittedly the default constructor muddles the entity. Again, it's a tradeoff and I can live with it. You can also add a comment to explain why it is there. The more important thing IMO is that from a correctness PoV, your entity cannot go inconsistent at runtime. – guillaume31 May 11 '16 at 15:32
  • @theDmi I just realized you wrote "public setters" but they can be private or protected with EF, I guess you know that already. So the reason for them being public in the OP's example is not exactly EF compatibility. It might be **people's misconceptions about what is EF compatible or not**, or more probably, the lack of knowledge about encapsulation. – guillaume31 May 11 '16 at 16:01
1

I would be more concerned about having public setters than a protected default constructor or a virtual property. The problem with that is can lead to an inconsistent state of the entity. For example, you may want to validate the address properties to make sure all the required properties are set and the postal code corresponds to the state/country. Another example would be status transitions; once the entity reaches a "final" status, it cannot be changed anymore.

While you can create separate validators for entities and use them before you persist the entities, it defeats the purpose of a rich domain model.

There are a few ways to get around it. You can create DTO objects that mirror the database schema and use hydrators to populate the entities (with protected/internal property setters) from those DTOs assuming the data in the database is always in the consistent state. All the new changes will have to go through entity methods to get validated. Then you would hydrate the DTOs based on the latest entity data and persist it.

CQRS with event sourcing is a more advanced alternative of this that persists all changes as an immutable log/event-store rather than (only) the latest data snapshot. But that is not something that is necessary for every domain scenario.

Dmitry S.
  • 8,373
  • 2
  • 39
  • 49