2

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?
2
  • Have you looked at Data-Oriented Design, or Component-Entity Systems?
    – Erik Eidt
    Commented Dec 18, 2020 at 15:54
  • @ErikEidt Yes, in fact the page you link to for ECS is the page I found a few years ago that convinced me that ECS solved some of the complexities I ran into while trying to make the game as flexible as possible. I realized that a Tree or Player is an Entity used in a specific way, for a specific purpose. Using DDD, EDA, and CQRS, this would translate into an Aggregate and Read Model Projection. The Components that make up the Entities would be expressed in that Projection, and actions needing to be performed by those Entities would be expressed in the Aggregate.
    – Zymus
    Commented Dec 18, 2020 at 22:22

1 Answer 1

1

The difference between an Aggregate and and Entity is purely conceptual in nature. That is, an Aggregate is just an Entity composed of smaller building blocks. In practice, the client of either of the above needn't have any idea at all how the object is working internally and does not care whether you may conceptualize that object as an Entity or an Aggregate. Therefore your first question doesn't make much sense to me -- ostensibly the answer is, of course, "yes". The number of domain invariants has nothing to do with how one classifies an object in terms of DDD.

As to your second question. While I'm an NOT a game designer, I wouldn't suppose DDD is very common or suitable as a design strategy for a game-type system. DDD excels at modelling systems optimized for change control. That is, DDD is used to manage the complexity that occurs when a system has many discrete invariants (the kind of rules that map most cleanly on LoB-type software), and those invariants change over time. Now, this doesn't mean that DDD can't be used to help inform your design, rather, that games often need to be optimized for other kinds of behaviors (performance being the most relevant here).

In terms of utilizing an ECS pattern, your Game may need to be a single Aggregate Root over everything else. You can see how this may limit the benefits of DDD applied to your Game. Though maybe DDD is appropriate at a more macro level? What other types of systems may need to exist to support your Game? It may be better to focus on using DDD in this space, and treat your Game as more of a "cohesive mechanism".

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.