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
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
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 GitHub - CargoSense/vex: Data Validation for Elixir · GitHub.
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
It’s certainly not intentional ![]()
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 ![]()
Popular in Wikis
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance









