We are trying the Domain Driven Development (DDD) while working on a project.
We've got a Product aggregate.
We've got a ProductRepository to load/save Products.
We've also got a Timeline aggregate, that contains TimeLineItems. And there's a TimelineRepository.
When a product is created/changed, we have to add a TimeLineItem to the Timeline aggregate, like a logbook that logs the changes.
The total process of creating a Product and saving a TimeLineItem to the timeline, could be considered as one transaction (am I right?).
Because, the whole transaction should either succeed entirely, or fail entirely. We don't want to have a product in the database but no timeline item saying it was created and vice versa.
In DDD, an aggregate root has its repository. There's ProductRepository and TimelineRepository. We have to interact with both to finish our task.
I don't want to confuse the concept of transactions in DDD with a transaction in database terms. By this I mean when we're using Laravel, we do something like:
try {
DB::beginTransaction();
// Do something
DB::commit();
} catch(...) {
DB::rollBack();
}
When we're in a repository and we have to work with multiple database rows or tables, we can wrap that in a transaction like that piece of code. Because its packed together in the same class or even the same function. The world outside of the repository doesn't have to know and it's specific to the storage technology (in this case a database).
But when we have to interact with two different repositories, we cannot "share" that transaction.
Because the repositories can both use a different storage technology. Say that the
ProductRepositoryuses a database and theTimeLinerepository a file or some kind of cloud service. When the transaction (DB::...) fails, it has effect on the database, but does not rollback anything in a file or cloud service. We have to implement that mechanism ourselves.If both repositories use the exact same storage (like both one and the same MySQL database), we still are not allowed to do something like:
.
try {
DB::beginTransaction();
$productRepo->save($product);
$timelineRepo->save($timeline);
DB::commit();
} catch(...) {
DB::rollBack();
}
How do we solve this problem?