DDD – Special scenarios, part 2

In my last post I discussed possible solutions for two specific problems when using DDD. In this post I want to analyze more

Collaboration of aggregates

Aggregates in DDD are very self centric or self focused. An aggregate does not care where it comes from and where it goes nor does it care about its environment. But sometimes our application needs functionality that requires two or more instances of aggregates to collaborate. In our world of personal loans that I have used in the preceding posts this could be a customer aggregate and a loan application aggregate. If we want to keep track about how many applications a specific customer has started and/or how many loans have been granted to this customer we need some kind of collaboration between said two types of aggregates.

public class CustomerApplicationService
{
  IIdGenerator _idGenerator;
  IRepository _repository;
  ICustomerLocator _customerLocator;
  
  public CustomerApplicationService(IRepository repository, ICustomerLocator customerLocator, IIdGenerator idGenerator)
  {
    _idGenerator = idGenerator;
    _repository = repository;
    _customerLocator = customerLocator;
  }
  
  public void When(StartNewLoanApplication cmd)
  {
    var applicationId = _idGenerator.Create<LoanApplicationAggregate>();
    var customerId = _customerLocator.GetByEmail(cmd.EmailAddress);
    var customer = _repository.GetById<CustomerAggregate>(customerId);
    var loanApplication = customer.StartNewApplication(applicationId, cmd.EmailAddress);
    _repository.Save(customer);
    _repository.Save(loanApplication);
  }
}

In the above snippet a service IIdGenerator is used to generate a new ID for the loan application aggregate to be created and a serviceĀ ICustomerLocator is used to locate a customer having the given email address and return its ID. This ID is then used to re-hydrate the customer aggregate using the repository. Then we call the StartNewApplication method of the customer aggregate which will return a new instance of a loan application aggregate. Finally the (modified) customer and loan application aggregates are persisted using the repository.

The respective (simplified) code in the customer aggregate might look like this

public class CustomerAggregate
{
  private CustomerState _state;
  
  public LoanApplicationAggregate StartNewApplication(Guid applicationId, string emailAddress)
  {
    var app = new LoanApplicationAggregate();
    app.StartNew(applicationId, emailAddress);
    // keep track of the applications this customer has
    _state.Applications.Add(applicationId);
    return app;
  }
}

As we can see each aggregate remains pretty much self centered and really doesn’t care about its environment and the whereabouts. The application service is responsible for the orchestration of multiple aggregate instances.

Generic vs specific commands

One of the most problematic things that I regularly stumble across is the fact that developers are using very generic commands. When we are used to a CRUD based approach where we have insert, update and delete commands and all of a sudden want to write an application that uses DDD we might be tempted to continue using these or similar types of commands. But the reason why we want to used DDD in the first place is the fact that the application is complex and involves some rather involved business logic and processes. In such scenarios we need to make sure that we keep the complexity of the domain under control. One important way to do so is to make our commands explicit and specific.

To give a concrete sample let’s assume we have the following command

public class UpdateLoanApplication
{
  public Guid ApplicationId {get;set;}
  public ApplicationStatus Status {get;set;}
  public string EmailAddress {get;set;}
  public string FirstName {get;set;}
  public string LastName {get;set;}
  public string StreetAddress {get;set;}
  public string City {get;set;}
  ...
  public decimal? LoanAmountRequested {get;set;}
  public decimal? AnnualIncome {get;set;}
  ...
  public Guid? AcceptedOfferId {get;set;}
  ...
}

which is used to update certain properties of an existing loan application. Easy enough you might think. No! Why not? This seemingly harmless command leaves a lot of questions unanswered and the back-end code that handles this command has to do a lot of guess work. What was the intent of the user when this command was triggered? What exactly changed. Did every property change or only a single one. What edge cases do we have to consider, etc. The validation logic and the business logic become extremely complex over time the more properties this very generic command includes.

It is much much better to have very precise and intention revealing commands that are focusing on an explicit scenario that is limited in scope like

public class StartLoanApplication
{
  public string EmailAddress {get;set}
}

or

public class SetPersonalInfo
{
  public Guid ApplicationId {get;set;}
  public string FirstName {get;set}
  public string LastName {get;set}
  public string StreetAddress {get;set}
  public string City {get;set}
  ...
}

or

public class AcceptOffer
{
  public Guid ApplicationId {get;set;}
  public Guid OfferId {get;set;}
}

or

public class WithdrawApplication
{
  public Guid ApplicationId {get;set}
}

technically we could have used the one generic update command to use in all four scenarios and thus avoid to have many different command classes. But the drawbacks of this approach by far outweighs the advantage.

Specifically note how some of the properties of the generic update command need to have their type defined as nullable since we do not always have a value for all of the properties depending on the scenario where we use the command. Contrary to that every single property of a specific command is required. It is strictly part of the delta that is going to change. Thus we don’t need any special validation like “if this property is there then that property should not be defined…”, to give just one sample.

Also note that we have the property Status in the update command. That is we expect the UI layer to provide us this information thus burdening the UI with unnecessary responsibilities. With specific commands we never need to include the status of the entity since the command is explicit in its context and intent.

Summary

In this post I have discussed two more scenarios that might not be straight forward but when done wrong can make our lives cumbersome. In the first scenario I have shown how we can orchestrate the collaboration of multiple aggregate instances of the same or different types. In the second sample I have discussed the pros and cons of generic versus specific commands.

About Gabriel Schenker

Gabriel N. Schenker started his career as a physicist. Following his passion and interest in stars and the universe he chose to write his Ph.D. thesis in astrophysics. Soon after this he dedicated all his time to his second passion, writing and architecting software. Gabriel has since been working for over 25 years as a consultant, software architect, trainer, and mentor mainly on the .NET platform. He is currently working as senior software architect at Alien Vault in Austin, Texas. Gabriel is passionate about software development and tries to make the life of developers easier by providing guidelines and frameworks to reduce friction in the software development process. Gabriel is married and father of four children and during his spare time likes hiking in the mountains, cooking and reading.
This entry was posted in architecture, DDD, design, How To, practices. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Pingback: The Morning Brew - Chris Alcock » The Morning Brew #1858()

  • Andrey Tamelo

    Gabriel, thanks for yet another useful article!

    I’m just wondering what is the purpose of having the cutomerLocator? Why can’t we go directly to the customerRepository?

    • gabrielschenker

      Goal is to use CQRS and thus keep read and write concerns separated. The repository is strictly part of the write side and as such cannot be used to query the data store other than by ID to re-hydrate an aggregate instance. The customer locator on the other hand is a query service and is used to try to locate a customer using other filters than the ID (e.g. email address in this simplified sample – in reality it is a match of several attributes like first and last name, email, state, zip code, etc.). The locator can use other data stores e.g. ElasticSearch to do the query…

  • gilligan_MH

    I like this blog post series, it matches up with my own experiences, and I do hope that our industry matured enough in DDD understanding these past few years to utilize your knowledge wisely

  • Chris Dunn

    Hi Gabriel,

    Interesting read. Your post on Generic vs specific commands is spot on.

    Based on my understanding, having a single transaction spans multiple Aggregate Roots may not be the best approach.

    According to Vaughn Vernon in his book “implementing Domain Driven Design” he writes:

    “A properly designed Bounded Context modifies only one Aggregate instance per transaction in all cases…. Limiting modification to one Aggregate instance per transaction may sound overly strict. However, it is a rule of thumb and should be the goal in most cases. it addressed the very reason to use Aggregates”. Page 354.

    An Aggregate is a consistency boundary and is responsible for enforcing the consistency of it’s invariants, hence why modifying the state of an Aggregate is limited to a single transaction.

    If the Customer and LoanApplication Aggregate need to be transactionally consistent together then this suggests to me that the domain model isn’t quite right and requires deeper insight.

    If they are not required to be transactionally consistent then I would suggest separating the transactions using Domain Events. The StartNewLoanApplication command modifies the CustomerAggregate which then raises the DomainEvent ‘NewLoadApplicationStarted’ which is then handled and the LoanApplicationAggregate is then modified and saved….or something along those lines, hopefully you get the idea.

    • gabrielschenker

      Very good observation! I totally agree with you that in general only one single aggregate should be modified by one command. When I use event sourcing in conjunction with DDD then this is “easily” achievable. But in this particular case I have a stateful system backed by an RDBMS and there the “easiest” way to achieve the goal I have is to use a transaction which encompasses the two aggregate instances. There certainly exist better designs (e.g. the one that you suggest) but it is a compromise (20/80 rule…).

      • Leo E.

        How about this:

        Customer = Aggregate Root.
        LoanApplication = Entity in the same aggregate.

        • Chris Dunn

          The act of starting a new load application could be argued as a ‘long running process’ so you’d want to use a ‘saga’ which could be represented as the Aggregate ‘CustomerLoanApplication’. Best of both worlds!

          • Leo E.

            Being a big fan of process managers myself, +100.

  • Matt Bailey

    Gabriel, I’ve been reading your blog for a few weeks now, it’s good stuff. Do you have any insight on this CQRS design pattern I’ve encountered quite a few times now. I created a gist here (Java syntax, not compile-ready) https://gist.github.com/breeze4/7361db0d92ecbccf7769

    The pattern is this: say you have a command (or event) that can have several enumerated options. Do you have a command for each possible enumeration with a shared abstract type, along with either a single command handler for an abstract type, or do you have a single command that has the enum object on it that the command handler now has to use? Or some mixed approach?

    My thinking has changed a few times on it and I’ve tried many different approaches while trying to find the right balance. Right now, I’m leaning towards expressive names (more command and event class files) along using abstract types to let the event handlers choose what level of specificity they need on that particular set of events.

    There is a definite trade-off between DRY and class name having intent. The generic style takes less code, but now the name has to be coupled with another piece of data to have meaning. The specific style uses way more boilerplate, but it’s very easy to glance at command and event names and get a clear grasp on what the flow of actions by the user was. That much information could be conveyed by the command/event data, but there is a lot of power in expressive names.

    I’d love to hear your thoughts on this pattern. Sorry if you’ve already written about it.

  • Thank you for this very interesting post. I’m currently migrating the command side (= POST in controllers) of our application to a DDD approach and I’m doing it without too much problems thanks to your series of articles.

    However I still have problems understanding which approach I should take for the reading side (= GET in controllers) of our application. When I need to display informations in a page, I query the database, shape the data and pass it to the view. My problem is that sometimes I have a bit of logic to implement in a GET before fetching the data. For example, I have a product page that is accessible only to restricted users and only if the product is in a specific status, moreover I have to query a third party with the user data before displaying the page. Where should be implemented all this logic? I’m tempted to put this logic in an application service that will check all conditions. I would then use the result from this service to either fetch the data to display the page or redirect to another page. Could you please give some insights on how you would handle such cases?

    • gabrielschenker

      If you are using an (eventual consistent) read model then ideally the read model is pre-calculated/preshaped into a form that is cheap and fast to query. It is a fact for most LOB applications that writing/changing of data happens much less frequently than reading and thus we should trigger the update of the read model when the underlying data changes. If this pre-shaping or -calculation is not possible then I would define some provider or data-aggregator service that collects the data from the various (external and internal) sources and merges them into the shape I need on the client. I would never put this logic into the API controllers directly. The only responsibility of a controllers is to route a request to the correct service provider.

    • Enrico Buonanno

      The part about authorization should be done elsewhere (in .NET, using attributes/interceptors; in node, using express middleware or similar).
      The validation can be done in a service; the data aggregation, Gabriel already addressed.

  • Enrico Buonanno

    I understand the UpdateLoanApplicationCommand is not DDD, but what to do in the case of an application generally designed following DDD, but in which some functionality is simply CRUD?

    For example, imagine you have a whole section of the Loan app that manages reference data (say, Lenders, or LegalEntities), and a UI that allows you to edit all or most fields of a LegalEntity. How do you get away from the LegalEntityUpdated blob in that case?

    You would have to change the UI and only allow your user to submit a smaller, more specific set of changes at the time, correct? and even then, some guesswork would still be needed to see which fields have changed…

    • Paul Taylor

      Hey. I know this is a very late reply to your query, and I don’t know if this is the right/a good answer, but I will put it here for others to comment on.

      My feeling would be to break your editing up into smaller chunks, along the lines of a Task Based UI. I may be teaching you to suck eggs here (this is all new to me) but the reasoning behind a task based UI is that in your typical CRUD application where you display all your LegalEntity fields to the user, the UI doesn’t really lead the user through the experience. In these CRUD based scenarios you typically find that users don’t fully understand the application, and they don’t form a model in their head of the data. They just see loads of input boxes, and wonder “do I need to fill all of these in?” “which ones to I need to edit?”.

      If you relate the UI to real world usage what may the user be expected to do? They will have a task. i.e. Change Lender Name, Relocate Lender Office Address, Change Lender Rate, Apply New Lender Terms. When you see your UI, and your application in these terms, it becomes very easy to design the Task based UI, and you know exactly which fields to present to the user. Also, from the user perspective, it becomes very intuitive as to what to do on the screen. what would be the motive behind an Update screen which shows all fields? Has the user come along to “update a Lender”? What the heck does that mean?

      This form of task based UI is recognisable in mobile apps, and lately some web apps (basecamp, Asana) where you might have UI Tasks on a Asana task entry like Change Milestone, Edit Description, Change Subject etc.

      Does this make sense?