Concepts

This document provides terminology used in the framework and its documentation. You’ll find most of the terms familiar from Domain-Driven Design, CQRS, Event Sourcing or Enterprise Integration patterns.

We give brief descriptions for those who are new to these concepts and to tell how they are implemented in our framework. Terms extending the industry-set terminology are designated as such.

Messaging

Command

Commands are messages that instruct an entity within Spine framework to perform a certain action. Compared with events, a command is not a statement of fact. They are a request, and, thus, can be refused. A typical way to convey refusal is to throw an error or rejection.

In Spine, commands are defined as Protocol Buffer (a.k.a Protobuf) messages in the file which name ends with commands.proto.

Event

Event is something that happened in the past. All changes to an application state are captured as a sequence of events. Events are the main “database” of the application.

In Spine, events are defined as Protobuf messages in the file which name ends with events.proto.

Rejection

Rejections is a special “negative” kind of events that we introduce to differentiate them from regular events. If an event is a fact of something that happened to a domain model, a rejection is a fact that states the reason why a command was not handled.

Consider the following examples of rejections:

  • CreditCardValidationDeclined,
  • OrderCannotBeEmpty,
  • InsufficientFunds.

In Spine, rejections are defined as Protobuf messages in the file which names ends with rejections.proto.

For detailed instructions on defining rejections, please refer to “Working with Rejections” guide.

Acknowledgement

Acknowledgement is an outcome of sending a Command to the Command Service.

It tells whether the Command has been accepted for handling.

Command Handler

Command Handler is an object which receives commands, modifies the state of the application, and generates events if the modification was successful.

Aggregate and ProcessManager are examples one of such classes. The code snippet below given an example of handling a command by an aggregate:

final class TaskAggregate
    extends Aggregate<TaskId, Task, Task.Builder> {
    ...
    @Assign
    TaskCreated handle(CreateTask cmd, CommandContext ctx) {
        return TaskCreated
                .newBuilder()
                .setTask(cmd.getId())
                .setName(cmd.getName())
                .setOwner(ctx.getActor())
                .vBuild();
    }
    ...
}

Event Subscriber

Event Subscriber is an object which subscribes to receive events.

The example below shows how a Projection class subscribed to the TaskCompleted event.

final class TaskProjection
  extends Projection<TaskId, TaskItem, TaskItem.Builder> {
  ...
  @Subscribe
  void on(TaskCompleted e, EventContext ctx) {
      builder().setWhenDone(ctx.getTimestamp());
  }
}

Event Reactor

Event Reactor is an object which usually produces one or more events in response to an incoming event. Unlike Event Subscriber, which always consumes events, a reacting object generates events in response to changes in the domain.

In some cases, Event Reactor may ignore the event, returning Nothing. It usually happens when a method returns one of the Either types, with Nothing as one of the possible options: EitherOf2<TaskReAssigned, Nothing>.

Value Objects

Value Object describe things in a domain model and do not have identity. Value Objects are also immutable. Some examples are:

  • PhoneNumber
  • EmailAddress
  • BarCode

In Spine, Value Objects are defined as Protobuf messages.

Entities

Entities are the main building blocks of a domain model. They have a unique identity and modify their state during their lifespan.

Identifier

The framework supports the following types of identifiers:

  • Integer,
  • Long,
  • String,
  • A generated Java class implementing the Message.

Examples of entity IDs used by the framework: CommandId, EventId, UserId, TenantId.

We highly recommend using message-based IDs to make your API strongly pronounced and type-safe.

Aggregate

Aggregate is the main building block of a business model. From the application point of view it consists of the following:

  1. Commands which arrive to it.
  2. Events which appear in response to these commands.
  3. How these events influence the state of an aggregate.

Aggregates guarantee consistency of data modifications in response to commands they receive. Aggregate is the most common case of Command Handler. In response to a command, it produces one or more events modifying own state. These events are used later to restore the state of the aggregate.

In Spine, aggregates are defined as Java classes, and their states are defined as Protobuf messages.

Process Manager

Process Manager is an independent component that manages the cross-aggregate business flows. It serves as a mediator by remembering the state of the flow and choosing the next step based on the intermediate results.

To do so, a Process Manager can be both Command Handler and Event Reactor. Also, it can emit Commands to other Aggregates and Process Managers.

In Spine, Process Managers are defined as Java classes, and their states are defined as Protobuf messages.

Projection

Projection is an Event Subscriber which transforms multiple events data into a structural representation. Projections are the main building blocks of the Query side of the application.

In Spine, Projections are defined as Java classes, and their states are defined as Protobuf messages.

Repository

Repository encapsulates storage, retrieval, and search of Entities as if it were a collection of objects. It isolates domain objects from the details of the database access code.

The applications you develop using Spine usually have the following types of repositories:

Snapshot

Snapshot is a state of an Aggregate. A snapshot ”sits” in between events in the history of the Aggregate to make restoring faster.

When an Aggregate is loaded, the AggregateStorage reads events backwards until encounters a snapshot. Then the snapshot is applied to the Aggregate, and trailing events are played to obtain the most recent state.

Services

Services are used by a client application for sending requests to the backend.

In Spine, services are based on gRPC.

Command Service

The Command Service accepts a command from a client-side application and redirects it to the Bounded Context to which this command belongs. This means that there is a context in which there is a handler for this command. Otherwise, the command is not acknowledged.

Query Service

Query Service returns data to the client applications in response to a query. The query is a request for the following:

  • state of one or more aggregates or their fragments;
  • one or more projection states or their fragments.
  • one or more process manager states or their fragments.

Subscription Service

Subscription Service allows to subscribe to something happening inside a Bounded Context.

There are two options for subscription:

  • receive changes of an Entity state for Projections, Process Managers and Aggregates;
  • be notified of domain Events.

Architectural

Bounded Context

Bounded Context is an autonomous component with its own domain model and its own Ubiquitous Language. Systems usually have multiple Bounded Contexts.

Orders, UserManagement, Shipping as examples of the contexts of an online retail system.

Message Buses

Command Bus

This is a message broker responsible for routing the command to its handler. Unlike a Command Handler, it does not modify the application business model, nor produces domain events.

There can be only one handler per command type registered in a Command Bus.

Event Bus

This bus dispatches events to entities that are subscribed to these events or react on them.

Message Stores

Command Store

This store keeps the history of all the commands of the application and statuses of their execution.

Event Store

This store keeps all the events of the application in the chronological order, which also called Event Stream. This is the main “database” of the Bounded Context.

New projections are built by passing the event stream “through” them.

Integration Event

Integration Events are events used to communicate between different Bounded Contexts.

In Spine, every domain Event may become an Integration Event, if it is emitted by the given Bounded Context and consumed by another Bounded Contexts.

Aggregate Mirror

In Spine, Aggregate Mirror contains the latest state of an Aggregate. It “reflects” how it “looks” at the time of the last update.

Stand

In Spine, Stand is a read-side API facade of a BoundedContext.

System Context

System Context orchestrates the internal Spine framework entities that serve the goal of monitoring, auditing, and debugging of domain-specific entities of the enclosing Bounded Context. Users of the framework do not interact with this component.