Commands and domain objects, at least in my world, have different design constraints. In particular, commands are part of the API surface - they are part of the contract with other services - and therefore need to have compatible definitions over long periods of time. Domain objects, on the other hand, are local to our current way of doing things - they are part of our organization of data within the black box. So we can change those at any cadence we like.
Commands that cross process boundaries are messages, which is to say byte[]s
. That's the bit that needs to be stable, both in form and semantics.
byte[]
is domain agnostic, and it's fairly common to pass through several other domain agnostic intermediate stages in "parsing" the message
byte[] -> utf8
utf8 -> DOM
DOM -> Dictionary
...
but we're generally driving toward a domain specific expression of the contract.
See, for instance Mark Seemann
At the boundaries, applications are not object-oriented.
A DTO is a representation of such a piece of data mapped into an object-oriented language.
Having coerced the byte[]
into a form that is convenient for querying, then we can start thinking about whether or not we want to use that data to start initializing "objects".
The other question that you may be asking - is there value in a having the message data within a generic metadata "envelope". That kind of pattern occurs all the time - the most familiar example being that an HTTP POST is a bunch of generic headers attached to a message-body.
The data and the metadata are certainly separate concerns; it definitely makes sense to keep them distinct in your solution.
I think compositing the data structures, rather than inheriting them, is going to be the more maintainable option.
public class Envelope<Message> ....
might be a reasonable starting point.