I am part of a team that works on a business critical microservice that captures a Submission from end users. A request submitted by a party flows through a workflow of approvals and at the end creates / generates sides effects in downstream services. There are several downstream services, each managed and deployed as separate applications by their own team.

Challenges

The service I worked on acted as a gatekeeper for data entering into these downstream service. An approval of this request resulted in CRUD operations to be performed on these downstream systems. The Submission in our domain was supposed to be IMMUTABLE. Business requirements, like they do, changed. Business needed overrides to the Submission before approval but at the same time we need to be transparent. We needed the end users to understand what came in, what alternations were made and by whom and how the result was derived from this altered almost immutable request.

engineering bits

ledger of changes

We enforced a rule of keeping the Submission domain entity which encapsulated the request from the end user to be immutable. This guaranteed a source of truth for what the end user had committed to the system.

Alternations to the Submission were recorded separately. The current state of the Submission was then derived by applying EditXXX event on the Submission

entities and events

We setup our system where the domain events were captured as part of an audit trail using MartenDB

Implementation bits

The project uses Mediatr for handling CQRS requests and commands with entity framework at the persistence layer. Instead of applying changes to the Submission model, the CQRS handler would hydrate the domaine entity which would raise appropriate events

We setup an event listener which used MartenDB and stored the events under Submission.Id as the stream context. The projection SubmissionProjection was defined which Applied the events stored for the Submission to give users the current state of the Submission

Projection = Entity + Events

MartenDB allows you to define a live version of the Projection, which helps you avoiding loading all the events applied on an entity to get to the current state of the entity.

learnings

  • transparency helped end users identify and at times correct configuration changes before they were applied
  • the changes helped reduce support tickets and retroactive reversals, which at times could only be performed by technical support tier or worst case developers