Ga door naar de hoofdinhoud

Upgrading Wdebelek to krakboem 1.0

As I mentioned in a previous blog post, I recently released version 1.0 of rva-vzw/krakboem, the custom php library I created to use event sourcing and CQRS in my applications. It comes together with a Symfony bundle, rva-vzw/krakboem-bundle, which is now at version 0.1.2.

The first project to use version 1.0, was dikdikdik, the score app for the wiezen card game. This is one of my pet projects, 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.

After that, I wanted to use krakboem 1.0 in wdebelek, the app I wrote in covid-times, to play cards online.

screenshot of the wdebelek card playing app

Wdebelek also uses krakboem, but it is different in that it uses event based entity repositories instead of deciders. 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 the upgrade instructions for krakboem 1.0.

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. (update 2024-02-14: Especially the new recipes for codeception 5 were not straightforward.)

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. (update 2024-02-15: Identifiers are now expected to be non-empty as well. This was also quiet an update.)

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.)

If you want to try playing cards with Wdebelek, you have to find at least 2 other people to play, and go to 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).

I still have one project to update: 1jg, 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 😉.

Krak? Boem! My first Symfony Bundle

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 🏆🔓

A little background.

picture of an elephant and playing cards

Back in 2019, I started writing an application that keeps track of the points when playing whist. I called it dikdikdik, a typical bad name for an open source project. It refers to some catch phrase in Dutch, and it can be used at It has become rather popular over time, which I find very cool.

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 lightning talk at the last PhpBenelux conference (ever? 😢) in 2020.

Not long after that, in 2020, Covid broke out, and we couldn't play cards anymore because of the restrictions. So we needed an app to play cards online. 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. rva-vzw/krakboem was born.

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 final and readonly. I know more about the relationship between Traversable and Generator. I also have better understanding about what infrastructure code exactly is. And recently I learned how to use deciders, and krakboem didn't know deciders.

So krakboem could use an update, and that's what I did. I rearranged the classes, added final and readonly, 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 krakboem-bundle. And I also tagged version 1.0 of the base krakboem package 🎉

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.

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.

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.

Whist with a decider

Back in June, I attended DDD Europe 2023. It was the first time I was at this conference, but I liked it a lot, and I was intrigued by Jérémie Chassaing's talk, in which he used a decider to keep track of the internal state of aggregates.

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: dikdikdik, my web based score sheet for the wiezen (whist) card game. It already had commands and events, so using a decider should not be too hard.

someone deciding what to bid with their cards

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.

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 TableDecider, 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.

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 given-when-then-unit tests in a quite elegant way, see e.g. this test that tests joining players.

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.

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. #304, #308, #302.

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 merge request (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 Domain\WriteModel\Table namespace, and almost no other things needed to change. The other aggregate, the ScoreSheet, 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.

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.)

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 TableCleared. Now this event is not really needed anymore, but in my integration tests I still (ab)use it to reset the read models.

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 TableDecider takes every TableCommand, and calls the handler function that corresponds to the command. But I guess these functions are the handlers now, which may be fine.

Anyway, I am happy about the result I've got so far. I think I will already release this to 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, since all tests are green, 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.)

So what's next:

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 ScoreSheet class is much smaller than the Table 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.

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.

Another thing I want to do, is add the generic decider classes I created to the krakboem 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.

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 Jérémie for his inspiring talk. I'm glad I got this far already, and we'll see what the future brings.

Until then: have a nice time playing whist.

Debian 11, XFCE and a bluetooth mouse

Last week, I gave an old laptop a second life. It's an old ASUS, I think it came with Windows 8 back in the day, and I installed Debian 11 with XFCE on it. This looks very retro, but it works like a charm. I can now use the battery for serveral hours, while with Windows it would die after 5 minutes. And today I got my bluetooth mouse working.

a bluetooth logitech mouse, sitting on the laptop

Here is what I did:

Lees verder…

Running apache and php-fpm as services in a gitlab-ci job

I've been using gitlab-ci to automate the end-2-end tests for my PHP-applications for several years now, but I wasn't really happy about the way I got it to work: it involved injecting IP-addresses into configuration files, and starting a web server as a part of the test job.

an elephpant, and the apache and gitlab logo's

Today I can run apache and php-fpm as services, so that the job's script doesn't have to care about the web server, and can fully concentrate on running the actual tests.

Lees verder…

Working around a Pop!_OS networking issue

Update (2021-11-26):

The solution I describe in the original post, did work for a while, and then stopped working. Then I got it working again by removing the kernel modules iwlmvm and iwlwifi, and modprobing iwlwifi again. Worked for a day, and stopped working again. So I guess it just sometimes worked, and sometimes, it didn't.

the TP-Link TL-WR1043ND v2

I think it was just the router. It's a TP-LINK TL-WR1043ND v2, and I installed OpenWrt on it (v19.something), a couple of years ago. Now I upgraded it to v 20.02.1, and I think - hope - that that will finally have solved the problem. I was a little reluctant to flash a firmware update, but it turned out to be very easy. The page for my device on the openWRT wiki had a direct link to the 'upgrade firmware', which I could easily flash using the openWRT web interface (using another device than my laptop, of course).

Lees verder…

Migrating a web app from VueJS to Symfony UX: retrospective

The last couple of weeks, I have been refactoring the frontend of dikdikdik, one of my pet projects, that we use to track the scores when we play the card game 'wiezen'.

twig and class for DelaerSelectComponent

The release of version 3.0, in which I threw out VueJS in favour of Symfony Turbo and Symfony Live Components was announced yesterday, and in this blog post I look back on the refactoring, making some kind of roundup on what I like and dislike about the new frontend I created with those new symfony-ux tools.

Lees verder…

Trying out Symfony Twig Components

Last summer, I attended SymfonyWorld Online 2021 Summer Edition, and I was fascinated by Ryan Weavers talk about Symfony Twig Components.

As the README says on the github project page

Twig components give you the power to bind an object to a template, making it easier to render and re-use small template "units" - like an "alert", markup for a modal, or a category sidebar.

I found the presentation very promising, and I wanted to try using twig components in combination with stimulus for the frontend of dikdikdik, a hobby webapp I maintain, to keep track of the score for the wiezen card game.

Lees verder…