In my Domain, I have numerous objects that are expressed by Identity alone. Specifically, several of my Subdomains exist only to represent something that has been created.
For example, in a video game with combat, I have a Weapon concept. Each Weapon is Unique. A
Weapon(bronze_sword) is different than a
Weapon(steel_dagger). Third-party content is a significant driving factor in the game. A developer could, at any moment, decide to create a new
Weapon(silver_mace). I don't know what Weapons they could decide to make, nor do I want to overly constrain them in their decisions.
A developer could decide that for their needs, a Weapon deals a certain amount of Damage. I'm not natively providing the concept of Damage, so this would exist explicitly in their Domain. Another developer could decide that for their needs, a Weapon has a particular 3d Model. I'm not natively providing the concept of a 3d Model, so this would exist explicitly in their Domain. Both of these developers though would leverage the native concept of a Weapon, which I provide. If a developer talks about the
Weapon(bronze_sword), other developers will know which context the conversation is happening in, and which Weapon is the subject of the conversation, despite the fact that they would still have their own, separate, Domain.
I am providing Core Concepts that other developers can talk about, with a shared understanding, and set of expectations. However, I do not know what these developers will create, or what meaning those things will have in their respective contexts. I'm not requiring all Weapons to have Damage, nor am I requiring all Weapons to have a 3d Model. I am only providing the concept (Weapon) and Identity (bronze_sword). This means that any, and every, possible attribute, or association, exists in some other context. Effectively, this means that my source code will not have any mention, class, interface, or method, describing or using Damage or 3d Models.
Based on this understanding and desire, it feels like the concepts I provide, like Weapon, are Entities. They are Unique, long-lived, and change throughout its lifetime (though the change happens in a separate Context that I do not control). From reading the Blue Book and Red Book, persistence and reconstitution focus more on the Aggregate level. Repositories storing and rebuilding Aggregate instances. Aggregates though handle some level of invariants, transactionally consistent boundaries, things that must always be satisfied. In my context, since only the Identity is provided, and the only thing I care about is whether or not an Identity exists (and subsequently, can be associated with in another Context), it doesn't feel like these concepts stand up to the level of Aggregate. There doesn't seem to be any transactional consistency I have to worry about. Weapons are created once, and exist until they are removed/deleted. In my context, no other change is possible, because nothing else is associated with the Weapon.
An additional complication, is a desire to derive the entire state of the game from an Event Store. In my case, creating a Weapon would be conveyed as a
WeaponCreated Domain Event, persisted in the Event Store. From the Red Book though, this is discussed in the context of Aggregates, CQRS, and how to use them together. Because a Weapon doesn't seem to exist as an Aggregate, it feels off somehow to use that strategy for this purpose. I could kind of reason that a Weapon is in fact an Aggregate, if I add some "not-saying-a-whole-lot-with-a-lot-of-words" fluff; like "a Weapon can only be created once", and "a Weapon can only be deleted once, if it has been previously created", both of which feel too obvious to enter the realm of invariants; the first being a natural property of Entities, and the second being a natural property of a lifecycle (something can't happen to something if that something doesn't exist yet). Additionally, using this strategy (and other parts of DDD), most Domain Events come from Aggregates, not Value Objects, Repositories, Factories, or event Entities. The Aggregate reacts to the Commands, and fires appropriate Domain Events.
Based on the (apologetically long) setup, the question boils down to these aspects:
- Do the natural properties of Entities (creation, uniqueness, and lifecycle) constitute sufficient invariants to push a Weapon to an Aggregate, despite it not changing in my Domain?
- Is there something fundamentally wrong with using Aggregate+Event Sourcing for concepts like Weapon, which exist primarily as Typed Identity Value Objects for other Domains to use?