<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="../../assets/xml/rss.xsl" media="all"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>blog.johanv.org (Posts about eventsourcing)</title><link>https://blog.johanv.org/</link><description></description><atom:link href="https://blog.johanv.org/en/categories/eventsourcing.xml" rel="self" type="application/rss+xml"></atom:link><language>en</language><copyright>Contents © 2025 &lt;a href="https://blog.johanv.org/pages/contact/"&gt;Johan Vervloet&lt;/a&gt; 
&lt;a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/"&gt;
&lt;img alt="Creative Commons License BY-NC-SA"
style="border-width:0; margin-bottom:12px;"
src="https://i.creativecommons.org/l/by-sa/4.0/88x31.png"&gt;&lt;/a&gt;</copyright><lastBuildDate>Wed, 29 Oct 2025 18:31:16 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>Upgrading Wdebelek to krakboem 1.0</title><link>https://blog.johanv.org/en/posts/upgrading-wdebelek-to-krakboem-1/</link><dc:creator>Johan Vervloet</dc:creator><description>&lt;div&gt;&lt;p&gt;As I mentioned in a previous blog post, I recently released
&lt;a href="https://blog.johanv.org/posts/my-first-symfony-bundle"&gt;version 1.0 of rva-vzw/krakboem&lt;/a&gt;, the custom
php library I created to use event sourcing and CQRS in my applications.
It comes together with a Symfony bundle,
&lt;a href="https://gitlab.com/rva-vzw/krakboem-bundle/"&gt;rva-vzw/krakboem-bundle&lt;/a&gt;, which
is now at version 0.1.2.&lt;/p&gt;
&lt;p&gt;The first project to use version 1.0, was
&lt;a href="https://blog.johanv.org/en/posts/wiezen-score-app"&gt;dikdikdik&lt;/a&gt;, the score app for the 
&lt;a href="https://en.wikipedia.org/wiki/Solo_whist"&gt;wiezen&lt;/a&gt; card game. This is
one of my &lt;em&gt;pet projects&lt;/em&gt;, in fact the one that I regulary work on.
So in order to test if the krakboem-bundle and the updated krakboem
actually worked, I tried to use them for dikdikdik. As everything seemed
to work fine, I tagged it krakboem 1.0.&lt;/p&gt;
&lt;p&gt;After that, I wanted to use krakboem 1.0 in &lt;a href="https://blog.johanv.org/en/posts/wiezen-app"&gt;wdebelek&lt;/a&gt;,
the app I wrote in covid-times, to play cards online.&lt;/p&gt;
&lt;p&gt;&lt;img alt="screenshot of the wdebelek card playing app" src="https://blog.johanv.org/galleries/cards/wdebelek.png"&gt;&lt;/p&gt;
&lt;p&gt;Wdebelek also uses krakboem, but it is different in that it uses
event based entity repositories instead of
&lt;a href="https://blog.johanv.org/posts/whist-with-a-decider"&gt;deciders&lt;/a&gt;. So I had to figure out if this
would work out fine as well. And while doing he upgrade, I had a nice
chance to improve
&lt;a href="https://gitlab.com/rva-vzw/krakboem/-/blob/develop/UPGRADE-1.0.md"&gt;the upgrade instructions for krakboem 1.0&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I can't say the update was an easy one. Krakboem 1 requires php 8.3 and Symfony 
serializer 6. And for krakboem-bundle, I need Symfony 6.4.
All this means that I had to update some other dependencies as well. For php 8.3, it
mainly came down to updating
a package here and there. But since until last week, Wdebelek was built on Symfony 5.3, I had
quite some work with the Symfony upgrades. (&lt;strong&gt;update 2024-02-14:&lt;/strong&gt; Especially the new
recipes for codeception 5 were not straightforward.)&lt;/p&gt;
&lt;p&gt;The update of kraboem, from v 0.11 to 1.0, was also not trivial. Lots of classes
moved around. And quite some abstract base classes became read-only, a concept I wasn't
aware of back in 2020. (&lt;strong&gt;update 2024-02-15:&lt;/strong&gt; Identifiers are now expected to be
non-empty as well. This was also quiet an update.)&lt;/p&gt;
&lt;p&gt;But since last week, the 4th of february to be exact, wdebelek is running with
the latest versions of my libraries. It still needed a blog post, but hey,
here it is, so I am a happy programmer again. (Writing the blog post took me
a week, because of, you know, life.)&lt;/p&gt;
&lt;p&gt;If you want to try playing cards with Wdebelek,
you have to find at least 2 other people to play, and go to
&lt;a href="https://kaart.rijkvanafdronk.be"&gt;kaart.rijkvanafdronk.be&lt;/a&gt;. Remember that you
need to drag the cards to play them. (This is not really clear from
the UI, and it often causes some confusion).&lt;/p&gt;
&lt;p&gt;I still have one project to update: &lt;a href="https://gitlab.com/johanv/1jg"&gt;1jg&lt;/a&gt;,
another score app for another game. This will probably a little easier than
the Wdebelek update, because 1jg is already on Symfony 6.3. And of course
I now have nice upgrade instructions for krakboem and its bundle
now 😉.&lt;/p&gt;&lt;/div&gt;</description><guid>https://blog.johanv.org/en/posts/upgrading-wdebelek-to-krakboem-1/</guid><pubDate>Sat, 10 Feb 2024 14:42:00 GMT</pubDate></item><item><title>Krak? Boem! My first Symfony Bundle</title><link>https://blog.johanv.org/en/posts/my-first-symfony-bundle/</link><dc:creator>Johan Vervloet</dc:creator><description>&lt;div&gt;&lt;p&gt;Earilier this week, I published my first Symfony bundle. Should you use it? I don't think so.
But I'm proud that I unlocked this achievement 🏆🔓&lt;/p&gt;
&lt;p&gt;A little background.&lt;/p&gt;
&lt;p&gt;&lt;img alt="picture of an elephant and playing cards" src="https://blog.johanv.org/galleries/cards/krakboem1.png"&gt;&lt;/p&gt;
&lt;p&gt;Back in 2019, I started writing an 
&lt;a href="https://blog.johanv.org/en/posts/wiezen-score-app"&gt;application that keeps track of the points when playing whist&lt;/a&gt;. I called it
&lt;a href="https://gitlab.com/rva-vzw/dikdikdik"&gt;dikdikdik&lt;/a&gt;, a typical bad name for an open
source project. It refers to some catch phrase in Dutch, and it can be used
at &lt;a href="https://score.rijkvanafdronk.be"&gt;score.rijkvanafdronk.be&lt;/a&gt;. It has
become rather popular over time, which I find very cool.&lt;/p&gt;
&lt;p&gt;So ok, I created this app because I wanted something to help us with the
scores of our card game. But maybe
at least as important: I wanted to create an app to fiddle around, and to learn
new things. I wanted to use Symfony and event sourcing, two technologies
that were still rather new to me. After some time, I had a fun project,
and I talked about it in a &lt;a href="https://jv3.johanv.org/phpbnl20"&gt;lightning talk&lt;/a&gt; at
the last PhpBenelux conference (ever? 😢) in 2020.&lt;/p&gt;
&lt;p&gt;Not long after that, in 2020, Covid broke out, and we couldn't play cards anymore because
of the restrictions. So we needed an &lt;a href="https://blog.johanv.org/en/posts/wiezen-app"&gt;app to play cards online&lt;/a&gt;.
Because I wanted that one to be event sourced as well, and because I didn't want to
write everything again, I extracted all relevant
classes and interfaces to a php package. &lt;a href="https://gitlab.com/rva-vzw/krakboem"&gt;rva-vzw/krakboem&lt;/a&gt;
was born.&lt;/p&gt;
&lt;p&gt;This package worked quite well for a couple of years. But things have changed.
Back then, I used php 7.4. Now there's php 8.3, with &lt;code&gt;final&lt;/code&gt; and &lt;code&gt;readonly&lt;/code&gt;. I know more
about the relationship between &lt;code&gt;Traversable&lt;/code&gt; and &lt;code&gt;Generator&lt;/code&gt;. I also have better
understanding about what infrastructure code exactly is. And recently I 
&lt;a href="https://blog.johanv.org/en/posts/whist-with-a-decider"&gt;learned how to use deciders&lt;/a&gt;, and
krakboem didn't know deciders.&lt;/p&gt;
&lt;p&gt;So krakboem could use an update, and that's what I did. I rearranged the classes,
added &lt;code&gt;final&lt;/code&gt; and &lt;code&gt;readonly&lt;/code&gt;, introduced deciders. And while doing this, I also
extracted all symfony messenger and doctrine code, and moved that to a bundle.
So now I have a &lt;a href="https://packagist.org/packages/rva-vzw/krakboem-bundle"&gt;krakboem-bundle&lt;/a&gt;.
And I also tagged &lt;a href="https://packagist.org/packages/rva-vzw/krakboem"&gt;version 1.0&lt;/a&gt;
of the base krakboem package 🎉&lt;/p&gt;
&lt;p&gt;Not that I'm 100% happy with how krakboem is structured, but I didn't want to move
every class around. And I'm fairly sure that it will be useful again for a couple
of years without needing lots of changes.&lt;/p&gt;
&lt;p&gt;The bundle is still experimental (version 0.1.2 at the moment); I don't really know 
yet how to properly create a bundle. But I am happy, because it already takes care of the
dependency injection for the doctrine and messenger infrastructure.&lt;/p&gt;
&lt;p&gt;So next thing on my to-do will be: upgrade my other krakboem-based projects, so that they all use my
new bundle. I don't expect this to be a whole lot of work, but I don't have a whole
lot of time either. So we'll see how it works out.&lt;/p&gt;&lt;/div&gt;</description><guid>https://blog.johanv.org/en/posts/my-first-symfony-bundle/</guid><pubDate>Sat, 13 Jan 2024 20:52:00 GMT</pubDate></item><item><title>Whist with a decider</title><link>https://blog.johanv.org/en/posts/whist-with-a-decider/</link><dc:creator>Johan Vervloet</dc:creator><description>&lt;div&gt;&lt;p&gt;Back in June, I attended &lt;a href="https://2023.dddeurope.com/"&gt;DDD Europe 2023&lt;/a&gt;.
It was the first time I was at this conference, but I liked it a lot, and I was 
intrigued by 
&lt;a href="https://2023.dddeurope.com/program/aggregates-composition-a-new-view-on-aggregates/"&gt;Jérémie Chassaing's talk&lt;/a&gt;,
in which he used a &lt;em&gt;decider&lt;/em&gt; to keep track of the internal state
of aggregates.&lt;/p&gt;
&lt;p&gt;I don't know a lot (yet?) about functional programming, but I was charmed
by this elegant way to work with commands and events. So I 
wanted to experiment with deciders as well.
As it turns out, I have an ideal project for doing this kind of
experiments:
&lt;a href="https://gitlab.com/rva-vzw/dikdikdik"&gt;dikdikdik&lt;/a&gt;, my web based
score sheet for the &lt;a href="https://blog.johanv.org/categories/wiezen"&gt;wiezen&lt;/a&gt; (whist) card
game. It already had commands and events, so using a decider should not
be too hard.&lt;/p&gt;
&lt;p&gt;&lt;img alt="someone deciding what to bid with their cards" src="https://blog.johanv.org/galleries/cards/decider.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Dikdikdik has two aggregates: a table (as in a piece of furniture, the 
table is where the players sit down, and play their games)
and a score sheet. Initially those aggregates had methods that emitted
events, and other methods that applied those events to their internal
states. The latter ones were also used to rebuild the aggregates based
on their event streams, since dikdikdik is also an event sourced application.&lt;/p&gt;
&lt;p&gt;In a first step, I replaced the table entity by a TableDecider and a
TableInternalState class. The idea is that when you pass
the internal state of a table and a command to the
decide-method of the 
&lt;a href="https://gitlab.com/rva-vzw/dikdikdik/-/blob/develop/src/Domain/WriteModel/Table/Aggregate/TableDecider.php"&gt;TableDecider&lt;/a&gt;,
it produces events, describing
what happens. When passing those events with the internal state to
the evolve-method of the decider, it
applies the events, creating an updated internal state.&lt;/p&gt;
&lt;p&gt;I could use this decider pattern to implement event sourcing, and it also
allowed me to create a kind of testing
framework, that made it easy to create &lt;em&gt;given-when-then-unit tests&lt;/em&gt; in a quite elegant
way, see e.g. 
&lt;a href="https://gitlab.com/rva-vzw/dikdikdik/-/blob/develop/tests/unit/Domain/WriteModel/Table/TableDeciderTest.php#L135-157"&gt;this test that tests joining players&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I created the decider in a more-or-less test driven way, by converting my old
tests for the Table aggregate to new tests for the table decider, and then make them
pass by converting the old logic to the decider based logic.&lt;/p&gt;
&lt;p&gt;This conversion was interesting, because it made me look back into
the existing code for the write side of the table. And whenever I see
code I wrote a couple of months or years ago, I am reminded about the
things I learned since then. That's a good thing, I presume. Other pieces
of the code have become less relevant, since the project has changed as well
during the last couples of years. I created a couple of issues on gitlab
for the oddities I enountered, 
e.g. &lt;a href="https://gitlab.com/rva-vzw/dikdikdik/-/issues/304"&gt;#304&lt;/a&gt;,
&lt;a href="https://gitlab.com/rva-vzw/dikdikdik/-/issues/308"&gt;#308&lt;/a&gt;,
&lt;a href="https://gitlab.com/rva-vzw/dikdikdik/-/issues/302"&gt;#302&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;When all unit tests passed, it didn't take a lot of work to make the integration tests
and e2e tests to be all green as well. Which made me happy, because I think this 
was an indication that the
degree of decoupling in my project is low.
If you look at the &lt;a href="https://gitlab.com/rva-vzw/dikdikdik/-/merge_requests/282"&gt;merge request&lt;/a&gt; 
(which I reviewed en merged myself, since I am the only developer on the project 😉),
you will notice that almost all changes are in the &lt;code&gt;Domain\WriteModel\Table&lt;/code&gt; namespace,
and almost no other things needed to change. The other aggregate, the
&lt;code&gt;ScoreSheet&lt;/code&gt;, still uses my old way of working, and guess what: that doesn't matter.
The score sheet doesn't need to care about the internal workings of the table,
and vice versa, the events are the only things that pass the boundries between them.&lt;/p&gt;
&lt;p&gt;All with all, there were two other things I needed to change. One thing, was the
validation of the games that can be logged. Now I can use a service for this, that I
can nicely inject into the decider, which is way more elegant than what I did before to
let the aggregate class validate the logged games. (The validation service still has some 
issues in its current form, but it is already injected; that's something.)&lt;/p&gt;
&lt;p&gt;Another thing is that the decider is aware of the initial state of the aggregate.
Previously, I prepared the initial state by handling the event &lt;code&gt;TableCleared&lt;/code&gt;. Now
this event is not really needed anymore, but in my integration tests I still
(ab)use it to reset the read models.&lt;/p&gt;
&lt;p&gt;Another interesting change that happened, when introducing the decider, is that I don't
have a dedicated handler for each command anymore. Which feels a little strange to me, I
always learnt that each command should have its own handler.
Now the &lt;code&gt;TableDecider&lt;/code&gt; takes every &lt;code&gt;TableCommand&lt;/code&gt;, and calls 
&lt;a href="https://gitlab.com/rva-vzw/dikdikdik/-/blob/develop/src/Domain/WriteModel/Table/Aggregate/TableDecider.php?ref_type=heads#L74-92"&gt;the handler function that corresponds to the command&lt;/a&gt;.
But I guess these functions are the handlers now, which may be fine.&lt;/p&gt;
&lt;p&gt;Anyway, I am happy about the result I've got so far. I think I will already
release this to &lt;a href="https://score.rijkvanafdronk.be"&gt;score.rijkvanafdronk.be&lt;/a&gt; at the
end of this month, so that we can try it out during the next meetup of our
wiezen club. (Of course everything should just work, 
&lt;a href="https://gitlab.com/rva-vzw/dikdikdik/-/pipelines/997997738"&gt;since all tests are green&lt;/a&gt;,
but I want to use the application quickly after the release, so that we would
notice any bugs that are not covered by the tests.)&lt;/p&gt;
&lt;p&gt;So what's next:&lt;/p&gt;
&lt;p&gt;Now that the write side for the table is handled by a decider, I will also replace
the one for the score sheet. Since the &lt;code&gt;ScoreSheet&lt;/code&gt; class is much smaller than
the &lt;code&gt;Table&lt;/code&gt; class was, this should take less time than converting the table, but
I also have little free time to develop these days, so we will see how this turns out.&lt;/p&gt;
&lt;p&gt;And then there's the process manager, that passes commands to the score sheet when games
are played at the table. I think Jérémy did something like this in his talk, by
combining deciders, but I will probably have to watch a recording of his talk again,
because I'm not sure anymore about how this works.&lt;/p&gt;
&lt;p&gt;Another thing I want to do, is add the generic decider classes I created to the
&lt;a href="https://gitlab.com/rva-vzw/krakboem"&gt;krakboem&lt;/a&gt; libray I created for my own
event sourced projecs. That library needs some updates as well, because it was
created when php 7.4 was a thing.&lt;/p&gt;
&lt;p&gt;For a short period of time, I had timelines for the new features of dikdikdik.
But not anymore, because life happens, and I will see when I have time to code.
Anyway, I want to thank
&lt;a href="https://mastodon.social/@thinkb4coding"&gt;Jérémie&lt;/a&gt; for his inspiring talk. I'm
glad I got this far already, and we'll see what the future brings. &lt;/p&gt;
&lt;p&gt;Until then:
have a nice time &lt;a href="https://score.rijkvanafdronk.be"&gt;playing whist&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;</description><guid>https://blog.johanv.org/en/posts/whist-with-a-decider/</guid><pubDate>Thu, 07 Sep 2023 18:47:00 GMT</pubDate></item><item><title>PHP event sourcing aan de kaarttafel</title><link>https://blog.johanv.org/en/posts/event-sourced-wiezen/</link><dc:creator>Johan Vervloet</dc:creator><description>&lt;div&gt;&lt;p&gt;Vandaag ga ik eens wat dieper in op de inner workings van
&lt;a href="https://www.rijkvanafdronk.be/apps/wdebelek"&gt;WDEBELEK&lt;/a&gt;, de webtoepassing
die ik schreef om online te kaarten (wiezen en gelijkaardige spelletjes).&lt;/p&gt;
&lt;p&gt;Want het is niet alleen erg fijn dat we in tijden van quarantaine en avondklok
nog kunnen kaarten, het is ook bijzonder cool dat de achterliggende software
gebruik maakt van 
&lt;a href="https://docs.microsoft.com/en-us/azure/architecture/patterns/event-sourcing"&gt;event sourcing&lt;/a&gt;;
dat is toch alleszins wat ik probeer.&lt;/p&gt;
&lt;p&gt;Mijn bedoeling is om jullie in al dit moois in te leiden aan de hand van de
&lt;a href="https://gitlab.com/rva-vzw/wdebelek/-/merge_requests/142"&gt;wijzigingen in de code&lt;/a&gt;
die nodig waren voor een nieuwe feature die ik onlangs inbouwde: het &lt;a href="https://gitlab.com/rva-vzw/wdebelek/-/issues/184"&gt;opnieuw 
open leggen van een slag&lt;/a&gt; 
die eigenlijk al opgeraapt was.&lt;/p&gt;
&lt;p&gt;&lt;img alt="playing cards" src="https://blog.johanv.org/galleries/cards/ikanemorenekerale.jpg"&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.johanv.org/en/posts/event-sourced-wiezen/"&gt;Read more…&lt;/a&gt; (15 min remaining to read)&lt;/p&gt;&lt;/div&gt;</description><guid>https://blog.johanv.org/en/posts/event-sourced-wiezen/</guid><pubDate>Wed, 24 Feb 2021 18:26:00 GMT</pubDate></item><item><title>Dikdikdik: a Wiezen (Solo Whist) score app</title><link>https://blog.johanv.org/en/posts/wiezen-score-app/</link><dc:creator>Johan Vervloet</dc:creator><description>&lt;div&gt;&lt;p&gt;For some time I've been working on a web application that
helps you keeping track of the score if you want to play
the Wiezen card game. Wiezen, as we play it, is called
&lt;a href="https://en.wikipedia.org/wiki/Solo_whist"&gt;solo whist&lt;/a&gt; on
Wikipedia.&lt;/p&gt;
&lt;p&gt;Yesterday this &lt;a href="https://www.rijkvanafdronk.be/app"&gt;score application&lt;/a&gt;
(in Dutch, sorry) reached version 1.0. So I thought it would
be appropriate to announce this release on my blog.&lt;/p&gt;
&lt;p&gt;Admittedly, the user interface leaves a lot to be desired. But 
it turned out a very cool application (imho), with a nice
event sourced backend, and gitlab pipelines that automatically
test new source code. 🤓&lt;/p&gt;
&lt;p&gt;The score app follows the
&lt;a href="https://www.rijkvanafdronk.be/spelregels"&gt;whist game rules&lt;/a&gt;
as set by
&lt;a href="https://www.rijkvanafdronk.be"&gt;Rijk van Afdronk vzw&lt;/a&gt;.
The application can be tested (as long as my vps doesn't die) at
&lt;a href="https://score.rijkvanafdronk.be"&gt;score.rijkvanafdronk.be&lt;/a&gt;; source
code can be found &lt;a href="https://gitlab.com/rva-vzw/dikdikdik"&gt;on gitlab&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="can only get this once!" src="https://blog.johanv.org/galleries/misc/ikanemorenekerale.jpg"&gt;&lt;/p&gt;&lt;/div&gt;</description><category>app</category><category>dikdikdik</category><category>eventsourcing</category><category>php</category><category>whist</category><category>wiezen</category><guid>https://blog.johanv.org/en/posts/wiezen-score-app/</guid><pubDate>Mon, 23 Mar 2020 16:03:00 GMT</pubDate></item></channel></rss>