An entity is the core logic of a service. Entities are the innermost parts of an implementation. In a concentric architecture, entities are at the very center. They are the kernel of a service or component.
Entities are data structures. They have some similarities to the model objects of classic ORM, but that analogy is quite limited and shouldn't be taken too far. An entity can be any kind of data structure, like an object, a struct, or even a hash. An entity doesn't have to implement any special base class or module.
Entities also have behavior. However, any entity method should pertain to the entity's data attributes. Any entity behavior that doesn't either access or modify the entity's attributes should not be part of the entity.
Entities operate entirely in memory. They don't save themselves, they don't retrieve themselves, they don't send messages. They don't have external I/O of any kind under any circumstances. I/O is the domain of elements that are outside of an entity and that interact with an entity, such as handlers or other plain old objects that coordinate interaction between external concerns and core logic.
As in-memory structures without external side effects or prerequisites, they are easy to test.
In practice, an entity receives its data from a projection that is fed the events from an event stream that is read by a store.
class Account include Schema::DataStructure attribute :id, String attribute :customer_id, String attribute :balance, Numeric, default: 0 attribute :opened_time, Time attribute :closed_time, Time attribute :sequence, Integer def open? !opened_time.nil? end def closed? !closed_time.nil? end def deposit(amount) self.balance += amount end def withdraw(amount) self.balance -= amount end def sufficient_funds?(amount) balance >= amount end def processed?(message_sequence) return false if sequence.nil? message_sequence <= sequence end end
# Entity Facts
- Entities are core business logic
- An entity can be any kind of object or data structure
- The are entirely in-memory
- Entities receive their data from projections
- Entities remain in-memory in a store's cache once retrieved
- Entities can be periodically snapshotted to disk
- An entity has no external side effects and no external dependencies
# Ensuring Idempotence
Idempotence is the quality of a message-based system that ensures that messages that have already been processed won't be processed again.
Entities are the pivotal element in a design that is idempotent.
In the example above, the
sequence attribute and the
processed? method are the mechanisms of idempotence protection. Handlers use these mechanisms to decide whether to process a message or to ignore it.
Note: A discussion of the implementation of idempotence is beyond the scope of this user guide. The Account Component example demonstrates a complete implementation of idempotence protections.