3

1) In most cases each Aggregate Root should define its own transactional boundary, in which case we don't need to expose IUnitOfWork interface in Domain Layer.

a) I assume in this situation a good option would be for a repository ( used by aggregate to enforce invariants applied within it ) to contain its very own instance of UoW ( if using EF, then this UoW instance could simply be of type DbContext )?

2)

a) But if for whatever reason transaction spans several aggregates ( thus more than one aggregate needs to be changed at one time ), then won't Domain Layer also need to contain IUnitOfWork interface?

b) Won't exposing IUnitOfWork interface in Domain Layer violate persistence ignorance rule?

c) If yes to b), doesn't then exposing IUnitOfWork defeat the purpose of having repositories?

Replying to Alexey Raga:

1) I would advice against exposing repositories to aggregates. Repositories are there to give you aggregates, that's it.

a) Though I assume that majority of ddd architects don't have a problem with exposing repos to aggregates ( I'm only asking because I read several articles on repos and DDD and the impression I got is that authors ain't against exposing repos to aggregates - but now I'm not so sure anymore )?

b) So you're also against exposing repositories to domain services?

c) Judging by your answer I'm guessing that you consider exposing IUnitOfWork as a violation of PI?

2)Note that although my command handler (app service in a way)...

Do you normally implement command handlers as app services?

3)

public void Handle(ApproveOrderCommand command)
{
    var order = Repository.Get(command.OrderId);
    property.Approve(command.Comment, ServiceRequiredForOrderApproval);
    Repository.Save(order);
}

Is property.Approve(...) a typo and you actually meant order.Approve(...)?

Thanx in advance

bckpwrld
  • 1,159
  • 1
  • 11
  • 23
  • 1
    Having the IUnitOfWork interface as part of your domain isn't necessarily a bad thing, just as having your repository interfaces part of your domain isn't a bad thing either. As long as they held distinctly separate from your implementation. – stephenl Dec 16 '13 at 22:10
  • @stephenl: The point of repository is to abstract away the persistence. But isn't IUnitOfWork interface itself a persistence detail and as such by introducing it in a Domain layer, we leaked persistence detail into a Domain layer? – bckpwrld Dec 17 '13 at 17:47
  • 1
    The interface doesn't actually implement anything so keeping that in the domain is ok. The implementation of that interface may vary, depending on the back-end storage you're using and therefore should be external to your domain. – stephenl Dec 18 '13 at 04:48
  • @stephenl: I'm aware that we should keep the implementation of IUnitOfWork out of domain layer. The purpose of repo is to keep domain blissfully unaware of any persistence-related concept ( and for that reason repo interface shouldn't define any methods named Save or Update, since that would introduce persistence-related concepts into a domain ). But wouldn't you agree that unlike methods defined by repo interface, the methods defined by IUnitOfWork interface do represent ( and as such leak into a domain ) the persistence-related concepts?! – bckpwrld Dec 18 '13 at 16:09
  • 1
    not really. Some of the responses to your question have already answered this better than I have. On a different note, I'm wondering if IUoW is even required given that most ORM's today already implement change tracking for you. If you remove the methods that implement change tracking you're only really committing or roll-back the transaction and this doesn't necessarily require as separate pattern. Or does it? – stephenl Dec 23 '13 at 23:50
  • @stephenl: a) "If you remove the methods that implement change tracking ..." By "remove" I'm assuming we instead implement repository methods such that they don't change track? b) "...you're only really committing or roll-back the transaction" I'm guessing you mean that if repository methods don't implement change tracking, transaction is still gonna be committed or rolled back when we instruct datacontext to save the changes? c) "...this doesn't necessarily require as separate pattern" But if not UoW and if not repository methods, what code then will instruct datacontext to save changes? – bckpwrld Dec 31 '13 at 00:37
  • 1
    As it happens Jimmy Bogard just blogged about this. See http://lostechies.com/jimmybogard/2013/12/20/proper-sessiondbcontext-lifecycle-management/ – stephenl Dec 31 '13 at 06:29

3 Answers3

2

I would advice against exposing repositories to aggregates. Repositories are there to give you aggregates, that's it.

Look at it at that way: your domain is a "bubble" which only understands its own stuff. Meaning, it only understand its own value objects, domain services interfaces it declares, etc. I wouldn't include repositories in this set.

When your domain (an aggregate) needs something it should explicitly expose the dependency of what it needs, not just ask for some repository.

Services is what brings things together. For example, my command handler could look like:

public class ApproveOrderCommandHandler  : IHandle<ApproveOrderCommand> 
{
    //this might be set by a DI container, or passed to a constructor
    public IOrderRepository Repository { get; set; }
    public ISomeFancyDomainService ServiceRequiredForOrderApproval { get; set; }  

    public void Handle(ApproveOrderCommand command)
    {
        var order = Repository.Get(command.OrderId);
        order.Approve(command.Comment, ServiceRequiredForOrderApproval);
        Repository.Save(order);
    }
}

Note that although my command handler (app service in a way) deals with repositories, my domain (order aggregate) is persistence ignorant. It doesn't know anything about repositories of UnitOfWorks.

When I do need to spin up a UnitOfWork I can compose it using a Chain Of Responsibility pattern:

public class WithUnitOfWorkHandler<T> : IHandler<T>  {
    private readonly IHandler<T> _innerHandler;

    public WithUnitOfWorkHandler(IHandler<T> innerHandler)  {
        _innerHandler = innerHandler;
    }

    public void Handle(T command) {
        using(var ouw = new UnitOfWork()) {
            _innerHandler.Handle(command);
            uow.Commit();
        }
    }
}

Now I can "chain" any of my command handlers by "decorating" it with WithUnitOfWorkHandler. And some of the handlers may even touch more than one repository or aggregate. Still, aggregates don't know anything about persistence, unit of works, transactions, etc.

Alexey Raga
  • 7,457
  • 1
  • 31
  • 40
  • thanks for your answer. Can you respond to my reply? – bckpwrld Dec 18 '13 at 16:51
  • 1
    My reply as asked. a) There is no "DDD police" and you can do whatever you want obviously, I just think that exposing repositories to _domain_ (not only aggregates) is illogical. IMO domain should explicitly declare its dependencies _in a domain language_, no some repos. b) Generally yes as they are part of the domain and speak in the domain language. Dependencies are provided to them. c) Not really, as `UnitOfWork` and repositories implementations are not 'inside' the domain, so the domain stays PI. – Alexey Raga Dec 21 '13 at 14:18
  • 1
    2) Typically yes, I look at command handlers as at my application services are because any _action_ is a result of some command. 3) Yes, it is a typo. I copypasted and forgot to change the name :) – Alexey Raga Dec 21 '13 at 14:24
  • I know my reply is late, but I've just noticed that ApproveOrderCommandHandler implements IHandle while WithUnitOfWorkHandler implements IHandler. Is this a typo and in fact both ApproveOrderCommandHandler and WithUnitOfWorkHandler implement the same interface ( ie IHandler )? – bckpwrld Dec 31 '13 at 00:28
2

Persistence ignorance means: The business layer has no knowledge and no dependency whatsoever on the concrete persistence system that is used under the hood (e.g. MS SQL Server, Oracle, XML files, whatever).

Thus, exposing an interface that abstracts away the concrete type of the datastore can never violate this principle.

Thomas Weller
  • 11,631
  • 3
  • 26
  • 34
  • I assumed that even exposing UoW interface in domain or service layers was a violation of PI, since UoW interface contains persistence-related language and thus in a way persistence-related details leaked into service/domain layers ( though I'm aware the two layers don't have any knowledge of concrete UoW implementations ) – bckpwrld Dec 23 '13 at 20:21
1

Persistence Ignorance is a guideline, it is almost impossible to reach with actual languages and technologies. The Repository pattern and the Unit Of Work abstract the persistence related stuff and "hide" the Data Access Layer to the business code, but it is more a trick (a clean one) than an absolute solution. The presence or the need for something (an interface, a base class, an attribute...) that says "heyyy, there is something in here we want to hide..." violates PI. But for the moment, there is no better solution.

Rénald
  • 1,412
  • 12
  • 29