Aggregates Composition: A new view on Aggregates - Jérémie Chassaing - DDD Europe 2023
Summary
TLDRスクリプトは、ホスピタリティ業界で15年間働いた外国人の専門家が、ホテルの予約やプランニングを管理する会社で建築家として働いていることを紹介しています。講演では、集約、構成、そして「decider」という用語について説明し、集約の定義のあいまいさと力、またその弱点についても触れています。deciderパターンを紹介し、これは集約を明確な方法で書くことができ、インメモリやイベントソーシングなどの異なる方法で動作する集約を作成する方法を説明しています。また、deciderを組み合わせて複雑なシステムを構築する方法も示されています。
Takeaways
- 🌟 集約化とコンポジションの概念が紹介され、集約化は境界内の一貫性を保つもの、コンポジションは複雑性を減らすために使用されることについて説明されています。
- 🔍 集約化の定義は曖昧であり、強みと弱みの両方を持っていると指摘されています。集約化は内部の一貫性を保つが、どのようにそれを管理するかは明確にしていません。
- 📈 集約化を設計する際には、小規模な集約化が独立して動作する多くの小さなピースになることがあり、これによりコンカレンシーやインフラストラクチャの複雑性が増大します。
- 🛠️ 問題を解決するために提案された「Deciderパターン」。このパターンは、特定の形状を持つ集約化を定義し、興味深い性質を持つことを説明しています。
- 🔧 Deciderパターンは、コマンドを受け取り、状態を変化させるだけでなく、イベントを出力する機能も持っています。これにより、永続化やイベントソーシングに使用できます。
- 🔄 Deciderパターンは、不変データ構造を使用し、状態の変更を純粋な関数で管理します。これにより、テストや理解が容易になります。
- 📚 シンプルなドメイン例(電球と猫)を使用して、Deciderパターンが実装され、テストされ、実行される方法が説明されています。
- 🔗 複数のDeciderを組み合わせて、1つのDeciderとして扱うことができる。これにより、関連するドメインロジックをグループ化し、管理が容易になります。
- 🔄 永続化とイベントソーシングの両方にDeciderパターンを使用することができ、インフラストラクチャに依存しないドメインロジックの実装が可能になります。
- 🎯 Deciderパターンを使用することで、ドメインロジックのテストが容易になり、状態の変更に関連するテストも簡単に行えます。
- 🛠️ Deciderパターンは、ドメインロジックをシンプルで再利用可能な形で構築し、様々な方法で実行可能にすることができる強力なツールです。
Q & A
どのような職業の人物が話している?
-脚本の人物は15年間ホテルの予約やプランを管理する会社で働いている建築家です。
集約(Aggregate)とは何ですか?
-集約は、境界内の一貫性を保持するものであり、内部は一貫性がある必要がありますが、どのようにそれを管理するかについては言及されていません。
Deciderパターンは何を可能にしますか?
-Deciderパターンは、集約を明確に定義された形で書くことを可能にし、特定の型を持つ異なるものを扱うことができます。
Deciderパターンの利点は何ですか?
-Deciderパターンの利点は、永続化に関連するコードを変更することなく、ドメインコードをテストし、インメモリで実行することができます。
どのようなシンプルなドメイン例が挙げられましたか?
-シンプルなドメイン例として、電球と猫が挙げられました。電球はソケットに取り付けられ、使用回数に応じて故障する可能性があります。猫は寝ていると觉醒しているという2つの状態があります。
どのようにしてDeciderをテストするのか?
-Deciderをテストするためには、期待されるイベントと実際の出力が一致していることを確認するBDD(Behavior Driven Development)テストが使用されます。
インメモリでのDeciderの実行方法は何ですか?
-インメモリでのDeciderの実行では、状態を変更するための命令を送ることができます。状態はミュータブルな変数として扱われ、各命令を処理することで新しい状態が生成されます。
状態を永続化するために何が必要ですか?
-状態を永続化するためには、シリアライザーとキーバリューストア(またはイベントストア)が必要です。シリアライザーは状態を文字列に変換し、キーバリューストアに保存します。
Deciderを複数のインスタンスで実行するにはどうすればいいですか?
-Deciderを複数のインスタンスで実行するためには、各インスタンスに一意の識別子を割り当て、状態を辞書(またはマップ)として管理する必要があります。
プロセスとは何ですか?
-プロセスは、イベントをリッスンしてコマンドを発行し、内部状態を持つステートマシンです。プロセスは、新しいイベントを生成するDeciderと組み合わせることができます。
Deciderとプロセスの組み合わせの利点は何ですか?
-Deciderとプロセスの組み合わせにより、複数のドメインロジックを単一のユニットとして実行できます。これにより、インフラストラクチャの変更なしにインメモリ実行とイベントソーシングの間を簡単に切り替えることができます。
Outlines
🏢 多国籍ホスピタリティ企業の建築家としての経験と新しい作業の紹介
スピーカーは15年間 hotellity 企業で働いており、その企業は世界中のホテルの予約や計画を管理するものであると説明しました。彼はその企業の建築家であり、新しい作業について話すことができるが、その作業は最近のものであり、まだ完全に記録されていないと述べました。スピーカーは実演を通じて、コードを用いてそれらを紹介する予定であり、集約、構成、そして「decider」という用語について話すことになると述べました。
📊 集約とdeciderパターンについて
スピーカーは集約の定義について説明し、集約は境界内で一貫性を保つものであると述べました。境界内のものは一貫性を保つ必要がある一方、境界外のものは一貫性を保つ必要がないと指摘しました。また、スピーカーは集約の複雑性を減らすために、小規模な集約を独立した要素やサービスに分割し、必要に応じてグループ化することで管理しやすくなると説明しました。deciderパターンについても触れ、それは集約を明確に定義した形で、興味深い特性を持つ集約を記述する方法であると述べました。
🔧 Deciderパターンの具体的な例
スピーカーはF#言語を使用して、deciderパターンの具体的な例を示しました。decider型を作成し、その型はジェネリックであり、異なる型に対して動作することができると説明しました。deciderパターンはコマンドを受け取り、イベントを出力するものであり、状態を管理するために必要とされると述べました。deciderパターンの構成には、decide関数、evolve関数、初期状態、およびターミナル関数が含まれることが示されました。
💡 シンプルなドメインのdeciderパターンの例
スピーカーは、電球と猫のシンプルなドメインを使用して、deciderパターンの例を説明しました。電球はソケットに差し込むことができ、猫は目覚めてると寝ているの2つの状態を持つと説明しました。この例では、電球を操作するコマンド(電球を差し込む、開ける、閉める)とイベント(電球が差し込まれた、開けた、閉まった)が定義され、deciderパターンがどのように機能するかを説明しました。
📈 テストと実行可能なdeciderパターン
スピーカーはdeciderパターンをテストする方法と、インメモリで実行する方法について説明しました。テストは、特定のコマンドが期待されるイベントを生成することを確認するものであり、インメモリ実行は、状態をミュータブル変数として保持することで行われます。この方法により、テストが容易になり、状態の変更を自由に行えることが示されました。
🔄 状態の永続化とイベントソーシング
スピーカーは、状態を永続化し、イベントソーシングを使用する方法について説明しました。永続化は、データベースに状態を保存することで行われ、イベントソーシングは、イベントを介して状態を更新する方法です。スピーカーは、簡単なキーバリューストアとイベントストアの玩具的な実装を使用して、このプロセスを説明しました。
🎵 複数のdeciderを組み合わせる
スピーカーは、複数のdeciderを組み合わせて一つのdeciderを作成する方法について説明しました。この方法により、異なるドメインモデルを一つに統合することができ、同じdeciderを繰り返し使用することができると述べました。また、中性要素のdeciderを作成し、それを使用して複数のインスタンスを一つのdeciderにまとめることもできました。
🤖 状態マシンとしてのプロセス
スピーカーは、プロセス作为一种状态机について説明しました。プロセスは、イベントをリッスンしてコマンドをエミットし、内部状態を持つものであり、異なる状態间的遷移を定義することができます。スピーカーは、プロセスとdeciderを組み合わせて、光がONになると猫を目覚めるという動作を実装する方法を示しました。
🚀 統合と柔軟性
スピーカーは、deciderパターンとプロセスを組み合わせて、柔軟性のあるシステムを構築する方法について最後に説明しました。この方法では、インメモリ実行、状態データベース、イベントソーシングなど、さまざまな実行環境を簡単に切り替えることができると強調しました。また、コードを変更することなく、さまざまな実行環境で動作するようにシステムを構築することができると述べました。
Mindmap
Keywords
💡aggregate
💡composition
💡decider pattern
💡event sourcing
💡state
💡command
💡event
💡concurrency
💡immutable data structure
💡pure functions
💡behavior driven test
Highlights
The discussion introduces the concept of aggregates and their role in maintaining consistency within their boundaries while allowing for complex interactions outside of them.
The importance of managing small aggregates and the challenges that arise from the concurrency and infrastructure required to run them is emphasized.
The Decider pattern is introduced as a solution to write aggregates in a well-defined way, providing a specific shape for aggregates with interesting properties.
The Decider pattern enables the running of classic load state safely without touching the domain code, making it versatile for different types of persistence.
The concept of a boundary in aggregates is explored, highlighting how it defines the consistency required within the system and the complexity that arises from managing interactions across boundaries.
The idea of grouping and splitting aggregates is discussed, along with the potential friction and challenges that come with reorganizing the system's structure.
The implementation of the Decider pattern is explained through the use of F#, showcasing its simplicity and powerful type system.
The concept of a 'command' and 'event' within the Decider pattern is introduced, explaining how they represent changes and outcomes within the system.
The role of the 'evolve' function in the Decider pattern is discussed, detailing how it manages state changes based on events.
The importance of having an initial state and a terminal function in the Decider pattern is highlighted, providing the framework for the lifecycle of an aggregate.
The demonstration of a simple domain model using the Decider pattern, such as a light bulb with a specific number of uses, is provided to illustrate the practical application of the concept.
The concept of 'even sourcing' is introduced, explaining how it can be used in conjunction with the Decider pattern to manage state changes and events.
The use of a key-value store and event store for persisting the state of deciders is discussed, providing a solution for maintaining the system's history and current state.
The ability to combine multiple deciders into a single, more manageable unit is explored, showcasing the flexibility and scalability of the Decider pattern.
The concept of a 'process' is introduced, explaining how it can listen to events, emit commands, and maintain an internal state, further expanding the capabilities of the system.
The practical application of combining deciders, processes, and event sourcing to create a cohesive and interactive system is demonstrated.
Transcripts
foreign
working at the age Hospitality for 15
years now so it's quite a lot of time
and you can also it's a company that is
managing bookings and planning for hotel
all around the world
I am an architect there and I'm applying
some of the thing I will show you but
this is quite recent work and it has not
been fully documented yet so you will
see here I will do everything
mostly live so it's cool and I think
after all you've heard this morning you
want to see some code to learn actually
the thing and this is what we will see
and today we will talk about aggregate
composition
and they use the word aggregate here but
we will talk about deciders who know
what we decider is
okay not many people so the problem with
the aggregate with the aggregate
definition is that it's quite fuzzy so
that one of the power of aggregate uh
but that's also one of its weakness uh
an aggregate is something that keeps
some consistency inside the boundary so
it's yeah there are something inside
there is a red outside and what it says
is that what is inside need to be
consistent okay so you need to move from
one valid state to another valid state
or not at all okay but it says nothing
about how you do that and how you manage
that but something interesting with this
definition is that you have a bundary
what is inside has to be consistent and
what he says is that what is outside
just doesn't have to doesn't mean that
it should be not consistent okay just
doesn't have to and this is something
that uh leads in a lot with that
regulate a lot of complexity when you
start to design small aggregate is that
you have a lot of small pieces Maybe
independently and you usually you need
some things like small actors or small
services for each aggregate calling the
the ones one other
in a complicated way and then at some
point you have too much moving Parts too
many parts in parallel in concurrency
there is no problem for that but it's a
lot of infrastructure to run all these
small things
and something we that could be easier
sometimes it's just to take several that
work together and group them together as
a more manageable all so what you can do
is that you can write add a code that
group them but then if at some point in
time it's better to split them again you
risk to have some friction because some
decisions have been taken in this
composition in this grouping and then
when you start to remove it you don't
know how to do and here uh I will show
you first what the decider pattern is
this is a pattern
that enables you to write Aggregates in
the
well-defined way so this is a specific
shape for aggregates
that has very interesting properties so
we are
in an even sourcing track so we'll talk
about even sourcing but not
exclusively because you can also use the
decider pattern to run classic loads
load State safe State way and the super
cool thing with that is that you never
need to touch the domain code whatever
the persistence you want to to use okay
so let's start with this idea pattern
the other side of pattern is quite uh
simple it's here we will I will write it
again
so that you see how it it works okay
so
it's a decider because this is this is
something that decide things okay so we
will create a who is fluent in F sharp
hey hey some some people yeah this is F
sharp you will you will see it reads
mostly like python but with more types
things and I will explain on the Fly uh
what's happening so we'll uh create
decider type
and this decider type is generic meaning
that it can act on different things with
specific types that we will find
multiple times in the definition the
first thing decider will do is that it
will receive commands comments that will
ask to make a change on the decider this
is the commands we talk about with
Aggregates it can also be seen as the
method on your Aggregates that will
change the thing in the aggregate but we
will
put this command in a type and we'll
just use this cut C
name inside the definition okay so these
are the comments okay but what an
aggregate this idea is doing also it's
it's taking decisions and the output of
this decision will be events saying this
happened okay so we will have an event
type
and to manage all this inside
it will need a state to know what is the
current state and take the decision so
an s okay so short end for command event
and state and the first thing in the
decider will be the decide function the
decide function is here to say when you
ask me to do this command and I'm in
this state here is what happened so
definition is quite straightforward this
is a decide function
and this function we'll take a command
of type c it will also take a state of
Type S and it will it will return events
so e
and this is a list
okay because it can return 0 one or many
events
so this is where the domain logic will
take place okay this is where we will
say okay I'm in this state you asked me
to do this this is the result this is
what happens
of course you can anticipate this is
this event can finish in an even store
of course okay
second step
once when we are in the state and
something happens the state change and
in the decider pattern we clearly split
the decision
from the state change and we will have
for this state change an evolve function
evolve and it says when I'm in this
state of Type S and this event happened
of Type e
here is the new state
of type S
Okay so
here
I'm writing in F sharp I'm using
immutable data structure so the state is
not like some things that change you
have a data structure that contains some
values and the evil function will create
a new version of this data structure
with a new value and return it okay so
this is pure functions will be really
easy to reason with and all that you
will see how we write it uh just after
uh to be able the evil function texture
state but the question is where do we
start
so we need an initial state
so initial State like that and this is
just a value of Type S that is the
State before anything happens okay
and the last thing is that at some point
we will need to to to finish to know
that this this idea has finished its job
and that we can archive it or something
so we have these terminal function that
takes to State and return a Boolean
value uh to say okay it's done
right
this is a decider
and actually you can take any aggregates
on writing with this form
you if you have access to external
service you move them
up the stack and you put the values
inside the commands as values and your
desired function will take everything as
the state
all the reaction instead of Performing
side effect you will have some events
from the decide function you can use
them to perform the side effect from the
outside remove all the rest you keep the
logic inside okay
this is a shape of a decider and on for
the last part I will need something that
I will explain later but I will need to
to make a dissociation between the state
that is on the output on the input on
the state on the output so everywhere
the state is on the left
I will call it s i on everywhere it's on
the right I will call it
so and we can just create another type
for short end which is
the same but with the same state on the
input and the output uh yes like that
it's a decider of c e S and S this is a
short n when the state on the input on
the output is the same okay
so know that we have a decider let's
write some domain code so we will take a
very simple domain we have a light bulb
okay and we have a cat
right so the light bulb you can
fit it in the in the blog in the socket
and it will have a specific number of
usage for blowing up right on the cat it
just has two states it can be a weight
awake or sleeping and you can wake it up
or get it to sleep okay so
our first example is here so document
here is the type command
and so this kind of type is called the
Union
uh so the command can be as three kgs
which is either fit with the feed value
which contains the max uses integer or
it can be a switch on or switch off okay
so
the way to implement it in other
languages usually you can create a base
class and having three classes the
deriving from from this base class and
then you can match on the type and do
the thing okay or you can use Dynamic
dispatch or anything but in our case
it's this is a single type with three
cases okay
the event
are quite the same as the users but in
the past tense right so we have a fit
and we have a fitted event
we have a switch on Switched on switch
off switched off but we have an other
event which is blue
uh when the the
verb just blue
the status can be on on on on or off and
the state is also a union
it can be not fitted working with the
statues
and the remaining uses and it can be
blown right okay so
usually you don't start like that you go
using a tdd to to Define what your state
is but the comment on the event
come from the specification the state is
more like implementation details so the
decide function here
as we said must take a command on the
state so what you ask the bulb to do on
in what state it is so we just match the
two values
and return some event for each right so
if it's not fitted then we send it a
feed command it will return fitted with
the max uses indicated if it's we ask we
to fit but the state is not not fitted
it will fail
when you ask it to switch in on uh while
it's working
and the status is off it will be
switched on okay but this is only the
case when the remaining uses are larger
than zero right because when it's zero
we go to the other line and it's earned
we ask it although the current state is
off it's just blue and the last one is
you switch it off while it's on and it
will say it switch off in all other
cases it does nothing right
so this is this the decision
for this thing right
so this is a very simple decider uh in
the case of a board game that I wrote I
have a decider which is 2 000 lines long
of F sharp which is quite test language
so yeah and it has been converted to
uh 11
000 lines of PHP so yeah you can imagine
the the thing
um so uh after the decide function we
need we need an evolve function
and this function is just changing the
state based on what happens so it takes
the state on an event and will return
the state
if it's not fitted only just fitted no
it's working with the status off and the
remaining uses are Max uses
if it's working on it that's been
switched on we change the statues and
remove one from the remaining uses if
it's working
and switch off it's off and if it's blue
it's a transition to the blown state in
other cases it's remaining the in the
same state
right the initial state is not fitted
and the e-terminal state is statically
equal to blown right and now I can just
create the structure by taking the
function and put it in put it put them
in the data structure
right so the cool thing is that this
decider is very easy to test so I wrote
here
function
given when which deck you decider
right
on what it does it takes its return a
function that takes some event on the
command
okay
it takes these events
and pass it to the list.fold list.fold
is taking your list
initial value which is the decider
initial State okay and it takes the
first element in the list and called the
function that is passed here is this
idea that evolve detect the result takes
the next the next item in the list and
do the same so
after the second line
we get the initial state
then the state after the first event
after the second event and the last
event so we get the current state right
and so this is a pipe forward thing here
this current state is passed to the
decider the decide function with the
command
and the result is a list of events right
so I just create a small operator which
is a equal bank which says assert okay
let's check that X actually is equal to
expected on print something
and no I can also create this small
Arrow operator
simple row
that is given when with the bulk decider
so my tests are here when nothing
happened before and I fit the bulb with
Max user to five the result is one event
which is fitted with maxus 5. when the
bulb has been fitted and you switch in a
switch it on it's switched on
etc etc so the tests are here and very
easy to to read so the last one is
checking that if you oops
if you start it with maxus one and
switch it on off and then you try to
switch it on again the resulting event
is blue okay cool thing here with this
with this this test is that the state
never appears in the state so I can
refactor the state as much as I want I
never have to change the test this is
pure Behavior driven test
and you have seen all the framework I'm
using like the
SE lines okay this is my test framework
to write this okay
uh
so this build thing I can there will be
the cat after this thing the first thing
I can do with this you will say okay you
can test it but can I run it right so we
can run it like this
uh we'll create a smaller module in
memory
and create an instance of it with in
memory
in memory with my bulb decider
and now I can send it some commands like
for instance fit
.fit
and with the value
dot Max uses is five okay
and after that we can call it with
another command which is a switch on
and same but we switch off
like that so I take my decider
I didn't run the code before so it's not
working of course
here
perfect
and so just to show you that it's
working I can run all the tests
and
we should get green
freeware okay
so I take my decider here okay I create
an instant of it uh an instance to run
it and you see that what I get is a
function that takes a command and
returns and evenly so I will pass some
to some commands to this function here
and it says okay the result is it was
fitted with a Max use of five if I try
it again I get an exception because you
cannot fit it twice right but now I can
switch it on okay switch on I can try to
switch it on again nothing happens this
is what we expect I switch it switch it
off it switched off on off on Earth
on earth once again and Bloom okay I
know I can try anything nothing happens
anymore okay so
when you have a decider you can just run
it like that I don't need an even store
or anything I can just turn it I will
show the cut just after the cool thing
with that
I can take the code I'll show you and I
can for instance we have a new service
that we that we want to to to to
implement and first thing I do is I
write my my domain code as a decider and
I use this
in memory function to run it I just put
it behind your service and I put it into
staging and people can start to play
with it there is no persistence no event
store no database but you can already
test the domain logic from here okay and
what is the magic for this in memory
function
it's very simple what it does it says
give me your decider
okay and I create a mutable variable
called state which is equal to the
decider initial state
right and then I return a function that
takes as a command
and it will call the decide function
with the command on the state I get some
events
with this event I use the level function
on the current state to fold them and
get a new current state that I store in
the state again and just return the list
of events that I computed
right
this idea running in Murray the cool
thing with that is that you can take any
domain logic written as a decider pass
it to this function and it will run like
that
I don't need to rewrite the same blah
blah blah running instantiate the thing
because all deciders have the same shape
I can write this code once and use it
for any domain logic
okay so next step
no at some point I will so to test that
it also work with something different I
can test it with the cat so
so I will not show the code for the cat
because it says even simpler decider
which can be awakened and it's just
doing the thing okay so I take Creator
in memory with the cat decider
and I can
cat dot wake up
no we see here
or I can get to sleep right so and
instantiate it when I tried it was
already woke up awake so if I try to
wake him up and nothing happens but I
get it to sleep wake up go to sleep I
try to go to sleep again nothing happens
and all that okay
it's working and I'm just running the
decider in memory no the thing we want
to do
is that we want to persist
uh
the state this way if we stop everything
and we will start we will be in the same
in the same position
um the thing usually is that if you
start with thing in memory and then you
want to implement it with the database
you get a bit in trouble because you
will have to change your code
here we will
just do something like that
module state
and we will create so it states that run
and for this I need to give a decider a
bird decider and what I will do is that
I also will give a serializer
state serializer and the two last things
I need to give is the container name
this is a bulb and this is instance one
okay
like that
I know I can just
do the same thing as before sending
command to this function
and Magic here this is the ESC KV this
is my toy implementation of key value
store and even store
only for educational purpose okay this
is stated in the lessons you can use it
if you want for your own demonstration
right
but only if you don't make money with it
or you contact me and you see and never
use it in production because it's not
done for that it's really something to
show how it works
there is a client library to use eskv uh
which has all the Primitives you find in
any client for the events to her and for
key value stores right but I try to
reduce it to reduce at the maximum the
complexity of demos okay so you do the
same for your own infrastructure uh you
you try to create the same kind of
client API that I created for eskv and
you will be able to do everything but in
your production right but don't use a
eskv for production
uh the cool thing is that you it's very
easy to install and all that you will
look at my um and my GitHub and you will
find it so now I have an instance and I
fit the bulb and as you can see just
appeared here in the key Value Store in
the container bulb key one the value is
of 5.
cool you know if I try to build do fit
it again it fails I can switch it on off
and off
on if I try on again nothing happens off
on off on off on on the next call the
state is blowing right so you see
uh
and as you can see I just took the same
decider and run it and I saved the state
so it will tell me yeah but we are here
for even sourcing it's not even sourcing
we are saving the state but the cool
thing is that we will switch to even
sourcing without changing the domain
code either right so follow with me
what's happening inside the state run
function
so it needs a decider on the serializer
a serializer is just a pair of
cellulitis and deserialized function
right
uh the serialized on this ILS function
take your state and return the string or
take a string and return the state and
the container is key is just to to know
where to store it in eskv so starting
the skv is is really easy
you create a client
right
and then what we have is these two
functions this first one is a try load
it takes a decile this iulized function
the default value and the container in
the key and it will call try load
with the container on the key to get the
string
that is contained for this key okay I
get a result if the key exists I take
the value and this I realize it if it
doesn't exist I take the default value
now I have a value and I will result the
value and the e-tag
for this key so the e-tag is useful
because the attack will change on each
version of the document right and when I
will
save the document again I will check
that the document has not changed
between the moment I loaded it and the
moment I save it right so the save is
equally easy
Texas cellular laser the container the
key the state and the tag and it called
try save
uh with the key and it's a realize the
state to a string it pathway tag if the
state has changed I will get null and I
can fail if the e-tag is not null I get
a new tag but I will not use it so I
just drop it so
um
know that I have these two very easy
function I can use just use them
so I
use the tryload function to get the
current state and the attack from the
database
now I can call the D type function with
the command that has been provided to
the function on the state I just loaded
I get some events I use list fold with
the evil function to get the new state
right and I just save it
okay I return the events and this is
working and this is working for any
designer right and this version as
controlled optimistic concurrency
checking because of the attack so if
some other instance
uh is messing with the state I will
detect it between the load and the Save
which should be super short anyway
the other thing is that it's very easy
to change this to keep state in memory I
can create also a mutable variable load
the state up front and then for each
command
I keep the e-tag for each command I will
compute a new state try to save it if
the tag has changed I will just reload
the state from the database and each
time I will update so I reload only if I
have a conflict with the current state
of the database so
and once again I don't need to know
anything about what's inside this
designer just to know that it's a
decider it can run for all your domain
logic exactly the same way so I just
need several versions of this run to
implement the different loading saving
keeping in memory patterns but the
decided I don't care
uh
it's also working for cats of course
let's see stat dot run
cat dot decider I will just take the uh
the cat
state serializer
and I will
call it cat one and I have my two
functions my two commands here
yeah
I wake it up it's awake I get it to
sleep it's asleep if it's already asleep
nothing happened and extra extra okay
so super cool I have a cat on the light
bulbs that are working now the question
is but how do you use these deciders for
even sourcing
oh it's actually very easy module even
sourcing
so let B and I will say even sourcing
dot run
with my bulb decider
bulb event serializer
[Music]
I don't have container on the streams
yet but it will come Monday
up
up like that so I get it
oh in my streams here I see this build
one stream the first event is fitted if
I try to run it again bam no I cannot I
can switch it on off on off so you can
see also the event uh
I can switch on if I do it again nothing
happened on off on
under that time it's just blue and
nothing happened anymore right so once
again no I'm using even sourcing
uh but totally without uh totally
without a
changing the code so for the
infrastructure for this is just
I load the events with my data laser
from the stream so there is an easy API
in eskave that just returns all the
events from a stream
I get the event on an expected version
this is the current version of the
Stream
I fold all my events using the evil
function I get the current state I pass
the student state to the decide function
with the command I get the new events
you follow it's okay so I get the new
events and then I open this event to the
Stream
passing the expected version if someone
added new events to the stream in
between it will be detected and I can do
something more specific right
so this is even sourcing now
cool it's also working for the cat of
course as you can guess
but no the thing is that
uh
I have this small decider and I
maybe I want to just run one thing and
not two things like not two apis or
something an API that will have things
for the cat thing for the
for the bulb and I want to put them
together because uh in some ways this is
so small they go together
uh what what the first to to create all
this infrastructure to run both okay
so I have two decider
is it possible to create a single
decider
and actually yes
and this is where it gets interesting
the thing here
so I will go a bit
here and we will create a compost
function
so this will be a bit harder to follow
this is the code but I will not show you
we will write it
Okay so
the only thing I will copy is the first
line because it's a bit long to type
the first two lines
up
like that
so uh I need I want to write a compose
function that will take an X decider
okay that text comment of type CX
that will return events of types e x and
have a state of type SX okay and I have
a second d y decider with the Cy ey Sy
and what I want
is a decideration can do both so it can
take
commands either
from the first one the one on the left
or for the second one the one on the
right right and
the decision taken from there for for
from this decider can either be uh an
event for the one on the left or an
event from the white run one on the
right okay
and what is the state the state is just
a pair of both States
okay
this is George repair the state of the
bulb on the state of the cat
okay so this is what the signature of
this function is saying the either type
is not a standard type in F sharp but I
just wrote it here so it's either
uh with two two type parameters and when
the left side is of Type L on the right
side is of type error
so
returning here the first thing we need
in our decider is a decide function
okay and as you decide function it will
take a command
I will say CMD for short and it will
take a state and we know that the
decider we want to provide
its state is a pair of State okay so we
will directly call the left part SX
and the right part is why okay so it
will get one pair and I call the left
part of the pair SX on the right by part
of the state Sy
the command can be either a common for x
or a command for a y so I will test it
with a match
on the command
and if it's for the left
we will call it CX recommend for X okay
and no we know that we have a command
for the left part so we will take the
left decider and call the D side
function from the last decider so the
left decider is the X
and I will call this side this digital
except CX as a parameter on SX as a
parameter okay and this will return
events
for the it will return events of the
left decider so to be able to
make it compatible with the others I
will say they are on the left so I will
just use
I will just say there are on the left on
all the events okay
like that four
if it's the right it will be equally
easy
so if it's the right I will call it Cy I
will take the right decider the Y pass
it
the command with the state for the right
and just say
okay it's an event on the right
and this is my decide function now what
I can do is eval function
so the function as you remember is
taking a state that our state is still
in two parts SX and s y and we have an
event here
so the thing is that we need to return a
new state that will be computed with the
2D slider we have so we will again match
but this time we haven't uh to see if
it's an event for the left or the right
if it's for the left we call it e x
and what we can call is the
evil function from the DX decider
with the state for x
though even for x and what we get is
just the new state for the left part so
I will just put the same value for the
right part like that
okay
but if it's for the right
it will be an event for y I will use the
Y evolve function
uh with the state for right for y and
the event and
I will keep the same value on the left
okay
uh yes uh where yes why like that uh
uh
the next thing is the initial state
initial state
the initial state is easy because it
will be the initial state from the DX
decider on the left
and the initial state of the d y decider
on the right
and
lastly the is terminal function
this is a function that will take a
state so we will call SX the left
pattern as why the right part and we'll
just say test that SX is this terminal
state
on the
X on the left decider and that Sy is the
terminal State on the right decider
like that and as you see yeah it it
works right so this is awesome I know we
can create a bulb
and cat a cat and bulb uh decider let's
try it
you'll
chat
and bulb
so let CNB it will be shorter c and b
and to create so to create the decider
uh I will
just created it here let's get and verb
equal and I will use a decider dot
compose function to take the cat decider
and the bulb decider
I know I get a cation belt decider
so the thing is that you can apply this
compose function to any decider you will
write with your on-demand logic of
course not just with the cotton bulb it
will work okay and we can run it in
memory
CNB
in memory
and I will need the cat and bulb decider
here right and then I can give it some
some function so I already wrote this to
gain some time so here I can so to to
pass
a comment to the cat I have to say that
it's on the left okay because this
slider is only accepting cat command on
the left and bulb command on the right
so I wake up look at nothing happens
because it's already awake you go to
sleep awake left go to sleep and then I
can fit the bulb switch on switch off
on off right and the cool thing is that
I can also run it not in memory but uh
as in
with the state so I will just go here
uh
this one
yes no this is not the one I wanted in
memory card on
I have a lot of things
so the thing is that here I also compose
a serializer together to be able to take
two serializer and make a single one
and then I can do this and as you can
see on the left of the pipe on the right
you have the state of the skirt and on
the right state of the of the bulb
so I can switch on off and go to sleep
awake
switch on switch off
on off
on off and it just blown right
so uh I can take two aggregate two
deciders on the other single decider but
what I can do now is that I can take
another decided and combine it with this
one right
and the fun thing is that we can also
create a neutral decider
like this which is a decider that you
cannot use and that does nothing why
because the command is void which is a
type which has no value so you cannot
create a value of it so you cannot
create a command of type void and it has
no event because it's of type void until
that it has a single state which is the
value of unit which has a single value
which is a parenthesis parenthesis right
and the decide function just says
whatever you ask me I return nothing
when you ask me to evolve I keep the
same state my initial state is the only
value I have which is boundary is bound
to this and it's always terminal right
no I if I take a decider and I composite
with this I get another decider but
which can do exactly the same thing as
the this later I composed with it right
so actually this is a neutral element
for the operation which says that the
operation is monoidal
because we have different shape but that
those exactly just do the same thing
something that is interesting also is
that we we when you have a cat uh you
can run a cat but if you want to run
many cats it can be cumbersome to
combine them all together as a single
decider so there is a mini operator
which take a decider and will return a
decider for many instances of the same
thing right so the thing is that in this
decider
uh each of the instance will have a
string identifier okay you can choose a
different type of a string but it was
easier for the demo uh and each time the
command will be
the name of the thing and the command
the event will be the name of the thing
on the event and the state will be a map
a dictionary of string and the state of
this thing right and so the decide
function it will receive a command which
is actually an identifier and the
command for the inside decider on all
the states so we try to find the state
in the map and if we cannot find it we
return the initial state
we have a state we call the decide
function we get some event and we just
add the ID on each event and no we can
decide for many things
okay the evil function is quite similar
we have an idea with the event so we try
to find the state or we use the initial
State and we use the evil function to
compute the new state and we replace the
replace the state for this identifier in
the in the dictionary
the initial status is an empty map
and there isn't this terminal function
check that all the values in the map are
terminal for the decider and with this I
can run many cats so I will run many
cats
uh kids a bit further so many cats uh I
will run it with uh with the state
so the first cat is called bullet
because this is the the name of of my
cat Okay uh
uh and when I put it to sleep you can
see that the state is a bullet is asleep
and I can wake it up and awake either
cat I know and I can wake it and with a
single decider I can run many cats
next interesting things also is that I
have a process
so a process is a state machine and the
process will I have four minutes left
process will evolve so a process listen
to mostly events will emit commands and
have a inner states so we have an evil
function that is similar to the other
one
the react function says when I'm in in
this new state and this event just
offshore is this here is the list of
commands that we must send
resume is when you just resume the
process after a crash it just Returns
the thing it has an initial date also
it's terminal also
I have every process that when a light
is switched on
it will wake up the cat and we will know
that the cat is like awake because we
will see the woke up
event so my state is either idle the
process is just waiting for the light to
switch on or waking up it's sending the
command but it does not the confirmation
yet that it has been done so it will
stay in this stage and when we
receive the workout event we will go in
idle State again so it looks a bit like
the decider but with different function
so we switched on a waking up
when it's woke up it will go to idle
state
when it's waking up in because we
switched on it will return backup and
the initial state is idle
and the cool thing with that is that we
can combine
this process with the decider so I'll do
with that we do that the thing is that
we take a process
on the decider and this decider will be
already the combination of the cat on
the bulb okay and I will take this this
uh this side there on my
process that will wake up the cat when
the light switch on okay so it doesn't
get the cat to sleep when it switch off
of course because the cat never go to
sleep when you want
um so uh it has a decide function so the
thing is I get a function and I get the
state for the decider on the process
and what I will do is that I will take
this command
right and pass it to this Loop so this
Loop will
accumulate events over several commands
because the thing is that we have an
input command but the process May
trigger other comments that will produce
a new state so the first thing is that
if I still have common to process I call
it command this is a year document
highlighting and I compute the event for
this command in my decider
and this event I will use my process to
collect new commands for each event so
this is the collect folder function
what it does it says okay so I'm in a
state I have some events and I have
nothing to return
uh uh and when I have an event I will
evolve the process first okay with my
current state on the the list of events
I get a new state
I call react on the process that can
return me one or multiple comments and I
put them in my result
and then I take the next event on my new
state and do it again until I have no
event to process and in the end I have
the the list of all the comments I need
to to to to to process after
and what I do is that once I have all
this new command I will just put it in
the list
and do it again it will go through the
deciders that will produce new events
that may produce new events that go to
the process that could produce new
commands but eventually there will be no
more common to send because everything
in the right State and at that time I
have collected all the events generated
by the decider okay so now I can use
this combine
with decider and go quickly to show you
how it works
so here I will combine the
uh
uh yes I know yeah adapted process is
here so this is just a small helper to
to convert the event from the decider to
the
process of the rest
yes I need to run both at the same time
yes almost
this is my
new version of this of course it will
not work
demo effect
ah
[Music]
why okay
[Laughter]
yes I will just run everything because
yeah I made some change on the way
uh
[Music]
with process yes
and here
like that no okay
no it's not working okay so I explained
what is happening so when I do this
uh I take my combined decider with a cat
on the bulb I take my process and I get
a new decider right
so this decider I can run it with any of
the other function I wrote before but no
when I get the cat to sleep and then I
switch the light on I get both the light
is switched on and look at woke up right
so
I had two deciders
that I could I can still run
independently using two different run
functions I have a process that can also
run independently using a process run
function I can Bridge everything with an
event store and all that but again also
using just this few line of code put
them together on every single thing okay
but I don't need to change the code
either for the cat for the bulb or for
the process to move from one setting to
another I can just
glue them with standard operators
and get all the things running as a
single unit okay so the interesting idea
is that you instead of thinking what
should be the side of my uh aggregate
you can think I will Design the small
thing I will Design the processor glue
that from them together and then I will
think how I run this right use the
operator I've shown
compose uh on the combined with the
decider and all that and you get two
single thing that is still a decider and
that you can run in memory with the
state database or with an even store the
same way
you're free to choose and you can always
choose letter and you can move from one
version to the other like starting in
memory State and then even sourcing and
that's just the same code so
I think my time is over so thank you
very much I hope that you like it
[Music]
5.0 / 5 (0 votes)