In a series of blog posts, Mathias Verraes describes patterns in distributed systems that he has encountered in his work and has found helpful. His goal is to identify, name and document patterns together with the context in which they can be useful, and he emphasizes that patterns often become anti-patterns when used in the wrong context.
Verraes, working as a consultant and founder of DDD Europe, currently describes 16 patterns in three areas: patterns for decoupling, general messaging patterns and event sourcing patterns. For each pattern he describes the problem and the solution, sometimes also with example or implementation.
Completeness Guarantee is a decoupling pattern where the goal is to define the set of domain events sent from a producer, where a consumer needs to be able to reproduce the state of the producer. Often, events are created or updated in response to consumers needs, and after a while it can be hard to understand the purpose of each event and if it’s used at all by a consumer. To accomplish a completeness, an event must be published whenever a state changes in the producer, and ideally the event only contains changed attributes, nothing more. This way it becomes clear what each event means and what attributes it carries.
Passage of Time Event is a decoupling pattern aiming at replacing a scheduler that at some rate calls an API in a service with a scheduler that emits generic domain events, like DayHasPassed or MonthHasPassed. Interested services can then listen to these events and internally handle any actions needed. For Verraes this is a very reactive approach. Instead of sending a command and expecting a response, a scheduler can now just emit events about time, without caring about if any listens to them.
Explicit Public Events is a pattern for separating events into private and public events. Often a service, especially when using event sourcing, should not publish all events to the outside world. One reason is that the external API for the service becomes tightly coupled to the internal structure and an internal change may require a change both in the API and in other services. This pattern can be implemented by making all events private by default and specifically mark events that are public. Private and public events can then be published using separate messaging channels.
Segregated Event Layers is a way to separate private and public events even more. By creating adapters that listen to internal events and emits a stream of new public events, internal events become strictly private. Verraes notes that this is an implementation pattern for building an anti-corruption layer where the new event stream in practise becomes a new bounded context with its own event types and names.
One pattern that can be used when there are attributes in an event that only should be visible to some consumers is Forgettable Payloads. Sensitive information in an event is then replaced with an URL pointing to a storage containing the sensitive information; a storage with restricted access. Another similar pattern is Crypto-Shredding where sensitive information is encrypted with a different key for each resource. By deleting the key, the information cannot be accessed anymore.
Decision Tracking is used to store the outcome of decisions when event sourcing is used. If a rule changes, for example limits when it should be applied, and the events are replayed without tracking the rule changes, the outcome may be different. One solution is to store decisions as events together with the events that caused the decision. Verraes notes that this also can be used to mitigate the consequences of a bug, since it’s possible to replay all events and compare the outcome with data from the decision event.
Natural Language Message Names is a pattern recommending that verbs be used in message names to make them more expressive. Using a natural language and embedding it in code and artefacts is a core concept in Domain-Driven Design (DDD). Verraes notes that domain experts don’t use terms like Payment event or Invoice paid; they say the invoice was paid. For events he recommends using names like CustomerWasInvoiced and InvoiceWasPaid. For commands he prefers InvoiceCustomer and FulfilOrder.
Verraes concludes by noting that his series of patterns is a start, and he asks about other patterns and experiences other developers have found or had. His contact information can be found on his website.
Chris Richardson has created a pattern language for microservices, with patterns about deployment, communication styles, data management and other areas.