Users do not always do things exactly as they should. They often make mistakes. This implies that we always first check whether they have requested "correctly" and then proceed with it. The correctness check, or validations as we call them, are following types.
Quite often data invariance checks are incorrectly performed during domain validation, as the race condition is over-looked during development. Lets take the example of verifying whether a user with same email-address exists in the system.
class RegistrationService {
UserRepository userRepository
public User register(NewUserRequest newUserRequest) {
User user = mapToUser(newUserRequest)
if (userRepository.findByEmail(user.emailId()) != null) {
throw new UserAlreadyExistsException()
}
return userRepository.save(user)
}
}
If two threads (caused by user requests), try to request for same emailId then it is possible that findByEmail might return null for both of them we would two users with same email address. Such validation can be implemented by putting a unique constraint in the database and handling the exception in code.
class RegistrationService {
public User register(NewUserRequest newUserRequest) {
try {
User user = mapToUser(newUserRequest)
return userRepository.save(user)
catch (SQLException sqlException) {
if (sqlExceptionCausedByUniqueConstraint("UC_USER_EMAILID"))
throw new UserAlreadyExistsException()
throw
}
}
}
In distributed database one might need to do more than this but the what still holds true is that such checks userRepository.findByEmail(user.emailId()) != null are not very useful. Infact as code review of domain validation one should always keep an eye for data invariance checks.