6 ms·
The DDD/CQRS/ES topic appears on Hacker News every so often, and never fails to stir a strong debate. In fact, I was going to "Show HN" an Event Sourcing librar
by victorNicollet 9y ago
The DDD/CQRS/ES topic appears on Hacker News every so often, and never fails to stir a strong debate. In fact, I was going to "Show HN" an Event Sourcing library I open sourced yesterday, but I guess I'll wait until everything dies down a bit :-)
I believe that the core principles of DDD/CQRS/ES are flawed and are the cause of a lot of pain. If your team plows forward and ignores the pain, you will have a bad experience working there. If your team decides to fix the problems with the architecture (usually in a way that's rather specific to their situation), and still insists that they're doing DDD/CQRS/ES, then you will have a great experience. The same can be said of many approaches to SQL database design.
When I joined Lokad, most of the code had been written by a strong CQRS advocate, and there were significant pain points caused by this approach that would have been nonexistent with a plain old SQL architecture. The author himself did a retrospective that covers a few issues: https://abdullin.com/lokad-cqrs-retrospective/ https://abdullin.com/lokad-cqrs-retrospective/
Instead of dropping everything and moving back to a more conventional SQL architecture, we dropped everything and moved to a solution which, if I were to describe it as DDD/CQRS/ES, would have me branded as a heretic by the DDD/CQRS/ES community: it does fit the definition, but it does not follow the best practices. There is a single data model shared by both commands and queries. Commands can sometimes return data. Each (micro?)service has access to exactly one aggregate. There is no uncertainty on event ordering, and no eventual consistency at the aggregate level. Materialized views for each aggregate are kept in-memory at all times. All of these intentional weakenings of the CQRS architecture were driven by pragmatic needs, and made with knowledge of the consequences.
- bonesss 9y ago> The author himself did a retrospective that covers a few issues: https://abdullin.com/lokad-cqrs-retrospective/ https://abdullin.com/lokad-cqrs-retrospective/ Having read the article: veeeeeery little of what is mentioned is related in any meaningful sense to CQRS... Horse-before-the-cart framework design is always bad. Encapsulating untested theories in frameworks instead of lifting them from operational designs, always bad. Building frameworks as a learning exercise, bad. Abstracting away data decisions and then trying to provide opinionated answers to storage at the framework level, very bad. Conflating logical system architecture with supplier provided products (ie cloud services), is framework _cancer_. That is simply not a reasonable starting point to provide value and scalable systems, and the end result was the same as all other similar attempts: an A for effort with a result that was at best 'close, but not quite...' To be clear: I do not intend this as criticism leveled at the author or the company. The article is great. I very much agree with his analysis though: > Lokad.CQRS was created with a very short-sighted design approach in mind, a reusable LEGO constructor...These days I'd try to limit the damage I inflict upon the developers and avoid writing any widely reusable frameworks This is where all the issues lay... Premature framework development causing up-front decisions untethered to practicality based on conjecture and prognostication instead of experience in a challenging domain insufficiently understood by the framework architect. From a high level perspective: neither CQRS, nor framework development, nor application development were sufficiently groked before being baked into a long-term production commitment. Those are organizational issues, not CQRS issues. In the same vein, coming from such an environment and basing judgment of DDD or CQRS on anything that came from that environment won't hold water. The architectural problems you're talking about, the core principles you think are flawed, work stunningly well in other places that have not made the same underlying mistakes. CQRS advocates != CQRS experts != framework experts.
- UK-AL 9y agoI'm CQRS advocate. None of are weakening the CQRS. CQRS is in fact pretty damn lose. "There is a single data model shared by both commands and queries." - Nothing wrong with that, especially in simple cases. "Commands can sometimes return data" - Well commands can succeed or fail. Greg young himself admits commands are really synchronous, and you need to communicate that. "and no eventual consistency at the aggregate level." - This is the recommended approach. Between aggregates and it becomes loser. "Materialized views for each aggregate are kept in-memory at all times" - Thats some advanced CQRS usage there.
- gregyoung1 9y agoI will speak for myself. Commands are by definition synchronous and return a success/failure. One of my favourite read models to use is an in memory model providing I can keep all of the data in memory (and its reasonable for the query patterns).
- victorNicollet 9y agoMaybe I'm not as much of a heretic as I thought I would be :-)
- UK-AL 9y agoStarting from fresh these days I would use something 2 way for commands, queries like HTTP REST. But a messaging system for events. If i'm using event sourcing use a dedicated event sourcing database with catchup subscriptions etc
- codebeaker 9y ago> a dedicated event sourcing database with catchup subscriptions etc Can you recommend any?
- slashdotdash 9y agoGreg Young's Event Store[1]. [1] https://geteventstore.com https://geteventstore.com
- sandGorgon 9y agohi - could you explain the implementation of this "Materialized views for each aggregate are kept in-memory at all times" ? i have been considering a heretical flavor of CQRS/ES as well, where the command returns data.... and i synchronously build the latest state before I return (rather than building through the whole event stream). when you say "materialized views" - do you really mean the current state of an Order for example ? and by "in memory", is it being persisted to a database ?
- victorNicollet 9y agoWhat we would do is have a single aggregate representing the entire state of a micro-service. For instance, for the "Orders" micro-service, it would contain all orders in the system, with events such as OrderCreated, OrderPaymentReceived, OrderShipped, OrderCancelled, and so on. Then, we would have a materialized view that would be a single C# immutable object (canonically called `State`) that contains a dictionary of every order, and maybe a few indices (such as "identifiers of orders currently waiting to be shipped out" or "list of orders by customer"). Everything fits in memory, so every query is simply a bit of C# code that traverses the in-memory graph of objectd rooted at the `State`. A command emits events, which are then applied by the system to create a new `State` from the previous one. Events emitted by other instances of the application are also fetched by the system every so often, and you can request a "force catch-up" to guarantee that the `State` you access takes into account all events appended so far (so that you're certain to see the results of your actions, even if the load balancer bounces you from one instance to another). Here's what we use: https://github.com/Lokad/AzureEventStore https://github.com/Lokad/AzureEventStore