Leonardo
Leonardo

Reputation: 11401

DDD - Rehydrate aggregate roots?

All my entities are implementation of interfaces. Most of their properties are read-only.
My repository holds a reference to the library project where i hold all the interfaces, so technically speaking, the repository can save the aggregate root without knowing anything about it's de-facto implementation (something i believe to be a +1).
The problem here is: if most of the properties are read-only, how can I rehydrate a aggregate root without breaking OOP principles? should the repository hold a reference to the domain project and be aware of the concrete implementation of interfaces?

Upvotes: 2

Views: 1109

Answers (2)

plalx
plalx

Reputation: 43728

Simply put, something somewhere in your application has to know about concrete implementations. If you really want to shield the repository implementation (not the contract) from knowing the concrete entities then that responsibility will simply have to fall on another collaborator (e.g. repository would delegate the rehydration to an abstract factory).

However, it's quite uncommon to have separate contracts for aggregates because you usually have a single implementation of these business concepts and there's usually no scenario where you would want to mock them in unit tests. Therefore, repository contracts and implementation are most of the time defined in terms of concrete aggregates.

Upvotes: 1

VoiceOfUnreason
VoiceOfUnreason

Reputation: 57367

should the repository hold a reference to the domain project and be aware of the concrete implementation of interfaces?

As Evans describes in the Blue Book; the Repository is a role played by an implementation, to keep the application from mutating the underlying data directly. Similarly, the Aggregate Root is a role -- we don't let the application touch the actual entity, but instead just a limited part of it.

The implementation of the repository is part of the model, so it can know more about the specific entities being represented; including knowing how to extract from them a representation of state that can be handed off to your persistence component for storage.

To choose a specific context, let's pretend that we are modeling a TradeBook, and one of the interesting use cases is that of a customer placing orders. In Java, the implementation of the Repository interface -- the bit that the application knows about, might look like

interface API.TradeBookRepository<TradeBook extends API.TradeBook> {
    TradeBook getById(...);
    void save(TradeBook);
}

interface API.TradeBook {
    void placeOrder(...);
}

So the application knows that it has an access to a repository, but it doesn't know anything about the implementation but the promise that it will provide something that supports placeOrder.

So the application code looks like:

API.TradeBookRepository<? extends API.TradeBook> repo = ....

API.TradeBook book = repo.getById(...);
book.placeOrder(...)
repo.save(book)

But a given repository implementation is usually coupled to a specific implementation of the book; they are paired together.

class LIFO.TradeBook implements API.TradeBook {
    ...
}

class LIFO.TradeBookRepository implements API.TradeBookRepository<LIFO.TradeBook> {
    ...
}

how can I rehydrate a aggregate root without breaking OOP principles?

To some degree, you can't. The good news is, at the boundaries, applications are not object oriented.

The thing you are putting into your durable store isn't an aggregate root; it's some representation of state. I tend to think of it as a Memento. What you really have are two functions - one converts a specific aggregate root implementation (ex: LIFO.TradeBook) to a Memento, the other converts a Memento to an aggregate root.

Key idea: you are probably going to want to change your domain model a lot more often than you are going to want to migrate the database. So the Memento needs to be designed to be stable -- in effect, the Memento is a message sent from the old domain model to the new one, so many of the lessons of message verioning apply.

Upvotes: 3

Related Questions