3

I am looking at a scenario for creating an aggregate instance from a trigger an a different aggregate.

I've incorporated some logic in my DDD and Event Sourcing with Onion architecture learning scenario around User Registration and creation of a User Account.

Currently I have a simple Registration class instance which has a number of attributes around Email Address and Name. This currently has a single method named Activate.

When the Registration is activated, an Account should be created.

Internally, I am recording events on the various actions.

public partial class NewRegistration : EventSourcedAggregate
{
    internal NewRegistration(
        string organisationName, 
        AccountContact contact)
    {
        OrganisationName = organisationName ?? throw new ArgumentNullException(nameof(organisationName));
        Contact = contact ?? throw new ArgumentNullException(nameof(contact));
        RequestedDate = SystemClock.Current.GetCurrentUtcDateTime();

        Apply(new RegistrationCreated(
            OrganisationName, 
            Contact.EmailAddress.ToString(), 
            Contact.Name.GivenName,
            Contact.Name.FamilyName,
            RequestedDate));
    }

     NewRegistration(Guid id, int version)
        : base(id, version)
    {

    }

    public string OrganisationName { get; private set; }

    public AccountContact Contact { get; private set; }

    public string ActivationCode { get; private set; }

    public DateTime RequestedDate { get; private set; }

    public DateTime? ActivatedDate { get; private set; }

    public void ChangeActivationCode(string activationCode)
    {
        if (ActivatedDate.HasValue) throw new InvalidOperationException("The registration has already been activated");

        if (activationCode != ActivationCode)
        {
            Apply(new ActivationCodeChanged(activationCode));
        }
    }

    public void Activate()
    {
        Apply(new RegistrationActivatedEvent(SystemClock.Current.GetCurrentUtcDateTime()));
    }

    protected sealed override void Apply(DomainEvent changes)
    {
        When((dynamic)changes);
    }

    private void When(ActivationCodeChanged activationCodeChanged)
    {
        ActivationCode = activationCodeChanged.ActivationCode;
    }

    private void When(RegistrationActivatedEvent registrationActivatedEvent)
    {
        ActivatedDate = registrationActivatedEvent.ActivationDate;
    }
}

Although the above is stored in a SQL table, it does not fully realise Event Sourcing - as it will only ever have a single record that will only get updated should the user reset the activation code.

So when Registration is activated, I need to created a new instance of Account. I currently see Registration and Account as part of the Customers bounded context. I feel Registration and Accounts are two separate domains/sub-domains within the context - I might be wrong! I was also feeling the account could be an Event sourced aggregate, although reading Udi Dahans blog post on when not to use CQRS I feel a little disappointed with what I was planning.

Now there are a number of ways to implement this. My first thought was to simply handle this in an Application Service. Typically I would put that logic here as they coordinate things. This would require the INewRegistrationRepository and IAccountRepository injected - to copy the information from one to the other.

We've been using a lot of application services at work and I have become bogged down in the number we have due to the way our business logic is (static managers, helpers, infrastructure mixed in with anaemic domain model.

But having been reading a little on Process Managers and Sagas, I which has confused me somewhat and halted my thoughts for the day.

I am all for keeping things simple, and this is a simple part of a domain implementation I am looking at. I feel a bit overcome with Application Services - is the domain Process Manager or Saga a better fit for this scenario.

How do DDD practitioners on here look at implementing such a scenario?

2

In fact, your RegistrationActived event is actually the same with AccountCreated. I would recommend to justify whether you need Registration model. The criteria is whether it's part of the ubiquitous language of your domain.

Regarding your first attempt,

My first thought was to simply handle this in an Application Service. Typically I would put that logic here as they coordinate things. This would require the INewRegistrationRepository and IAccountRepository injected - to copy the information from one to the other.

I would not encourage this approach. By this way, your application services is very easy to get blown-up. Usually, we should always try to keep the application service as simple as possible.

Moreover, you're mentioning

"I feel Registration and Customers are two separate domains/sub-domains within the context"

, this is another evidence that we should not put them together. I would suggest using Eventual Consistency to address such scenario. Technically, people usually use a domain service to publish an event(RegistrationActived in your case) from one domain, then subscribe in another domain (Account or Customer domain in your case).

  • Nice answer. I have edited the question about the "I feel Registration and Customers ...". This should have been Registration and Account. It might make sense to marry the two into a single Account, but there is the scenario where people could sign up and not bother completing the activation - which could be via bot attacks etc if using a web front end. – Andez Feb 4 '18 at 13:06
1

You could use an Domain Service RegistrationService which on activate registration command does 2 things:

 1. RegistrationAggregate.activeRegistration
 2. AccountAggregateService.createAccount

But in case of server crash, etc it could happen that registration was activated but account was not created. Consistency will not be ensured

This behavior is not desirable in your use case. You would want account to be created for every registration activation.

Hence you would need to write this coordination logic using jobs/Process Managers.

A sample solution using process managers and eventual consistency would be like this :

RegistrationAggregate publishes RegistrationActivated event.

A Process Manager CreateAccountProcessManager in Accounts domain listens to the event and issues a command to AccountAggregateService to createAccount. Here AccountAggregateService is a thin domain service layer which interacts with AccountAggregate.

CreateAccountProcessManager{

Handle(RegistrationActivatedEvent message){

AccountAggregateService.createAccount(AccountInfo accountInfo);

}

}

Since your RegistrationActivated event will be persisted and will be marked as consumed only on successful account creation, consistency will always be ensured.

Another approach to the implementation of process manager without eventual consistency would be like this:

A process manager is created on activate registration command which does the following:

1. RegistrationAggregateService.activeRegistration
2. AccountAggregateService.createAccount

This approach is called pure orchestration.

You can choose any implementation which suits your use case and business invariant the best. Each approach comes with pros and cons. This is a nice article on the approaches and their pros and cons.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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