Translating domain elements into services
Domain models contain a few well-defined types:
- An Entity is an object with a fixed identity and a well-defined “thread of continuity” or lifecycle. An oft-cited example is a Person (an Entity). Most systems will need to track a Person uniquely, regardless of name, address, or other attribute changes.
- Value Objects do not have a well-defined identity, but are instead defined only by their attributes. They are typically immutable, so that two equal value objects remain equal over time. An address could be a value object associated with a Person.
- An Aggregate is a cluster of related objects treated as a unit. It has a specific entity as its root, and defines a clear boundary for encapsulation. It is not just a list.
- Services are used to represent operations or activities that are not natural parts of entities or value objects.
Domain elements in Game On!
As mentioned in 1.3.1, “The meaning of “small”” on page 4, we built the game around the notion of a Player, an obvious Entity. Players have a fixed id, and exist for as long as the player’s account does. The player entity has a simple set of value objects, including the player's username, favorite color and location.
The other significant element of the game, rooms, don’t map so obviously to an Entity. For one thing, room attributes can change in various ways over time. These changeable attributes are represented by a Value Object containing attributes like the room’s name, descriptions of its entrances, and its public endpoint. Further, the placement of rooms in the map can change over time. If we consider each possible room location as a Site, we end up with the notion of a Map as an Aggregate of unique Site entities, where each Site is associated with changeable room attributes.
Mapping domain elements into services
Converting domain elements into microservices can be done by following a few general guidelines:
- Aggregates and Entities should be converted into independent microservices, using representations of Value Objects as parameters and return values.
- Domain services (those not attached to an Aggregate or Entity) should align with independent microservices.
- Each microservice should handle a single complete business function.
Let’s explore this process by applying these guidelines to the domain elements listed above for Game On!, Figure 2-1 on page 14.
The Player service provides the resource APIs8 to work with Player entities. In addition to standard CRUD (Create, Read, Update, Delete) operations, the Player API provides additional operations for generating user names and favorite colors, and for updating the player’s location.
The Map service provides the resource APIs9 to work with Site entities, allowing developers to manage the registration of room services with the game. The Map provides CRUD operations for individual Sites within a bounded context. Data representations inside the Map service differ from those shared outside the service, as some values are calculated based on the site’s position in the map.
Some additional services from the game that we haven’t talked about:
- Mediator – The Mediator is a service that splintered out of the first implementation of the Player service. Its sole responsibility is mediating between two WebSocket connections: one long-running connection between the client device and the Mediator, and another connection between the Mediator and the target independent room service. From a domain modelling point of view, the Mediator is a domain service.
- Rooms – What about individual room services? Developers stand up their own instances of rooms; for our own modeling purposes, we treat rooms, even our own, as outside actors.