Orchestration vs Choreography
- Whenever you want to execute a sequence of actions then you can pipe them through:
- choreography: Each and every action knows who is the next in the calling chain
- Or in other words, they know how to interact with each other
- orchestration: There is a an orchestrator which chains the actions after each other
- Or in other words, they don't know how to interact with each other
- You have chosen the choreography which made your program harder to understand IMHO
- None of your methods return anything rather they are calling each other
- As a reviewer/maintainer it is harder to create a mental model
- If you would compose your actions as an orchestration
- then it would be much easier to follow the data and execution flows
- Here is a (pseudo) example
async Task ExecuteCoreAsync(CancellationToken token) { var purchaseRequests = await GetPurchaseRequests(token); var accessToken = await RetrieveAccessToken(token); var purchaseIds = await ProcessPurchaseRequests(accessToken, purchaseRequests, token); await UpdateStatusOfPurchaseRequests(purchaseIds, token); }
- The above code sequentially executes each actions
- But from this mental model it is much easier to create a pipeline
Problem domain decomposition
- We can see that you have tried to split up the problem domain into smaller chunks
- My problem here is that they are not on the same level of granularity
- Compare
MakeRequestsToRemoteService and UpdateData
MakeRequestsToRemoteService has multiple responsibilities - Retrieving access token
- Issuing requests against downstream system
- Calling update on database records
- If you would try to aim for smaller composable chunks
- then it is much easier to create actions with single responsibility
- BTW: based on the shared code fragment it seems like it is unnecessary to retrieve access token whenever you start to process a purchase request
- IMHO it would be enough to retrieve only once
Distributed transaction
- According to my understanding your code is the glue between two subsystems (a database and a service) >> distributed
- I assume that you want to guarantee that either you can update records in both systems or in none of them >> transaction
- Let's suppose that for some reason your last action the
UpdateData fails for a given purchase - That would mean the database is not updated but the other subsystem did
- Based on the purchase domain I assume that this inconsistency can cause problems
- You could for example do a compensation action against the service to undo/rollback the change to heal the consistency across multiple subsystems
- I would suggest read about SAGA pattern or Two/Three Phase Commits