1

I am designing a system using domain driven design concepts and I am struggling with a few things. The "domain" is essentially a business system for the company I work for. I am also using dependency injection. So, in my model I have things related to any typical business system (Employee, Order, Invoice, Deposit, etc..). Right now I am trying to create a cash posting application in which users (aka Employees) can create deposits and apply them to unpaid invoices. The problem that I am having is that we are also using an external business system (Microsoft Dynamics Nav) to handle our accounting transactions. So essentially I am dealing with two different databases. So, for the cash posting application I have modeled the domain objects Deposit and DepositLine. I also have in my domain an IDepositRepository interface that is responsible for persisting the deposits. To get a deposit from the system I just want to grab it directly from the database. However, in order to create a deposit I have to use the Dynamics Nav web services because there is certain logic that gets executed behind the scenes that I don't know about. I started looking at the concept of an Anti Corruption layer in which I could translate my version of the deposit object into a deposit object suitable for the web service. So here is what I am envisioning right now:

Domain Layer

- Models
    - Deposit
    - DepositLine
- Repositories
    - IDepositRepository

Infrastructure Layer

- Data
    - Repositories
        - DepositRepository
- DynamicsNav
    - Services
        - INavCashManagementService
    - Translators
        - IDepositTranslator
    - Adapters
        - INavAdapter

Now I thought i might implement the DepositRepository like so:

public class DepositRepository
{
    private INavCashManagementService navCashManagementService;

    public DepositRepository(INavCashManagementService navCashManagementService)
    {
        this.navCashManagementService = navCashManagementService;
    }

    public Deposit GetDeposit(int id)
    {
        // use nhibernate to get directly from the database
    }

    public void SaveDeposit(Deposit deposit)
    {
        this.navCashManagementService.CreateDeposit(deposit);
    }
}

First of all, is this an appropriate design? My next problem is that users are also going to have to "Post" deposits. The Nav web services will also have to be used to run the posting routine. But, this is more of a business process rather than a persistence issue, so I don't see it fitting into the repository. So I am wondering how/where I should call the posting routine. Should I create a domain service like this:

public class CashPostingDomainService
{
    private INavCashManagementService navCashManagementService;

    public CashPostingDomainService(INavCashManagementService navCashManagementService)
    {
        this.navCashManagementService = navCashManagementService;
    }

    public void PostDeposits()
    {
        this.navCashManagementService.PostDeposits();
    }
}

One confusion I have with domain driven design is external dependencies. Doesn't the CashPostingDomainService class now have an external dependency on Nav? I know the implementation isn't in the domain layer, but doesn't the interface itself make it a dependency? The same goes with other technical concerns like sending emails. If I have an IEmailService interface and want to send an email once the deposits are posted, would I inject the interface into the CashPostingDomainService class? Or would that be part of the application workflow? So which one of these options make the most sense (if any):

1

public class DepositController
{
    private ICashPostingDomainService cashPostingDomainService;
    private IEmailService emailService;

    public DepositController(
        ICashPostingDomainService cashPostingDomainService, 
        IEmailService emailService)
    {
        this.cashPostingDomainService = cashPostingDomainService;
        this.emailService = emailService;
    }

    public void PostDeposits()
    {
        this.cashPostingDomainService.PostDeposits();
        this.emailService.NotifyDepositsPosted();
    }
}

2

public class DepositController
{
    private ICashPostingDomainService cashPostingDomainService;

    public DepositController(
        ICashPostingDomainService cashPostingDomainService)
    {
        this.cashPostingDomainService = cashPostingDomainService;
    }

    public void PostDeposits()
    {
        this.cashPostingDomainService.PostDeposits();
    }
}

public class CashPostingDomainService
{
    private INavCashManagementService navCashManagementService;
    private IEmailService emailService;

    public CashPostingDomainService(
        INavCashManagementService navCashManagementService,
        IEmailService emailService)
    {
        this.navCashManagementService = navCashManagementService;
        this.emailService = emailService;
    }

    public void PostDeposits()
    {
        this.navCashManagementService.PostDeposits();
        this.emailService.NotifyDepositsPosted();
    }
}

Thanks for the help!

1 Answers1

1

is this an appropriate design?

It seems fine to me. The important thing is for your Repository to stay oblivious of the Nav side of things and let the anticorruption layer handle that. You might want to have a look here for a similar example.

I know the implementation isn't in the domain layer, but doesn't the interface itself make it a dependency?

You may have that feeling because the name of your (supposedly agnostic) service interface contains "Nav". To reflect a service abstraction that could have Nav or any other ERP as an implementation, you should rename it to ICashManagementService.

If I have an IEmailService interface and want to send an email once the deposits are posted, would I inject the interface into the CashPostingDomainService class? Or would that be part of the application workflow?

It's your architectural decision to choose one or the other.

Option 1. means that sending an email is an intrinsic part of the deposit posting domain operation. If you take your domain module and reuse it in another application, posting deposits will automatically result in sending an email whatever that application is about. This might be the right thing to do in your context, or you might want to make things a little more generic (like, sending feedback after the operation but not deciding in the domain service whether this feedback should be mail, a log file, etc.)

Option 2. means that the sequence of events that happen after posting the deposits is application specific, that is at the use case level rather than business/domain level. It is up to the Controller (or Application Service) to decide which actions to take -send an email or anything else. Consequently, different applications based around your domain layer could decide to take different actions. This also means possible code duplication between these applications if several of them chose to send mails.

Community
  • 1
  • 1
guillaume31
  • 13,738
  • 1
  • 32
  • 51