1

I'm working on a HR application that has employee management and access control.
We decided to go with these bounded contexts:

  • Employee management: manage employees information, like name, contract, birthdate etc
  • Access control: manage whether an employee can get into the facility, in which case we upload his or her fingerprint to fingerprint scanners. (fingerprint should be uploaded beforehand)
  • Presence and absence: calendar (hours of work of each employee), based on information from timecloks, we get to calculate presence, absence, how many times employee got into the facility etc.

the boundaries between these bounded contexts are clear and easily seen by the specific language of each of these contexts.
The problem at hand is, we have a UI page that holds employee information, this same page contains both information related to employee management and also information related to access control (example: identifier of this employee in the fingerprint scanners which is an integer).

When the user edits all this data, he saves it at once with save button, this is supposed to be single transaction (the save), but it involves two savings of two aggregates in two bounded contexts.
Currently, aggregates across all these bounded contexts are saved in one database but we like to keep the possibility of making them in separate schemas in the future.

How to handle this situation to insure that if saving in one database wasn't done properly for some reason, than the saving in the other database is not going to be saved as well.

Also I thought about changing the way we do our UI, but this situation is almost frequent where one UI can hold information of multiple contexts, and saving info on that page will include updates on those contexts as well at once.

Any suggestions will be much appreciated.

1
  • Saga Pattern is usually how to handle this issue. Simply said, it is a manually implement transaction that rollbacks changes if one of the parts fails. Yes, it is additinal complexity, but that is price for domain separation.
    – Euphoric
    Commented Jan 9, 2023 at 19:56

2 Answers 2

1

How to handle this situation to insure that if saving in one database wasn't done properly for some reason, than the saving in the other database is not going to be saved as well.

I would recommend against artificially putting this into one transaction if there is no business reason for it. Since these are different bounded contexts, there will most likely nothing really "bad" happen when savings to one of the contexts will succeed and another one will fail. Just think of your UI as a binding bracket over three invidual UIs with individual Save buttons.

Of course, the Save operation inside your UI should

  • iterate over all the three partial Saves

  • collect failure state and failure messages for each individual step,

  • tell the user precisely which of the steps succeeded and which failed.

If it makes sense to stop further savings when one of the previous saves failed depends heavily on the case, but usually there should be no need to undo a successful partial save.

There are some options you can consider to make this more user-friendly:

  • You may visualize which parameters / attributes are already saved in the DB and which are pending. Depending on the application and how it is used, this may be negligible, or crucial, or only convenient.

  • You may run a validation of the data inside the UI before you try to save it, and force the user to correct anything which would let the save operation fail. This does not give a 100% chance against failure during the real save operation, but it can sort out most domain reasons, leaving only technical failures or failures by unexpected concurrent access.

Finally, if you really need to implement a transaction over multiple bounded contexts, which may be persisted within different storage systems, look into techniques like Two-phase commit or the Saga pattern. Here is also a Stackoverflow Q&A comparing the two.

2

I mean it doesn't sound overly critical, I would just allow the UI to show the partial failure.

However, the way to do it is to allow undo's of the various actions. This means you need to store a history of each object, perhaps use the Event Store pattern?

You can then add the various updates in a "Pending" way and then send a "Complete" message to mark them and finished if everything worked.

Obviously you have "what if the transaction completion fails for some contexts!" problems, which you can solve with a clean up job running on a schedule to roll back bad changes delete old "pending" updates etc

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.