DEV Community

Cover image for Ming: A CQRS Experiment in Elixir
Rafael Andrade
Rafael Andrade

Posted on

Ming: A CQRS Experiment in Elixir

Introduction

Learning a programming language is most effective when paired with hands-on projects, as real-world challenges accelerate mastery. With a background in C# and active contributions to the Brighter framework, I decided to build a project called Ming to deepen my Elixir skills. This project explores Elixir’s functional programming paradigm while implementing patterns like CQRS (Command Query Responsibility Segregation).

Ming project

Ming draws inspiration from the Brighter framework and Commanded. Its core focus is to replicate and adapt CQRS principles from C# to Elixir’s.

Name

Maybe you are asking yourself why Ming and if there is any meaning, I was looking a library name that was short easy to pronounce in English and it should be close the Brighter, I couldn't find any good name in Portuguese, the Chinese world Ming (明) is very close to Brighter and it's short and easy to pronounce.

Core Concepts

Handlers

Handlers in Ming are simple modules defining an execute/2 function, which processes commands/events and an execution context. For example:

defmodule SampleHandler do
  @moduledoc false

  def execute(%Ming.ExampleCommand1{}, %Ming.ExecutionContext{}), do: :ok
end
Enter fullscreen mode Exit fullscreen mode

This mirrors the straightforward design of C# interfaces but leverages Elixir’s pattern matching for clarity.

Routing Commands/Events

To register handlers, use use Ming.Router to define dispatch rules:

defmodule Ming.SampleRouter do
  @moduledoc false
  use Ming.Router

  dispatch [SampleCommand, SampleEvent], to: ReturningAKeyHandler
  dispatch SampleEvent, to: ReturningAKeyHandler
end
Enter fullscreen mode Exit fullscreen mode

The router generates send/publish pipelines. If multiple handlers are registered for a command, Ming returns {:error, :more_than_one_handler_founded} to enforce explicit design.

Middleware

Add middleware to pipelines using middleware/1, send_middleware/1, or publish_middleware/1:

defmodule Ming.SampleRouter do
  @moduledoc false
  use Ming.Router

  middleware SomeMiddleware

  dispatch [SampleCommand, SampleEvent], to: ReturningAKeyHandler
  dispatch SampleEvent, to: ReturningAKeyHandler
end
Enter fullscreen mode Exit fullscreen mode

This allows cross-cutting concerns like logging or transactions, akin to .NET’s middleware pipeline but with Elixir’s functional purity.

Macros

Elixir has macro which is interesting feature, allow to generate code during compile, but it's difficult to debug and understood what is wrong (maybe it's because I don't have much experience), the closed feature that in C# is the source code generator, but the source code generator require knowledge in Roslyn API.

Command Processor

In Brighter, IAmACommandProcessor centralizes command send/event publish. Ming adapts this with Ming.CommandProcessor:

defmodule SampleCommandProcessor do
  use Ming.CommandProcessor, otp_app: :sample

  router SampleRouter
end
Enter fullscreen mode Exit fullscreen mode

This module registers routers and serves as the entry point for interactions, leveraging Elixir’s OTP for robustness.

Roadmap for Improvements

  • Documentation: Follow the Elixir guide’s structure to improve accessibility and publish via Hex.pm.
  • Features: Add support to consumer and producer message from messaging gateway
  • Testing: Add comprehensive tests to validate error handling and middleware behaviour.

Conclusion

Ming is a personal project for CQRS and help me to understood Elixir features and ecosystem. For learners, starting with small projects and leveraging resources like Programming Elixir or the Elixir official guides provides a balanced path to mastery.

Reference

GitHub of Ming

Top comments (0)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.