Exon hex.pm

A collection of useful concepts for building data backed applications in Elixir

Exon draw inspiration from DDD’s approach to domain modeling. It encourages the use of aggregates, commands and events to describe the application’s domain.

Usage

Add Exon to your mix.exs file:

defp deps do
  [
    {:exon, "~> 0.1.11"},
  ]
end

Concepts

Command

A Command is a module function responsible for a specific write operation of the application.

Command Gateway

A CommandGateway is a module responsible for dispatching commands to their respective aggregate root. A CommandGateway should use Exon.CommandGateway.

Aggregate Root

A module that represents an entity or a group of entities in the domain. Every command is dispatched to a single aggregate root. This makes the aggregate root a transaction boundary for every command in the system. An Aggregate Root should use Exon.AggregateRoot which provides the command registration mechanism using the @command method annotation.

Event Bus

A module responsible for publishing domain events to it’s registered event handlers. An event bus should use Exon.EventBus which provides a GenServer based publisher and the add_handler function to add event handlers.

Event handler

A module responsible of domain logic that should be executed when a specific domain event is raised. An event handler can handle zero or more domain events.

Middleware

A module that is registered using middleware/1 in the command gateway. It’s before_dispatch/2 and after_dispatch/2 functions will be called before and after dispatching the command to the aggregate root.

The before_dispatch/2 can be used to change most aspects of the command execution. For example Exon.Middleware.EctoAggregate will fetch the correct entity from the DB and add it as the first argument for the command method.

The after_dispatch/2 can be used to handle changes that should happen after a successful or failed command execution. For example Exon.Middleware.EctoAggregate will save a changeset in case one is returned from the command.

Example

See the code for TodoApp under test/support/todo_app.