-1

I am trying to understand how to implement this in Event sourcing model / DDD.

Assume a distributed application in which user submits an application for something, say Job/Loan. So the application raises an UserApplied Event.

There are few micro services like credit service, criminal record service.. they consume this UserApplied event do some validation, responds with CriminalCheckPassed, CreditCheckPassed ... etc. Assume there are 5 checks to be done. In future we might also add more checks like this.

The app consume these events and take some decision. That is - only if they are all validated successfully app can approve the user application by changing the status to UserApproved. Any of the validations failed, them it would be UserDeclined. Something like that.

It sounds simple. But I am banging my head how to implement that correctly?

This is my event store

enter image description here

I have a materialized view

enter image description here

If we have to update the materialized view/aggregate whenever we receive an event, app needs 5 different events to take decision. Till then it will be pending. Even when I receive the 5th event, the materialized view does not know how many events it has received before. I will end up querying entire event-store.

Another approach is - adding these columns in the materialized view. So that we know if we have received all these events. It will work. But looks super ugly.

enter image description here

My question is - how to use the aggregation properly in this case?

RamPrakash
  • 2,218
  • 3
  • 25
  • 54

2 Answers2

0

If I understand correctly, the validation is a part of domain logic (it is something that has to be made sure that it passes). Here, there are some external services like Credit Service and Criminal Record Service.

First, I would model User as an Entity and an Aggregate Root of itself. Then, I will model Job Application as another Entity and another Aggregate Root of itself. Now there are 2 aggregates, with the relationship: User can have many Job Applications.

Now, you need to validate some things before you create a Job Application instance. This validation requires some knowledge from other services. This can be solved by creating a domain service, say JobApplicationCreationService which sole responsibility is to create new instance of Job Application. Then, you would want to inject those external services here. Inside the service, do the validation using the services you injected, then if all validations pass, return a new Job Application instance. This Aggregate instance will have fulfilled your validation rules/domain logic.

Events here is not suitable for validation, rather it is used to synchronize states between Aggregates using eventual consistency. When Events are published and being processed, you want to make sure that the Aggregate that produces the events is already in a consistent state (in this case, the Job Application aggregate).

Here is my personal rule of thumb: Try to create an Aggregate from static factory method to contain the creation logic. If the creation requires something outside of the boundary of the Aggregate itself, refactor it to a Domain Service.

  • I really appreciate your answer. Unfortunately does not answer my question. I also updated my question for better clarity. – RamPrakash Dec 17 '20 at 19:30
0

Well, if CriminalCheckPassed are domain events, then they need to somehow mutate the domains state, so you need to store it within your domain (which will be restored when you load your domain entity), say a private readonly List<RequiredCheck> RequiredChecks and check these on recieving of any of the responsible events, then decide.

If it's not a domain event and is not persisted with the aggregate root, then have a process manager (aka Saga) (i.e. UserApprovalProcessmaanger) collect these external events and process/persist them and once all of them are collected fire off an UserApproved / UserDeclined event which is processed by the domain model/aggregate root

Tseng
  • 61,549
  • 15
  • 193
  • 205
  • Thanks. My question is more of saga related now. When you say persist them - outside the event store rt? - because my original question is around that. – RamPrakash Dec 18 '20 at 14:55
  • Well yea. This approach won't save the `XxxCheckPassed` won't be saved on the `User` aggregate anymore. From your question, it seems that no of the `XxxCheckPassed` event's is changing the `User`'s state, otherwise you would be able to access then without scanning the events. As for sagas/process managers, a process manager is any long running process, which is exactly what your external checks may be. They may complete in a couple of seconds, hours or even days or weeks and the process can only continue then – Tseng Dec 19 '20 at 01:36