π₯ Explore this awesome post from Hacker News π
π Category:
β Hereβs what youβll learn:
Golo: Frank, you are one of the managing directors at Digital Frontiers and also one of the architects and main developers of OpenCQRS. Over the past months we’ve seen a lot of interest in the framework, especially now with version 1.0 out. Some of our customers have even been building production systems with the release candidate for quite a while already, which shows how stable and usable it has been early on. Before we dive into details, let’s start at the very beginning: can you tell us a bit about how OpenCQRS came to life? What triggered the idea and what gap were you trying to fill?
Frank: To be honest, OpenCQRS started out as an experiment or prototype back in 2024. When the two of us first met each other to talk about EventSourcingDB, I immediately recognized that it contained a lot of hidden gems, such as hierarchical event streams. So, imagining a suitable CQRS framework on top of the EventSourcingDB did not feel like building yet another framework. Instead we were eager to expose those gems to Java developers, who might not even know yet, what they lacked so far.
A colleague then started out by implementing a first prototype on a train ride to Hamburg. The result, though in a very early draft state, convinced us that we could come up with a very clear design for CQRS applications. We especially focused on getting rid of some of the annoying relics of typical CQRS frameworks as well.
Moving Beyond Aggregates
Golo: I know that quite early on you decided to move away from the traditional aggregate pattern, which is a pretty bold step since aggregates have been central to Domain-Driven Design (DDD) for years. Instead, you speak about No Aggregate. Can you explain how this idea evolved and why you deliberately stepped away from the classic approach?
Frank: Well, this is definitely the number one relic that we abolished: I’ve never felt very comfortable with the term “aggregate”, as the term does not express clearly, which problem it actually addresses, at all. In the end, events are the predominant aspect of CQRS/ES style applications. So, in order to decide whether a command is acceptable or not, you need to aggregate the relevant events in order to make that decision. The aggregate therefore determines your consistency boundary, that is, which events need to be sourced to make this decision and β from the perspective of the underlying event store β to assure that new events published don’t violate these consistency constraints.
So from a developer’s perspective it felt wrong to impose the term “aggregate” on them, when a simple, immutable write model class β for instance a Java record β is all you need. In the end, the developer has to decide, which events are necessary for a specific command to be handled properly. Put differently, one might choose completely different write models for different commands all related to the same aggregate. This flexibility is what we considered more valuable than enforcing the term “aggregate” within the code.
No Aggregate vs. Kill Aggregate
Golo: That reminds me a lot of Sara Pellegrini’s talk “Kill Aggregate!”, but you’ve pointed out several times that your goal isn’t to “kill” anything β you deliberately call it No Aggregate. Could you explain the difference and what mindset shift developers should have when moving to your approach?
Frank: I think for developers new to or just beginning to work with CQRS/ES there isn’t a major shift, at all. It’s natural to think about your business constraints, when starting to implement a command handler’s business logic. You would have to develop with these constraints in mind anyway, so there is no need for an aggregate. The focus is on the relevant events containing the necessary information to “decide” and I’m convinced that this might even lead to better code.
Instead of re-using an existing aggregate class, just because it seems to fit the constraints of your next command handler, we could focus more on what’s really needed. However, developers already familiar with the concept of aggregates, will have to “unlearn” a bit of what they were used to so far.
At last, I’m also a bit concerned about the DCB hype, which originates from “Kill Aggregate!”. While it is invaluable to be able to dynamically query the events needed for each command handler individually, I fear that developers will over optimize to an extent where the relevant constraints might be violated.
Architecture and Design Principles
Golo: When you think about the overall architecture of OpenCQRS, what are the core principles that guide your design decisions? I’m especially curious which aspects you consider essential to keep the framework lean but still powerful.
Frank: OpenCQRS is relatively new, so we were blessed with modern Java features like immutable records or sealed classes, which we happily adopted. This is why OpenCQRS requires Java 21 as a minimum version. In addition to that we love Spring and Spring Boot and know that most of the Java enterprise projects out there are written using Spring. So we wanted to provide a first-class native integration with Spring Boot, which greatly simplifies command and event handler definitions using annotations.
OpenCQRS’ modularization, however, enables developers to use it using plain Java, as well. We thus leave plenty of room for other integrations to step in, if needed, for instance an integration with Ktor. Finally, we decided to avoid orchestration, when running OpenCQRS in cloud environments, at all costs, which is why we don’t provide any server components, whatsoever. We believe in choreography as the key to building scalable and reliable cloud native applications.
Testing as a First-Class Citizen
Golo: You highlight testing a lot. Why is testing so central in OpenCQRS, and what makes the testing experience different or easier compared to other frameworks? Are there particular techniques or patterns you encourage?
Frank: First of all, I am a big TDD enthusiast, so I can assure you that OpenCQRS itself is thoroughly test covered to maintain a high quality. But speaking about TDD, I often found myself struggling with the idea of test-first development, for instance in layered architecture projects. Developers more than often end up in a mocking hell, with the test code more or less duplicating the production code. This becomes a nightmare, whenever refactoring is needed, and I think that a lot of developers out there dislike TDD just because of that.
CQRS on the other hand offers clear and simple interfaces by means of inbound commands and outbound events, much like stdin
and stdout
in Unix. This enables us to express our tests as black-box tests without the burden of excessive mocking. OpenCQRS supports this by providing developers with fluent API test fixtures enabling them to easily define their constraints using Given-When-Then syntax, even before any of the command handlers under test was even written.
Lightweight by Design
Golo: You often describe OpenCQRS as “lightweight”. What does that really mean in practice β how does it help developers build something productive quickly and with relatively little complexity?
Frank: “Lightweight” for me has multiple aspects: first of all there is the usability of the framework, that is how easy it is for developers to reach their goals, which obviously should be building business applications and not fiddling around with the framework itself. This is why we focused strongly on the Spring Boot integration, which provides us with superior configuration, such as application properties for the event processors, and the magic of auto-configurations that enable us to detect command and event handler definitions using simple annotated methods.
The second aspect I would like to point out is the focus on flexibility and opt-in. OpenCQRS, by default, chooses the least invasive configuration, yet gives the developer the opportunity to override it easily. For instance, we do not execute event handlers transactionally by default, if executed within a Spring application. However, the developer may choose to do so by simply annotating any event handling method with Spring’s @Transactional
annotation.
And last but not least we strived to not reinvent the wheel for commonly solved problems, such as distributed leader election, where we suggest Spring Integration β another Spring project β to be used, if needed.
Scalability and Cloud Readiness
Golo: Cloud readiness and parallelization are also topics you talk about frequently. How does OpenCQRS help teams build large, scalable event-driven systems that work reliably in modern distributed environments?
Frank: Scalability and reliability are two aspects that tend to compete with each other to a certain degree. From a scalability point of view, for instance, it makes sense to simply start additional compute nodes (JVMs) as needed, if the application work load increases. The question, however, arises how to reliably avoid command and event handling inconsistencies due to the increased level of parallelization.
Let’s focus on the command side first: two command handlers competing with each other is a very common scenario. Luckily, the only side effect of command execution is the fact that new events may be published. The solution to this problem is commonly referred to as “optimistic locking” and EventSourcingDB provides us with a set of well established preconditions to detect any race conditions and prevent conflicting event publications.
With respect to event processing on the other hand, you want to assure that event handlers do not process the very same event in parallel. Here, locking strategies such as distributed leader election are supported by OpenCQRS to coordinate the work within a clustered environment. So actually for both scenarios there is no need for a dedicated coordinator, such as a central server component, without compromising the scalability of the overall system.
Developer Experience
Golo: We repeatedly hear from teams β including those who already started using the release candidate β that working with OpenCQRS feels straightforward and productive. They can get things done quickly without heavy infrastructure or steep learning curves. Why do you think developers react so positively to the experience?
Frank: I’d say it’s still too early for the acclamation here. We are proud, of course, that developers like the way we built OpenCQRS and feel comfortable with our design decisions. However, many frameworks out there that started out 10 years ago, might have looked clean and crisp back then. We are very well aware of the fact that the actual challenge is to keep up this spirit over time, but I am convinced that we will.
Integration Landscape
Golo: Integration with other frameworks is always a topic developers care about. Many use Spring, but there are also teams working with frameworks like Ktor or others. How does OpenCQRS fit into these different environments? Do you explicitly recommend Spring, or what should developers consider if they use other frameworks?
Frank: We strongly recommend Spring developers to use OpenCQRS together with its Spring Boot starters. Since more than 80% of all enterprise Java applications out there are built using Spring, this is probably the one-stop shop for them. OpenCQRS itself, however, is strictly separated into core framework modules and those provided for Spring environments. Technically speaking, you could build a fully working OpenCQRS application with plain Java. So we expect other popular application frameworks, like Ktor, to integrate with OpenCQRS as well, just like Spring. And we at Digital Frontiers would be happy, if the community were contributing here.
The EventSourcingDB Connection
Golo: How do you see the connection between OpenCQRS and EventSourcingDB? Where do the two technologies complement each other most effectively and what advantages does that bring?
Frank: In my opinion the biggest advantage for developers is OpenCQRS’ tight integration with EventSourcingDB. We carefully designed our CQRS abstraction around the database’s features. It’s a thin line between relieving the developers from low-level details on the one hand, still allowing them to dive deeper, if needed. What we tried to avoid at all costs is to build yet another event store abstraction that claims, one could easily replace the underlying event store at no cost. I’ve seen this pattern way too often back in the days of J2EE, where over-abstractions like Enterprise Java Beans were highly worshipped just in case you wanted to switch your SQL database vendor, which surprisingly no one ever did. An event store is even less standardized than an SQL database for good reasons, so I think it’s important to integrate it properly.
Lessons Learned
Golo: When building version 1.0, were there any unexpected challenges or lessons learned that you’d like to share with other framework authors or potential users?
Frank: That’s easy to answer: never underestimate the effort needed to write a good documentation!
Getting Started
Golo: And for those who want to get started with OpenCQRS now β what should they absolutely know at the beginning? Are there key concepts or practical tips you would give to newcomers?
Frank: I think they should have a basic understanding of CQRS in general. The “unlearning” needed to switch to those paradigms, especially if you were used to layered 3-tier architectures all the time, shouldn’t be underestimated. So I suggest to start out with an easy domain first to get used to CQRS/ES.
OpenCQRS currently includes an example application for a very simple book library domain. Together with our Getting Started Guides they should be able to adapt to their own needs. On top of that, I strongly recommend to explore the testing capabilities of CQRS and OpenCQRS in particular. Finally, we offer more advanced sample applications for those diving deeper into OpenCQRS.
Looking Ahead
Golo: And looking ahead β what’s next for OpenCQRS? What are you working on for the future that developers can look forward to?
Frank: Actually, there’s a lot of ideas in the pipeline. We are currently working on DCB support, which will give developers the choice to dynamically query the events needed for each command handler individually. While this has a direct impact for developers, there are other topics such as GDPR support that need to be addressed as well, especially for the enterprise market. And I am pretty confident that further ideas will arise as more people start to adopt CQRS/ES.
Golo: That sounds pretty impressive and inspiring, and I’m really looking forward to seeing what comes next. Thanks once again, Frank, for taking the time to share the story and ideas behind OpenCQRS with us.
Frank Scheffler is Managing Director at Digital Frontiers GmbH & Co. KG, a German IT consulting company focused on digitalization and cloud solutions. For more information or to get in touch, visit the Digital Frontiers website.
β‘ Tell us your thoughts in comments!
#οΈβ£ #Rethinking #CQRS #Interview #OpenCQRS
π Posted on 1761170950