Donald Barre
Donald A. Barre
Event-Driven Architecture
I love events. It's my opinion that events are one of the greatest tools we have to avoid tight coupling. For this discussion, I'm going to return to the Medical Records example I provided in A Word About Cohesion. The billing software for a newly created medical record should be located in the same package. But there was one glaring omission. The software that creates the medical record was modified to invoke the software that does the billing. That is tight coupling. The medical record creation is aware of the billing component and has a dependency on it.
We can use events to remove that coupling. After saving the medical record to the database, the MedicalRecordCreationService can simply publish an event that contains the ID of the newly created medical record. It no longer has any dependency on the billing code. As for the medical record billing code, it doesn't even need to be in the same code base. It could reside in a totally separate microservice that handles billing. It simply handles the event when it arrives asynchronously.
We use lots of different names for the code that receives events: Event Handler, Event Listener, Event Consumer, etc. Regardless of what it is called, I like to think of each Event Handler as being responsible for a separate Use Case. In our example, I see two Use Cases:
  • Create a new medical record
  • Bill hospital for each new medical record
Now let's suppose we are given a new Use Case:
  • Email the hospital administrator for each new medical record
We can see an immediate benefit for this new Use Case: we don't have to modify the code that creates the medical record. We simply add a new Event Handler that is notified when a medical record is published and that Event Handler sends the email to the hospital administrator.
There is a final set of benefits that should be noted. Let's suppose we didn't use events. In that case, our code that created the medical record would have to make a call to send the email and then another call to bill the hospital. Because we don't want long-running transactions, the transaction to save the medical record to the database has already committed before we invoke either of those calls. There are several problems with this solution:
  • Sending the email and billing the hospital are completely independent of each other. We could do them in either order. In fact, we could execute them concurrently.
  • The end user who requested the new medical record has to wait longer. The medical record was created, but end user now has to wait for the email to be sent and for the billing to be completed.
  • In our example, the email is sent first. What would happen if that code threw a runtime exception? Unless the developer codes for it, we are in danger of not billing the hospital even though the medical record was committed to the database.
Events negate each of these issues. Using events, we can send the email and bill the hospital concurrently. Likewise, the user doesn't have to wait longer for a response. And lastly, if email operation fails, it does not and cannot impact the billing.
© Donald A. Barre. All rights reserved.