alex-lawrence

Joined 5 years ago

Karma
96
Submissions
22
Member since
Dec 15
Full-Stack Developer, Technical Lead, Software Architect.

Author of https://leanpub.com/implementing-ddd-cqrs-and-event-sourcing

View on Hacker News

Recent submissions

Comment · 5 years ago
This library provides selected useful features of modern UI libraries, while staying at a minimal size. Without the need for compilation and extensive tooling, it is easy and straight forward to use.

Originally, this project started out as an experiment. After using React/Preact for some time, I thought about alternative approaches without the VDOM (and JSX). Soon, I encountered libraries such as htm, hyperHTML, lighterhtml, lit-element and lit-html. All of the mentioned projects are definitely worth checking out.

I would love to hear your feedback on the library. Even more, if you have a scenario where adequate could be useful, please let me know! Also, feel free to ask me anything about the project, be it about its functionalities or about bundle size optimizations.

Comment · 5 years ago
The Aggregate Root must track all Domain Events that occur upon executing an action and make them accessible somehow. Only after the successful persistence of the associated state change (and/or the events), they can be published via an Event Bus. The Aggregate itself only expresses that Domain Events occurred, but does not deal with publishing.

The article from Udi Dahan shows Domain Event handlers that "will be run on the same thread within the same transaction". This implementation is not suitable for handlers that affect other transactions. Udi explains that "you should avoid performing any blocking activities, like using SMTP or web services. Instead, prefer using one-way messaging to communicate to something else which does those blocking activities." What he is referring to as "one-way messaging" is the actual event publishing in my opinion and must guarantee event delivery.

In my book, the example implementations store all occurred Domain Events together with the Aggregate state. This is because it resembles the later use of Event Sourcing. There is a separate component that watches for changes in Aggregate data and publishes new Domain Events. After publishing, the events are marked accordingly.

Regardless of where newly occurred Domain Events are retained, it should be persistent. Many times, the events are stored in a separate table inside the same store as the affected Aggregate. Later, they are retrieved, published and either marked or deleted. This is called a Transactional Outbox: https://microservices.io/patterns/data/transactional-outbox.... The approach ensures that both the Aggregate change and the request to publish an event happen within the same transaction. The actual publishing happens in a separate one. This way, you get guaranteed event delivery or more specifically "at least once" delivery.

Comment · 5 years ago
Comment · 5 years ago
Without Event Sourcing, I would say there is almost no boilerplate code for aggregates themselves or their root Entities. After all, an Entity can be implemented as plain old class or object. For event-sourced aggregates, it depends on the implementation style. With OOP, there might the typical AggregateRoot base class. With a more functional style, there can even be less of boilerplate code.

About the Domain Event publishing, I'm afraid I don't understand the question. What challenges did you face? Is it about event-sourced aggregates?

Comment · 5 years ago
I will definitely look into this. What I can already say is that it has the best name for a ES/CQRS library!
Comment · 5 years ago
Thank you!
Comment · 5 years ago
I think this is a great recommendation for any new project that is considering to use Microservices. I like the approach of an in-memory event-driven system. This helps to enforce a message-only relationship between different conceptual parts from the start.

In fact, I did the same in one project. Also, while I am not covering Microservices in my book, the Sample Application uses a similar approach. The different contexts integrate via event communication. At first, this is an in-memory implementation and everything is running in a single process. Later on, it is replaced with a filesystem-based variant and the individual contexts are operated as individual programs.

Comment · 5 years ago
Please note that I have limited experience with domains where Event Sourcing is without a doubt the weapon of choice. Hope my input still helps. Maybe there are other people that can give more qualified input on that. In the end, I am not trying to advocate for the pattern.

The project was about building a SaaS for structured meetings, both for on-site and remote use. It involved topical areas such as collaboration, moderation and presentation. The model defined that every meeting consists of six steps, where each is facilitated with one specific method (out of multiple). There were also additional functionalities such as a collaborative whiteboard and audio/video communication.

I briefly mentioned this in another comment: With regard to software architecture and pattern use, the project is a negative example. CQRS and Event Sourcing was prescribed on a system level. Regardless of conceptual/technological boundaries, every part made use of it. This decision was by no means reinforced with domain- or business-specific arguments. However, for us as developers, it was a great learning opportunity.

In terms of significant benefits for specific contexts, I can only think of the whiteboard part. However, even for that, it is about a feature we never got to implement. At some point, we wanted to add a "Undo" functionality. With Event Sourcing, you can simply append events that represent the reversal of previously persisted state transitions.

Independent of domain-specific aspects, I experienced three universal benefits. I hate to say it, but one was in fact reporting. Another benefit is the increased possibility to solve concurrency conflicts in a domain-specific way. Third, an event-sourced service is an ideal foundation for sending notifications, such as when publishing Domain Events. In the project, it helped us to build a real-time reactive User Interface. Of course, I'm not saying you necessarily need Event Sourcing for that.

Comment · 5 years ago
Could you explain which aspects specifically require a lot of boilerplate code? Judging from my experience, I think the tactical DDD patterns are straight forward to implement. I didn't mention this in my post, but the Node.js framework was only concerned with CQRS & Event Sourcing.

I fully agree with you that (static) types are inevitable for tackling rich/complex domains adequately. Personally, I would often recommend the use of TypeScript over plain JavaScript.

As for the book, when I started working on it, I was using plain JavaScript. Over the course of the past four years, there were times, when I considered to rewrite the DDD parts with TypeScript. My current plan is to add an appendix or integrate additional content about (static) typing.

While types are an important aspect for the Domain layer, I think the rest of the book works fine without TypeScript. Its absence might even help to keep the code example more concise.

> I'm curious whether you used plain JavaScript on the professional projects?

Yes, in both relevant projects we were using plain JavaScript (or CoffeeScript). We had many runtime type checks and a high test coverage to overcome the lack of static types. TypeScript would have definitely been the better choice.

Comment · 5 years ago
Thanks!

It is important to note that my book is not an alternative to "Domain-Driven Design" by Eric Evans. Rather, it is an introduction to DDD, an explanation of CQRS and Event Sourcing and an implementation guide. Also, it is not explaining how to approach and model complex domain problems. I wouldn't consider myself experienced in that. Everything I worked with so far was rather trivial.

I can very much relate to your experience with projects that applied CQRS and Event Sourcing. In fact, the longest project I worked on was a negative example. The patterns were used as part of the system architecture. Their use was never justified with any reason specific to the domain or the business. In the end, some parts of the system would have been better off with a completely different architecture.

I already have convinced project teams to not use Event Sourcing when they thought they needed it. Also, I often hear it being conflated with Event-Driven Architecture.

Comment · 5 years ago
Thanks for the feedback. Happy to hear that you appreciate the UI chapter. For me, it was important to explain how to approach the User Interface. I often had the feeling that this part was a bit neglected when reading about CQRS & Event Sourcing.

The book contains numerous standalone examples throughout the chapters, which are all executable. At the end of each chapter, the explained concepts are applied to the Sample Application context.

The Sample Application is a greatly simplified task board. Users can register, login, create projects, manage team members and work with a task board. The task board is essentially a collection of items, grouped into three columns. Individual tasks contain details such as title, description, status, assignee, etc.

While there are some constraints/invariants in the Domain Model, I would consider the Sample Application fairly trivial. It does not represent a complex domain problem. One reason for this is that I personally did not encounter any highly complex domain so far. It would have been weird if I tried to explain something I am not really experienced in.

> what if domain logic can be optimized in the database?

IMHO, the question is a bit too generic. The generic recommendation would be to not put domain logic into the database. However, one would need to look at what the domain logic in question is. Also, what does "in the database" mean? Are we talking about code that is being executed in the database environment, such as PL/SQL?

> examples where you have property method on a model that goes and performs additional queries

This sounds a bit like the Active Record pattern or the use of an ORM, where one "model" is somehow linked to another. Again, a generic answer would be that domain objects should stay free of infrastructural concerns. If you have posts and comments and need to get the latest comment on a post, this represents a use case. Use cases are executed by an Application Service. This part is allowed to query any number of domain objects / data sources. If you would be using CQRS, you would likely have a denormalized Read Model that contains comments per post.

Comment · 5 years ago
In fact, the book was called "Implementing DDD, CQRS and Event Sourcing in Node.js" up until the release of its complete version. I thought about this for a longer time and decided to remove the "in Node.js" part from the title. Instead, I made it clear in the book description. In my opinion, the book can be valuable for anyone who is interested in the concepts, regardless of technology choices.

I think that it is fair to say that my book is partially also about Node.js, but not primarily. I wouldn't say though it is about JS. In fact, many of the code examples would look similar in other languages. Furthermore, the use of Node.js helps to provide concise code examples and executable code without much ceremony.

When reading "Implementing Domain-Driven Design" by Vaughn Vernon, all the code examples are in Java. The book "Enterprise Integration Patterns" has a lot of code examples and all of them are also in Java. The most recent edition of "Refactoring" by Martin Fowler uses JavaScript. Still, I wouldn't say that these books are about a particular programming language.

Comment · 5 years ago
I only heard of Nest.js a few weeks ago and haven't had the chance to look it. Therefore, take my reply with a grain of salt.

Libraries and frameworks can help you with different things, but they can also get in your way. If the CQRS module of Nest.js seems useful for a specific scenario, I would give it a try.

CQRS can be implemented in many different ways. Even more, a lot of software is applying this pattern inherently to some extent.

If you separate a software (or a part of it) into a write side and a read side, the two become independent. They both only interact with the synchronization mechanism. Therefore, they are free to use their own set of patterns, libraries and even technologies. Many times, the two parts are operated as individual programs/services and can scale autonomously.

Personally, I never encountered a situation with implementing CQRS where I really would have needed a framework. In fact, I contributed to a Node.js framework for implementing CQRS and Event Sourcing. In hindsight, I think the framework was a mistake and should not even be used.

My book explains how to implement all the concepts, patterns and mechanisms without any third-party code. The goal is not to use the custom code in production, but to understand how everything works.

Comment · 5 years ago

Live from the official Hacker News API

A modern reader for Hacker News · SvelteKit + Skeleton