Question

I'm in the process of adopting DDD concepts for designing our next projects, and more specifically CQRS.

After reading a LOT of stuff I'm now trying to implement a simple Proof Of Concept.

The thing is I'm stuck right after I started :p

I'm trying to apply this approach to a simple user registration process, where steps are:

  • User fills the registration form & submit the request
  • The app creates the user
  • The app authenticates the user (auto log in)
  • The app sends a verification email to the user
  • The app redirect the user somewhere else with a confirmation message

From an implementation point of view, what I get so far is:

  • The controller action maps the request data to a RegisterCommand object
  • The controller action asks the Command Bus to handle the RegisterCommand
  • The command handler (UserService) "register" method creates a new User object (whether by a new command or a factory object)
  • The model raises a RegisterEvent
  • The command handler asks the repository to store the new user object

That's it, the controller action doesn't know about any of that.

So, my guess is, since everything in this context HAS TO be done synchronously (except for the email sending), I can use a direct/synchronous command bus, and in the controller action, right after the command bus invocation, I can query for a read only User (query database) and if it exists assume that everything went well, so I can give the user a confirmation message.

The automatic log in process being handled by an Event Handler.

Assuming that this is correct, what if something goes wrong, how to inform the user with the correct information ?

A common example is often used in articles we can find over the internet: A customer pays his order by using an expired credit card. The system accepts the request, informs the user that everything is OK, but the user receives an email a few minutes later telling him that his order could not be processed.

Well, this scenario is acceptable in many cases, but for some other it is just not possible. So where are the examples dealing with these use cases ? :p

Thank you !

Was it helpful?

Solution 2

The problem with contrived examples is that you can change your mind about how the "domain" functions, so there's little use in discussing this example in particular. The basic premise you seem to forego is that we must assume that things are just going to work. Everything else is about risk and mitigating it. Taking this example, if I ask you, what if I lost 1 user registration in 100000? What if I lost 1 out of 10? Why would that happen? Do I have bigger problems at that point in time? Would future users be likely to register again when the system comes back online and works as expected? When would that be? What if we monitored our quality of service and prevent users from registering because we can't assure the quality they've come to associate with our brand? What if the server exploded, or the datacenter got nuked? Do we want to protect against that? You see, there is no right answer. Just various shades of grey. So how do we mitigate the risk? We could make things synchronous but that is only a guarantee at that limited point in time. What if I had to restore a backup that's 2 hours old (e.g. because the disk corrupted)? That's 2 hours of registered users lost (maybe). These things happen ... I just wanted to point out the relativity of what I consider a false sense of security. Mitigate it, invest in what you can't afford to lose, make sure you have a good audit trail. Probably not the answer you were looking for ...

OTHER TIPS

I think this registration use case is closer to the paying for an order use case than you think.

Most of the CQRS thought leaders suggest validating on the read side before issuing a command, thus giving your command a higher probability of success.

If the validation fails on the read side, you know how to handle this - make the user pick another name before you even send off the registration command. If validation succeeds, send the command - now you're talking probably a few hundred microseconds AT MOST where another user could've come in and taken the same username between the time you validated the command and sent it off. Highly unlikely.

And in the very rare case when that does happen, you act in the same as way as the expired credit card example - the next time the user logs in, you present them with an explanation and a form to submit a new username - or send them an email saying "hey - someone else has that username, please click here to select a new one". Why does this work? Because you have a unique ID for that user.

Look at a user registration page like Twitter. As soon as you enter a username, it does a little Ajax call and says "nope, this is taken" or "this one is good!" That's pre-validation.

I hope this helps!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top