TECHNICAL FEATURE SET
Domain Driven Design |
Command Sourcing |
CQRS |
Functional Reactive Programing |
Haskell
GSD is a distributed application based on the following concepts :
- Domain Driven Design (DDD)
- Place the project's primary focus on the core domain and domain logic
- Base complex designs on a model of the domain
- CQRS
- It stands for Command Query Responsibility Segregation.
- It also known as the distributed version of DDD (and then DDDD as Distributed Domain Driven Design)
- Command Sourcing ( Event Sourcing ++)
- It's Event Sourcing where commands are also persisted
- Capture all changes to an application state as a sequence of events
- Capture all the commands sent to the system
- Commands sent to the system are stored and consumed asynchronously as opposed to Event Sourcing
- Command losses are reduced when the service is down
- The data flow is pulled as opposed to pushed in Event Sourcing
- Processes are embedded in a stream from A-Z
- This command consumption produces and stores a single transaction :
- It's Event Sourcing where commands are also persisted
data CommandHandlingResult = CommandRejected { reason :: RejectionReason}
| CommandValidated { events :: [Event]}
data CommandTransaction = CommandTransaction {
commandId :: CommandId,
commandOffset :: Offset ,
aggregateId :: AggregateId ,
commandHandlingResult :: CommandHandlingResult }
- Functional Reactive Programing
- it's a programming paradigm for reactive programming (asynchronous dataflow programming) using the building blocks of functional programming (e.g. map, reduce, filter).
- Streams and Logs (FIFO) are natural DDDD Architecture Building Blocks.
- Micro-service Architecture
- Services are small in size
- Messaging enabled
- Bounded by contexts
- Autonomously developed
- Independently deployable
- Decentralized
- Built and released with automated processes.
All these concepts are building blocks for implementing the Kahn process networks (KPNs, or process networks). They are a concurrent model of computation which can be also considered as a Pattern / Architecture for distributed systems.
Related Articles :
- https://martinfowler.com/eaaDev/EventSourcing.html
- http://www.cqrs.nu/faq
- https://thinkbeforecoding.com/post/2013/07/28/Event-Sourcing-vs-Command-Sourcing
- https://blog.jonathanoliver.com/cqrs-sagas-with-event-sourcing-part-i-of-ii/
The GSD application is made of 6 distributed services :
-
cli
- Command Line Interface to pilot the system.- Send commands to the system
- Read eventually up-to-date projections from the Read service
- Read eventually up-to-date projections from a Monitoring service
-
command-sourcer
- Receive commands
- Dispatch and Persist these commands
-
command-consumer
- Command Consumption Orchestration (CQRS Sagas Terminology)- Listen on commands arriving on the command stream for each aggregates
- Re-build the write model from the previous command transactions
- Perform the transactions on each command persisted (
handleCommand
), a command can be :- Accepted (contains events)
- Rejected (contains the reason of rejection)
- Persist these command transactions
-
gsd-read
- Read from the command transaction streams
- Project a model optimised for the read
- Serve that model to the cli service
-
gsd-monitoring
- Read the command transaction and the command streams
- Project a model optimised for monitoring the system
- Serve that model to the cli service
-
eventstore-service
- embedded into a docker container- Implement the
PersistedStreamEngine
interface . - Persist and give access to Logs
- Implement the
Each service is safe and can only be terminated by
- a SIG-INT (releasing resources properly)
- a SIG-KILL
Each service has a built-in bootstrap health-check mechanism and come back in that mechanism whenever it becomes unhealthy.
- Regarding the GSD application
-
cli
is healthy, when the following dependencies are healthy :command-sourcer
command-consumer
gsd-read
gsd-monitoring
-
command-sourcer
is healthy, wheneventstore-service
is healthy -
command-consumer
is healthy, wheneventstore-service
is healthy -
gsd-read
is healthy, wheneventstore-service
is healthy -
gsd-monitoring
is healthy, wheneventstore-service
is healthy
-
Eventuria
is the name of the company hosting the project (root package). By flicking through the codebase under Eventuria
, you'll see the following packages :
-
Adapters
: Contains wrappers, tweaks on external libraries -
Commons
: Tiny Bounded Contexts -
GSD
: GSD Application Bounded Context, you'll find the 4 services cited previously in that docCLI
:gsd-cli
implementationWrite
:gsd-command-consumer
gsd-command-sourcer
Read
:gsd-read
implementationMonitoring
:gsd-monitoring
implementation
-
CQRS
: CQRS Bounded Context (this Library will eventually become a Framework - see Emergent CQRS framework Section )PersistedStreamEngine
- Interface for Reading/Subscribing/Writing messages to Logs (persisted streams)
- Contain one instance for the EventStore
All these packages will eventually be in their own git repository as they get more mature.
command-sourcer
- Handle an Aggregate index (AggregateId Stream)
- Serve Command Requests - Feed the Command Streams (1 Command Stream per Aggregate)
command-consumer
- Per aggregate :- Subscribe to Commands
- Project a write Model
- Handle each command by providing a Command Transaction :
- Accepted (contains events)
- Rejected (contains the reason of rejection)
- Feed the Command Transaction Stream
gsd-read
- Read a Command Transaction Stream
- Project from command transaction to a specific read model
- Serve clients with this model
gsd-monitoring
- Read a Command Transaction Stream
- Project from command transaction to a specific read model
- Serve clients with this model
One of the intents when starting this project was to formalize the CQRS pattern and get eventually a Framework out of a concrete application like GSD. This is what the package Eventuria.CQRS
will eventually become...
To use this framework, the GSD application provides the following :
- a specific WriteModel (GSD
WriteModel
) - a map between the application and CQRS events (GSD
Commands
) - a map between the application and CQRS commands (GSD
Events
) - a Command Consumption Orchestration (GSD
Orchestration
) - 2 functions (
ProjectWriteModel
andHandleCommand
)data CommandHandlingResult = CommandRejected { reason :: RejectionReason} | CommandValidated { events :: [Event]} type ProjectWriteModel writeModel = Maybe writeModel -> CommandHandlingResult -> Maybe writeModel type HandleCommand writeModel = Maybe writeModel -> (Persisted Command) -> IO (CommandHandlingResult)
- GSD
ProjectWriteModel
- GSD
HandleCommand