Charles
Charles

Reputation: 3774

Dealing with property duplication

In a demo project I am setting up as a proof of concept I am finding myself with a lot of duplicated DTOs and fields. For instance considering 1 root object representing an item or inventory, I would have the following classes and properties

All these objects are a result of separating my app into the traditional Domain, Application, Presentation layers.

How are you managing all this duplication? Tools like AutoMapper and such help to convert between them, but if I wanted to add a new property to Item that would be used everywhere I would have to update all these models.

Because the domain model may not be exactly the same as the application read model, I understand the need for separate definitions, however this can very quickly become a maintenance nightmare.

Upvotes: 2

Views: 272

Answers (1)

turdus-merula
turdus-merula

Reputation: 8854

Charles,

An approach that might help you get rid of some bits of duplication could be the following:

  • do not add public properties on the entity. As you are using event sourcing, the internal state of the entity will be restored by replaying the events associated with the entity in question. And nobody from outside the entity should know how the reconstructed state of the entity is represented - a series of private fields, an array of string objects, whatever. After all, you can choose to have no internal representation of its state, but implement all the behavior (all the methods) by simply replaying the events each and every time :) So, at one extreme, you may have 1 single field on the entity = a collection of events.

  • Item read model and Response DTO... Make them the same thing! As you are using cqrs, that is, you have already segregated the read model from the write model, there is no need to make a lasagna out of the read-side of the application. It is OK to have a minimum number of abstraction layers on the read-side. The read model is already behavior-less, it is data only. It's a DTO that gets constructed from events, gets persisted into a data storage with a (more or less) denormalized schema and, upon user request, is retrieved from the storage and presented on the UI or so. It's pure data that gets transferred from one place to another. Though, if, for some reason, you have to return to the end user (human or machine) some other data in addition to the data from the read model object, apply basic object composition. Compose two or more behavior-less objects into one such object. And send the latter on the wire.

  • speaking of composition, you may even define a (value) type such as ItemDescriptor [Code, Description, Weight] in a shared library and use it when defining the CreateItem command, the ItemCreated event, the read model, the query request object or so. If you are using a language that supports mixins, then mix that ItemDescriptor in :) Else, basic composition may be applied.

Furthermore, the "maintenance nightmare" can be ameliorated to some extent if packaging by feature would be used instead of packaging by layer.

Also, perhaps this post might help a bit.

Upvotes: 1

Related Questions