kraades

kraades

DDD/CQRS/ES/NoSQL and functional programming

I was wondering if anyone is using Domain Driven Design and/or CQRS and/or Event Sourcing and/or NoSQL storage for a business application that is written in a functional language (in particular Elixir and/or Phoenix).

Hit or miss? I am getting some mixed signals. Any thoughts would be appreciated.

What is it?

Domain Driven Design

CQRS, Task Based UIs, Event Sourcing agh! - Greg Young
http://codebetter.com/gregyoung/2010/02/16/cqrs-task-based-uis-event-sourcing-agh/

CQRS - Martin Fowler

Event Sourcing - Martin Fowler

Some links…

Functional Data - Greg Young
Event Sourcing is “Functional Data Storage”

A Functional Foundation for CQRS/ES - Mathias Verreas

Domain Driven Design with the F# Type System - Scott Wlaschin

CQRS with Elixir and Phoenix - Jean-François Cloutier

Building a CQRS/ES web application in Elixir using Phoenix
Case study describing how I built a web app following a Command Query Responsibility Segregation and event sourcing pattern.

Most Liked

slashdotdash

slashdotdash

I’ve created an “awesome list” of Elixir and CQRS/ES resources: Awesome Elixir and CQRS.

The list is designed for only CQRS/ES resources that explicitly target Elixir/Erlang, as there’s an existing awesome collection of general domain-driven design content.

Contributions via pull request most welcome.

hubertlepicki

hubertlepicki

I am using CQRS in one project. So this is qorking, and I see no reason why it would not.

CQRS/DDD and friends are not bound to object oriented programming at all. Also, Elixir/Erlang are not that much different from object oriented languages when you think about it.

What I am doing at the moment is that I have two supervised workers, started when my application starts:

  • CQRS.Commands
  • CQRS.Events

there’s little bit of DSL in CQRS.Commands to define the list of commands my system accepts. These look like:

public MyApp.LogIn   
public MyApp.Register
private MyApp.CreatePost
private MyApp.DeletePost`

I have a single controller exposed on /api/commands that accepts params that have command name and payload. Public commands are ones that do not require User fetched (have plug for that). Private commands are the ones that get forwarded payload, but additionally current user.

Command looks like this inside:

defmodule MyApp.Commands.Register do
  alias MyApp.Repo
  alias MyApp.User
  alias MyApp.Events

  import  MyApp.Validator

  alias MyAppCommands.Register.Form

  def execute(params, _ \\ nil) do
    form = Form.from_params(params)

    if valid?(form) do
      Events.trigger("UserRegistered", event_data(form))

      {:ok, %{message: "email conrirmation needed"}}
    else
      {:error, errors(form)}
    end
  end

  defp event_data(form) do
    %{
      id: UUID.uuid4(),
      first_name: form.first_name,
      last_name: form.last_name,
      email: form.email,
      lang: form.lang,
      password_hash: Comeonin.Bcrypt.hashpwsalt(form.password),
      email_confirmation_token: Ecto.UUID.generate
    }
  end

  defp token_for_user(user) do
    Phoenix.Token.sign MyApp.Endpoint, "user_id", user.id
  end
end

and in my system commands can either succeed :ok , then generate some events, or fail (return tuple of :error and validation messages.

I do simple validations with https://github.com/CargoSense/vex.

Generated events are being dispatched by my CQRS.Events, that is also a bit of DSL that lists all the events that can happen. They return nothing and they should succeed. I do not have the strategy worked out yet on what to do when they fail. I am experimenting here, not everything is yet perfect.

But basically, commands gets executed, generates some events, those events are handled by events handlers. This is all happening in two workers that are GenServers, so one thing at a time.

In addiion to that I package all my queries into MyApp.Queries… etc. Events modify data, queries read data, I have clear separation here.

Queries are executed normally in Phoenix controllers.

I use Phoenix’ views to serialize results of my queries and send over to client either via JSON or just embed the thing into conn and pass to view.

I haven’t figured everything out yet. I will wrap it up in a library, and write a blog post soon. Maybe it’ll be useful for someone and maybe I get some good feedback. I am not CQRS/ddd expert, so will need that.

sasajuric

sasajuric

Author of Elixir In Action

It’s certainly not intentional :slight_smile:
That said, I’ve read the Evans book a long time (~ 10 years) ago, so it’s possible that some ideas got stuck in my subconsciousness and are still present in my coding style :slight_smile:

hubertlepicki

hubertlepicki

OK @josevalim, I think there is some definitions mismatch. In DDD/CQRS we have a command, which has a name, data, possibly also ID and timestamp (depending on implementation), and a command handler.

So a command, quite naturally fit into a module and could be:

%TransferMoney{from: “SOME IBAN”, to: “SOME IBAN”, amount: 1234)

and the command handler will be a function.

BTW: Have a look at this project on GitHub: https://github.com/slashdotdash/commanded that is pretty young but I did give it a shot yesterday and it seems to work surprisingly well and has some advanced features.

Where Next?

Popular in Wikis Top

axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 45766 226
New
swelham
Introduction After some discussion with a few other members we thought it might be an idea to start a thread where we can post about libr...
New
Rich_Morin
I’d like to start a discussion of data serialization formats, in the context of Elixir. The rest of this note is a combination of persona...
New
AstonJ
Wonder if we can compile a list of learning resources, blog posts, talks, threads etc to help those who are just learning about Contexts....
New
ibgib
Popular Elixir Packages List of popular Atom.io Elixir Packages. These can be installed via atom’s package center or a command line with ...
New
shavit
To transcode the video there is FFMPEG. On Demand When a user uploads a video, the app renames and copy the file to a path, then call F...
New
BartOtten
A wiki for Doom Emacs Doom is a configuration framework for GNU Emacs. It focuses on performance and customizability. It can be a founda...
New
nicbet
Introduction Now that the language is picking up support and maturing nicely, I’d like to start a collection of common and recurring Elix...
New
TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
273 38985 115
New
blackode
Hi and Hello Every Elixirian. After Learning the Elixir basics, I struck then. I have no idea of how to put my Elixir Knowledge in pract...
New

Other popular topics Top

yurko
Here are few pieces of (common) Linux knowledge that we use for reasonably small one server apps. We use Ubuntu but this should work for ...
New
Tee
can someone please explain to me how Enum.reduce works with maps
New
chrismccord
This release brings a number of exciting features, including integration with the new Phoenix LiveDashboard and Phoenix LiveView. There h...
New
script
If I have a string “1000 cfu/ml” . I want to remove the characters and / and space . So the string is like this "1000" What is the ...
New
vac
Hi, I'm quite new in Elixir and I'm trying to format a string to a PEM format. I have the certificate value like MIIDBTCCAe2...... and ...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
chensan
I have a User schema with a :from_id field set to type :string: defmodule TweetBot.Repo.Migrations.CreateUsers do use Ecto.Migration ...
New
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 42633 214
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New

We're in Beta

About us Mission Statement