Event Driven Architecture & DDD
Event-Driven Architecture (EDA) revolves around events, as the name implies. It's an architecture focused on fostering the creation, detection, consumption, and response to events. 😉
Lets consider a system which has been designed using Hexagonal architecture to represent the notion as its participating in an EDA by means of incoming and outgoing messages. An EDA doesn’t have to use a Hexagonal, but it’s a decent way to present the concepts here.
Now lets get into the diagram mentioned above:☝️
The diagram just demonstrates how Event-Driven could be supported if multiple systems were Hexagonal at their foundation.
For simplicity lets consider the hexagonal’s mentioned above are the different services(i.e., different bounded contexts) communicating with each other using Ports(represent the entry and exit points for interactions with the application) and Adapters[adapters serve as the bridge between the core application logic (the inner hexagon) and the external environment (the outer layers)].
Events enter and exit the system by means of the symbolic triangles. And the triangle clients acting as the input/output are the different kinds of messaging mechanisms as bridge btw different Hexagons. And each client communicates via a Port which is different for both input and output. Each separate port represents the message transport over mechanisms such as AMQP, RabbitMQ, Message brokers rather than the more common HTTP clients.
It’s possible that a specific Domain Event received represents only one part of a multitask process. Until all anticipated Domain Events arrive, the multitask process is not considered completed. It could become complex to track a system in a distributed system. But first some initial groundwork is in order. Message-based systems often reflect a Pipes and Filters style.
Pipes and Filters:
Even the day-to-day shell commands we use, represent the Pipes and Filters approach.
$ cat phone_numbers.txt | grep 303 | wc -l
3
$
The linux command above represent to find the contacts from the text file which has a 303 number as the match.
1. The cat utility outputs the contents of phone_numbers.txt to what is called the standard output stream. Normally this stream is connected to the console. But when the | symbol is used, the output is piped to the input of the next utility.
2. Next, grep reads its input from the standard input stream, which was the result of cat. The argument to grep tells it to match lines that contain the text 303. Each line that it finds is output to its standard output stream. As with cat, grep’s output stream is now piped to the input of the next utility.
3. Finally, wc reads its standard input stream, which was piped from grep’s standard output. The command-line argument to wc is -l, telling it to count the number of lines it reads.
Now lets relate how Pipes & Filters are similar to the EDA:
Now, what if we were to think of each of the utilities cat, grep, and wc (or type and find) as components in an Event-Driven Architecture? What if we even implemented components to act as message senders and receivers to process telephone numbers in a similar way?
From the above flow diagram: Component named PhoneNumbersPublisher that reads all the lines in phone_numbers.txt and then creates and sends an Event <<AllPhoneNumbersListed>> that includes all of the text lines.
PhoneNumberFinder component subscribes to the event above and Filter to search for the text 303. And then creates a new event named <<PhoneNumbersMatched>> placing the few lines of matching lines in the result.
Then the MatchedPhoneNumberCounter subscribing to the above event, whose job is to count the phone numbers in the Event and then forward the results in a new Event.
Finally, PhoneNumber-Executive component receives the event called MatchedPhone-NumbersCounted. Its single responsibility is to log the result, including the count Event property and the date and time it was received, to a file.
Result below:
3 phone numbers matched on July 15, 2012 at 11:15 PM
Final Note: The pipeline offers flexibility. Adding new Filters involves creating Events subscribed to by existing Filters. Adjusting the pipeline’s order requires configuration changes. While not as straightforward as command-line adjustments, such alterations are infrequent in Domain Event pipelines.
In a real enterprise we would use this pattern to break down a large problem into smaller steps that would make distributed processing easier to understand and manage. It would also allow multiple systems to care only for what they do well.
In an actual DDD scenario, Domain Events reflect names meaningful to the business. Each step could create or modify Aggregates in their respective Contexts.
Domain Events explicitly model business process activity occurrences that are useful for domain-wide subscribers to know about, and they pack unique identity and as many knowledge-conveying properties as necessary to clearly get their point across. Yet this synchronous, step-by-step style can be extended to accomplish more than one thing at the same time.
Thanks for reading 👋✌️.
Reference: https://www.amazon.in/Implementing-Domain-Driven-Design-Vaughn-Vernon/dp/0321834577