1

I'm doing a project in PHP and I'm implementing Aggregates and Event Sourcing. In order to avoid coding up all the logic related with ES myself I've decided to use a third party library called EventSauce.

I would want to avoid coupling my code, specially my domain, with an external library. However, from what I have seen in the docs I need to use classes that implement the EventSauce interfaces. I would like to use my own interfaces in order to have control of the possible changes made to the library or if I would like to change to another library in the future. I would illustrate this with an example.

I have a repository with the following interface:

interface ItemRepository
{
    public function itemOfSku(Sku $sku): Item;

    public function nextSku(): Sku;

    public function save(Item $item): void;
}

And the library needs an interface, which is kind of equivalent, like:

interface MessageRepository
{
    public function persist(Message ... $messages);
    public function retrieveAll(AggregateRootId $id): Generator;
}

Other parts of the library depend on this MessageRepository so I am forced to implement this interface. If this restriction doesn't exist it would be much easier.

I would like to know if there is any design pattern that would allow me to decople from the third party interface and not pollute my domain.

  • a repository isnt part of your domain – Ewan Jan 2 at 9:50
  • Thanks @Ewan. The implementation of the repository is not part of the domain but the interface of the repository can be. However that wasn't the important part of the question, it was just the easiest example I could make up. – Juan Abascal Jan 2 at 9:58
  • The implementation of the repository is not part of the domain but the interface of the repository can be Are you perhaps implementing the port-&-adapter architecture? Because basically that's a way to decouple your domain from the "implementation details" imposed by the framework. – Laiv Jan 2 at 11:30
2

It seems to me like the fundamental problem you are getting at is the need to generate the Message objects as you call methods/fields on your Domain objects.

There's not much you can do about this if you want to do Event Sourcing. If you keep the simple ItemRepository, then when you call Save(Item) the underlying event source database has no way to work out the list of things that have happened to the Item between you retrieving it from the repo and putting it back again. Which it need to do to implement any kind of event sourcing.

Of course you don't need to use the library's Message object. You could use your own and then convert that list of events to messages when you call ItemRepository.Save

class ItemRepository
{
    private MessageRepository messageRepo;
    public function save(Item $item): void
    {
        foreach(var i in item.Events)
        {
            messageRepo.Persist(ConvertToMessage(i));
        }
    }
}

I would caution you against attempting to infer the Events by comparing the before and after object as this can miss vital information.

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.