Creating new Aggregates in DDD

A few weeks ago, we had a question at work: is it OK to create new Aggregates and modify existing ones in a single transaction? We’re using DDD principles for modelling and one of the rules of thumb regarding Aggregates is that you should not modify two aggregates in a single transaction. In our use case, we needed to create a new Aggregate instance from existing one and also possibly modify the source Aggregate. We had to make a choice if this should be done in a single transaction, or using eventual consistency. The former was not even possible in our current architecture, due to explicit API restrictions that we had (you could only store a single Aggregate per transaction). The latter would require some new mechanism to asynchronously process domain events and create a new Aggregate separately from modifying the old one, which would increase complexity of the solution and we did not even need it before. I’ll try to explain how we made the choice here.

Creating a new Aggregate instance

Udi Dahan has written a blog post that explains why Aggregates should not just appear out of nowhere: http://udidahan.com/2009/06/29/dont-create-aggregate-roots/
To summarize, you shouldn’t create Aggregates by just calling the “new” operator, but instead use another Aggregate to create the new one. This can be implemented using Factory Method pattern on an Aggregate Root, as shown in Vaughn Vernon’s book “Implementing Domain-Driven Design”.

Let’s take e-commerce as an example: an anonymous customer can place a single order. The order is created from shopping cart contents and that can be done only once. Using the Aggregate Factory method pattern, this could look something like this:

public class Order: AggregateRoot {
    public Order(ShoppingCartItem[] contents) {
        // initialize the order lines
    }
}

public class ShoppingCart: AggregateRoot {
    public Order CreateOrder() {
        if(this.IsOrderCreated)
             throw new InvalidOperationException("An order has already been created for this shopping cart");

        var newOrder = new Order(this.contents);
        this.IsOrderCreated = true;
        return newOrder;
    }
}

In the code, a new Order Aggregate is created from the ShoppingCard Aggregate and the latter also remembers that it already has been used, so it cannot be used to create any more orders to avoid duplication. As you see, we have a situation where we need to save two Aggregates now in a single transaction.

Saving the new Aggregate instance

I mentioned that we did not have a way to save two Aggregates in a single transaction. Basically, there was a Repository.Save(AggregateRoot aggregateRoot) method, that only accepts a single Aggregate and atomically saves it to the database. There are two cases that can happen when creating a new Aggregate using Aggregate Factory Method:

1) The source Aggregate is not modified – you only need to save the new Aggregate instance
2) The source Aggregate is modified and must be saved together with the created Aggregate instance

In the first case, there is no problem, because you’re only saving/modifying a single Aggregate, just as the rule says. The second case is a bit more interesting, since saving two Aggregates basically means that you’re modifying two Aggregates in the same transaction.

You could say that there is a third case that involves the first case with a race condition added: the source Aggregate is changed in one transaction, while a new Aggregate is created at the same time in another without modifying the source. To solve this race condition, the easiest way is to actually modify the source Aggregate somehow that would increase it’s version number and fail the concurrency check on saving it. So I think this would fall into the same category as the second case I’ve defined above.

Eventual consistency might seem like a solution for this. A domain event would be raised in one transaction and it’s handler would create a new Aggregate instance in another transaction:

public class ShoppingCart: AggregateRoot {
    public void MarkAsUsed() {
        if(this.IsUsed)
             throw new InvalidOperationException("An order has already been created for this shopping cart");
        this.IsUsed = true;
        DomainEvents.Raise(new ShoppingCardMarkedAsUsed(this.Id));
    }
}

public class ShoppingCardMarkedAsUsedHandler: IHandle<ShoppingCardMarkedAsUsed> {
    public Handle(ShoppingCardMarkedAsUsed @event) {
        // this is done in another transaction
        var shoppingCart = repository.Get<ShoppingCart>(@event.ShoppingCartId);
        var newOrder = new Order(shoppingCart.Contents);
        repository.Save(newOrder);
    }
}

Apart from additional complexity in implementing this (this needs to be done asynchronously, ensuring that the event will not be lost even after a process crash) this has an impact on the domain language and encapsulation as well. We introduce a term like “used shopping cart” and also must expose the contents of the shopping cart publicly. This might not be very natural. So, let’s consider if we can just safely ignore the rule this single time and do it the simple way of saving multiple Aggregates at once.

The reason why modifying multiple Aggregates in a single transaction is discouraged is because this increases the possibility of a concurrency issue. The more Aggregates that you touch, the more likely someone is going to touch the on of those same Aggregates. In that case, one of the transactions will fail with a concurrency error or, depending on your concurrency handling strategy, the last transaction will overwrite the first transaction’s changes.

What concurrency issues might we have when creating new Aggregate instances? If the source aggregate is not modified in any way, I’d say that there just are no issues. Multiple transactions will create new, separate instances, so there is no conflict here. However, if the source Aggregate is modified, we’ll have a version conflict (again, it depends on your concurrency handling strategy, but versioning is pretty common and good way). Notice, though, that the version conflict probability does not really increase because you’re creating new Aggregates. It is exactly the same as with modifying any other state in the source Aggregate. Based on this, we can say that, even though we’re saving multiple Aggregates state in a single transaction, we’re not really running into problems that the rule of modifying multiple Aggregates tries to prevent.

Conclusions

To summarize, I think there should be no problems in creating new Aggregates in the same transaction as modifying an existing one. We went and changed our code to allow saving multiple Aggregates at once. Of course, we’ll keep an eye on the usage of this method during code reviews, to ensure no one’s abusing it.

The “modify one Aggregate per transaction” rule is just a guideline that should be followed most of the time, but I would consider the case I’ve described an exception. As always, if we understand why we’re violating the rules, I don’t see why we can’t. That isn’t to say that the rule is wrong in any way. As they say, an exception just proves the rule 🙂

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s