1

I'm new to DDD and trying to wrap my head around it by writing a prototype for an application (Core-Logic-Layer).

My domain model looks like this atm. (I leaved out parts, that weren't necessary for the problem):

enter image description here

So we have an aggregate root DebitAccount that has assigned Estimations (about costs / income that will occure in a given interval). It also has assigned Postings that physically occured (Cost / Income) at a given date.

A Posting may occure with an estimation assigned(e.g."We have monthly costs for paying the rent"), but it also may occure unforseen ("My notebook broke, so I need to buy a new one.")

Here is the (imho) necessary code to implement the model:

public class DebitAccount : BaseEntity
{
    protected ICollection<Estimation>     _Estimations;
    protected ICollection<Posting>        _Postings;

    public virtual IEnumerable<Estimation> Estimations
    {
        get 
        {
            return new List<Estimation>(_Estimations);
        }
    }

    public virtual IEnumerable<Posting> Postings
    { 
        get
        {
            return new List<Posting>(_Postings);
        }
    }
    public void Post(Posting posting)
    {
        var associatedEstimation = _Estimations.FirstOrDefault(e => e == posting.BelongsToEstimation);
        if(associatedEstimation == null)
        {
            var now  = _DateProvider.GetCurrentDate();
            var guid = Guid.NewGuid();
            associatedEstimation    = new Estimation(new Posting[] { posting }, new Amount(0, _CurrencyProvider.GetDefaultCurrency()), posting.PostingName, new DayInterval(now, now, 0),new EstimationId(guid));
            _Estimations.Add(associatedEstimation);
        }
        _Postings.Add(posting);
    }
    public DebitAccount TransferAmountTo(DebitAccount to, Amount amount, string transferName)
    {
        var currentDate = _DateProvider.GetCurrentDate();

        var fromPosting = new Posting(amount.Invert(),transferName, currentDate, null);
        var toPosting   = new Posting(amount.Clone() ,transferName, currentDate, null);

        this.Post(fromPosting);
        to.Post(toPosting);

        return this;
    }
}

There are several problems I'm facing:

  1. When calling the Post-Method of a debit account, how to get the Estimation to which the posting belongs (if there is any)? In the application code, one could get all estimations by the public property, find the correct one, and assign it to the current posting. But this requires the client to know, that he have to look for the estimation in the property.

  2. The next problem is similar to the first one: when transferring to another DebitAccount, how to find the corresponding Estimation (if any) ?

  3. TransferTo-Function: Where and how to persist both DebitAccounts. Shall the calling code (e.g. Application layer) assume, that implicitly the passed DebitAccount(to) was changed (call-by-reference) and just persist both of them in a repo?

How could these problems be addressed? Or maybe I'm wrong and my DDD-design is flawed? Any idea, comment and thought is appreciated :)

  • What happens when a Posting that belongs to an Estimation of DebitAccount A gets posted to DebitAccount B? When exactly a Posting gets created? If a Posting exists before a call to the Post method, how does it relate to a DebitAccount? – COME FROM Sep 5 '18 at 11:46
  • @COMEFROM: Very good questions. Well, postings shall be created through UI by the User or through a Task(regarding estimations that cause a posting on their due date). They shall only be created with reference to a DebitAccount. One could throw an Exception, if a Posting assigned to Estimation of Account A is posted to Account B (as Estimation are Entities with an Identity.) – Anton Rhein Sep 5 '18 at 16:37
1

I think the direct object reference from Posting to Estimate is a little bit problematic.

If Posting should be a pure value object, then it should be immutable. So, you shouldn't be able to create a Posting without designating the Estimate it belongs to. So, whenever there's a need to create Posting, there's also a need to access some DebitAccount and its Estimates. That sounds like a lot of control and logic is leaking out from the DebitAccount class.

What if only a DebitAccount knew how its Estimates and Postings are related to each other? Then there would be no need to have a reference to an Estimate from a Posting and perhaps not even references from Estimate to Postings.

That would solve problems 1&2, I think.

About problem 3: I would probably prefer having a method AccountService.ExecuteTransaction(Transaction) instead of a method DebitAccount.TransferAmountTo(DebitAccount, Amount amount, string transfername). A Transaction could be a value object like

class Transaction : ValueObject {
    private Id fromAccountId;
    private Id toAccountId;
    private Amount amount;
    private string name;
    ...
}

The Execute method would then update both accounts and make sure everything gets persisted correctly.

  • Indeed, direct reference from posting to estimation is problematic when posting to another account. I agree, that there will be a lot of logic leaking into application layer. But on the other side, I can't imagine a way how the account could know, which posting belongs to which estimation. This decision has to be made by the user (alternately task when it's processing the estimations, but in this case, the Task knows to which Estimation a posting belongs to) – Anton Rhein Sep 6 '18 at 14:48
  • A Service is imaginable, but managing persistance (in clean architecture) is part of Application layer (even with interfaces), so again domain logic leaks into application layer. – Anton Rhein Sep 6 '18 at 14:48
  • @AntonRhein I don't know what a Task is. What I meant by only a DebitAccount "knowing" the relationship between its Postings and Estimations is that it would be the only class that captures that information. A Posting would not know anything about Estimations and perhaps even an Estimation would not need to know anything about Postings. Some other class and other layer might still send messages to a DebitAccount about Postings and Estimations. I'd begin with removing the dependency Posting->Estimation. There's now a circular dependency between those classes. – COME FROM Sep 7 '18 at 6:18
  • @AntonRhein About Transactions: I can't really say what belongs to which layer in your application without seeing the big picture. What I would try to avoid anyway, no matter the overall architecture, is having DebitAccount handle the data and the logic of transactions, unless it's really simple. DebitAccounts already take care of Postings, which is clearly a lower level concept than a Transaction. – COME FROM Sep 7 '18 at 6:44
  • So an imaginable way for posting could be this: Post(Posting p, EstimationId e) which throws an exception if DebitAccount has not assigned an Estimation with the given Id. The DebitAccount could have a Dictionary or something like that, that tracks estimations and associated postings. And there is another method Post(Posting p) that creates an Estimation with value zero. A task may be a script or console app that reads from db and creates estimations etc. But thats another topic. – Anton Rhein Sep 7 '18 at 8:21

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.