After getting the first version of #Java samples of #EventSourcing, I asked the community for feedback for my PR github.com/oskardudycz/Ev…
I wanted to get harsh but fair feedback to make it idiomatic and, in general, better. I got what I ask for, let me share what I learned 👇😅 1/
Java Optional should be used only as a result, to reduce the confusion around the `void` type. It should not be used as a method input parameter or field. This makes sense, as Java generics are more compile-time templates and are zipped. See more in: nipafx.dev/design-java-op… /2
I already used sealed interfaces to have a nice pattern matching while rebuilding the state from events. Yet it appeared that they allow full "union types" experience! After that, I went further and created 👇It enables concise and precise modelling /3
I'm a huge fan of slicing architecture vertically ( event-driven.io/en/how_to_slic…). I also think that composition = simplicity. Yet, "simple" means different for everyone. Sometimes is better to group smaller things to provide more accessible structure like github.com/oskardudycz/Ev… /4
Spring Boot has a built-in ApplicationEventPublisher ( reflectoring.io/spring-boot-ap…), so there's no need to implement a custom in-memory bus. I had to go full-circle and remove my "great" but totally redundant implementation. Reminder: not forget to learn tools, before going custom /5
Pushing up all the possible exceptions is like being sainter than the pope. If we don't want to handle them in code, then it's better just to make them runtime exceptions and catch them in a generic mechanism. Read more about checked/unchecked split /6 baeldung-cn.com/java-checked-u…
Btw. for the global exception handling, you can use ControllerAdvice and ExceptionHandler annotation like that 👇This enables doing an automated mapping to HTTP Statuses /7 github.com/oskardudycz/Ev…
As I'm not a huge fan of annotations/attributes/decorators with conventional-based magic, I decided to do manual Java Beans registrations. I stand by my decision, but I think that I went too far. It's better to compose stateless code rather than outsourcing it to DI /8
Reviewers also motivated me to finish what I started instead of postponing it to other PRs. E.g. thanks to that I came up with a nice Given/When/Then API testing syntax 😀👇 /9
- github.com/oskardudycz/Ev…
- github.com/oskardudycz/Ev…
-
Instead of doing manual threading with synchronised, Thread.sleep etc., in @eventstore Subscription to $all error handling, I found docs.spring.io/spring-batch/d… and used it: github.com/oskardudycz/Ev…. Again, throwing out code helped me to make it better and resilient /10
I also added Log4J instead of System.out.println. Yup Log4J. Btw. I think that their famous "breach" was more an issue with the enterprises not having a proper dependency upgrade strategy. Everyone can be breached, but we need to be prepared for that as architects. /12
I also added CI using @eventstore and @PostgreSQL Docker images to run end-to-end integration tests. We're not living in caves anymore. It's fine to run tests against real databases /13 github.com/oskardudycz/Ev…
If you reached here, then I hope that this thread will help you learning on my mistakes. Not always we have to do our own. Here's the full, merged sample. Feel free to send a feedback if you want to have it expanded! /14 github.com/oskardudycz/Ev…
Some numbers:
- 143 comments in discussions,
- 47 commits,
- 80 files changed,
- 3,906 lines of code.
That was a long run!
Thanks again for the great reviews and the lesson I got! 😅 15/15
@dustinmoris@noseratio Unfortunately, the narration that's NATO's fault comes from the Russian propaganda. Beware of spreading it forward.
There were neither talks about that. The only reason why Putin invaded Ukraine was that it finally started to be a sovereign country 1/
@dustinmoris@noseratio Even though Ukraine got technically independence it wasn't neutral at all as you said. It was still reigned by an ex-party oligarch that was steered by Russia (see Łeonid Kuczma). It was almost a Russian puppet-like Belarus now. So please don't tell that they were neutral /2
@dustinmoris@noseratio The real, practical independence came in 2004 in the Orange Revolution. People were so fed up with oligarchs, bribery and they just wanted to have control over their lives. That meant being finally free from the direct Russian impact. No NATO, no Western impact. Humanity. 3/
@tomasz_ducin@tomasz_ducin, chciałbym podkreślić, że na bazie relacyjnej można zamodelować każdą inną bazę, nawet event store, dlatego mówimy tutaj o różnicach między Event Sourcing, a klasycznym znormalizowanym podejściem 🙂 Oczywiście w takim podejściu da się zrobić obsługę koszyka 1/
@tomasz_ducin Główna kwestia, w której Event Sourcing ma przewagę jest brak utraty danych biznesowych. Jeśli np. ktoś dodał produkt do koszyka, a następnie go usuniemy, to z perspektywy klasycznego podejścia osiągniemy ten sam stan. W Event Sourcing będziemy mieć dwa zdarzenia 2/
@tomasz_ducin To oczywiście nie musi być problemem, w niektórych przypadkach jest to wystarczające, ale w obecnych czasach przechowywanie danych jest względnie tanie, ale za to informacja jest droga. Niektóre domeny biznesowe mogą wyciągnąć więcej z danych,inne mniej. ECommerce myślę więcej 3/
If you’d like to know why you may not need snapshots and learn modelling patterns to do #EventSourcing efficiently, read my latest article on @eventstore blog 👇
It may sound blatant, but I think that there are not many resources like that on this topic 1/ eventstore.com/blog/keep-your…
It’s a looking article, much longer than the length of the streams you should keep in the event store 🙂 I tried to keep it shorter or split it, but my main goal was to provide a thorough, nuanced and complete explanation. So grab a glass of preferred drink and have a read 2/
This is the third part and (hopefully) the last one of the triad about temporal modelling patterns. I started with a general introduction, explaining closing the books as to why you should reconsider your decision about snapshots. 3/ eventstore.com/blog/snapshots…
@bitbonk@bitbonk good question! Indeed, the IoT model seems to be aligned with Event Sourcing, as we're listening for the events and then doing interactions. The main issue is the nature of data coming from machines and the frequency. In Event Sourcing events gather business value 1/
@bitbonk IoT data is usually raw. Also, the number of measurements and their frequency can be really high, especially for the really busy production line. Most of the event stores are not so lightweight. So they not always can be run on e.g. raspberry pi. 2/
@bitbonk Also, quite often, they have a bigger frequency than event stores can handle per second. The common pattern is to do the data ingestion. So using lightweight, but fast type of storage (e.g. key/value) or queue that will batch the events from IoT, group and change into events /3
@mzagozda Dziękuję bardzo! Cieszę się, że się podobało 🤩 Bardzo dobre pytanie.
Zacznijmy od tego, że sam Event Sourcing jest wzorcem, który co prawda o tym mówi, jak przechowywać dane, a w zasadzie nie tyle jak co w jakiej formie - konkretnie zdarzeń. Jednak sam w sobie nie mówi gdzie 1/
@mzagozda Zatem moglibyśmy przechowywać te zdarzenia równie dobrze w pliku tekstowym, binarnym, excelu, xmlu, json, czy też już bardziej rzeczywiście w bazie danych. No i tutaj w zależności od tego jaka jest charakterystyka naszego miejsca przechowywania takie mamy też możliwości 2/
@mzagozda Jeżeli korzystamy z jakiegoś rozproszonej bazy danych to może to być faktycznie utrudnione. Większość z nich ma możliwość tylko "symulowania" takiej weryfikacji (np. DynamoDB aws.amazon.com/blogs/database…). Zwykle jest to przy symulowane poprzez algorytmy rozwiązywania konfliktów /3
@HaripraghashS@HaripraghashS 2 short questions without 2 short answers 😅But let's try! Projections for me when I started my journey with #EventSourcing was the hardest thing to understand. I thought: ok, I can rebuild the aggregate state by replaying events one by getting them by id 1/
@HaripraghashS Having that I'll have the state of the single aggregate. Wait a minute! If I won't to do that for the aggregate list then I'd need to get all events for those aggregates and reply it one by one? Nah that's can't be! For that we have we have projections. As you for sure know /2
@HaripraghashS What are projections? It's just representation and interpretation of the set of event. What's more when we're replying events to get aggregate state - that's also projection. It's easy to forget about that because it's default case. We're just interpreting events to get state /3