ExampleWe have 'Tags' that can be applied to a 'Post'. When creating a post, we want to only create new tag entities when the tag does not already exists. A race condition can exist when two posts with the same new tag are created at the same time as the check if the tag exists can be false for both posts.
Solutions1) Always create a new tag - we don't really care that we have duplicate tags if we always perform operations on the tagName, not the actual instance of a tag - this in ddd would be a 'Value Object'.
Side effects are; a potential drop in performance, and an increased database size
2) Use Database constraints to mark the field as unique, so the second post will attempt to create the tag and fail.
Side effects are; it is difficult to impose unique constraints in ORM, not all underlying providers (object store for example) will support this, and requires 'retry' logic.
3) Use a Transaction to check the existance of the entry before the insert.
Side effects are; a drop in performance from transactional locking and increased solution complexity.
4) Use a messaging service model for processing each post creation as a separate operation so the race conditions wont exist.
Side effects are; an increase in application complexity due to the asynchronous nature of the queue, and reduced performance due to the overhead (albeit with an increased scalability)
ConclusionsOption 1 in this scenario is entirely valid but this is not always the case, often guaranteed uniqueness is important, so using this as a general solution to race conditions is not appropriate.
Options 2 and 3 are very reiliant on the functionality of the underlying data provider. In most LOB solutions is probably OK, but it is not as flexible and scalable as I would like.
Option 4 seems like a fairly drastic change in application design, but in reality this should not be as large an impact as you would think.