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.