dimanche 26 novembre 2017

The aggregate must know and base its behavior only on its own state? Can the aggregate use the state of other aggregates in its behavior (methods)?

Can the aggregate use the state of other aggregates in its behavior (methods)? Should I inject links to other aggregates, services with access to other aggregates. Or the aggregate must know and base its behavior only on its own state?

Does the DDD community have a clear understanding on the "Aggregate" pattern on this issue? Or this question does not apply to DDD? On the other hand, for example, I've heard a fairly unambiguous view of the community that you do not need to inject a repository to the aggregate.

Where is the boundary between the fact that the operation of the meaning of the aggregate that precedes should not go to the level of services (anemic model), and meanwhile, to reduce the dependence and connectivity of aggregates?

If the aggregate is based only on its state and there are no external dependencies, then it is necessary to make a layer from the domain services? How to call these domain services?

I have an example. I deliberately threw out all the extra to simplify it as much as possible. And left only one operation. In this example, I implemented this approach: 1. Aggregates are independent and satisfy invariants only on its own state. 2. The logic belonging to the domain, but interacting with other aggregates and services is transferred to the domain services.

Описание примера: This is bounded context - auction. Here there are Lot, Bid, Bidder, Timer - which are put or restarted to count down the time before the victory. The operation that is being considered here is "make bid":

  1. Application layer get from client required data, get aggregates, services, repositories. Than call domain service (Domain Service BidMaker -> makeBid) and passes on to that service all that is necessary.
  2. Method of domain service (#Domain Service# BidMaker -> makeBid)

    а) Call method of aggregate (AR Lot -> makeBid), then this method check invariants, then make bid and add it to bidIds.

    b) Checks whether the timers exist in lot, if no start new timers or restarts old timers using the domain service - WinnerTimer.

    c) If timers new - save them using repository

    d) Call method of aggregate (AR Lot -> restartTimers), then this method add timers to winnerTimerId и winnerTimerBefore2HoursId.

I got a duplication of the name of the methods of the domain service and the aggregate. And logically, however, the "make a bid" operation belongs to the Lot aggregate. But then you need to transfer the logic from the BidMaker domain service to the aggregate, which means that you will also need to inject a timer repository and a timer service into the aggregate.

I would like to hear opinions - what would you change in this example and why? And also opinions on the first and main issue. Thanks to everyone.

/*Domain Service*/ BidMaker{
  void makeBid(
    WinnerTimer winnerTimer,
    TimerRepository timerRepository,
    int amount,
    Bidder bidder,
    Lot lot,
  ){
    //call lot.makeBid
    //check Lot's timers and put new or restart existing through WinnerTimer
    //save timers if they new through TimerRepository
    /call lot.restartTimers
  }
}

/*Domain Service*/ WinnerTimer{
  Timer putWinnerTimer(){}
  Timer putWinnerTimerBefore2Hours(){}
  void restartWinnerTimer(Timer timerForRestart){}
  void restartWinnerTimerBefore2Hours(Timer timerForRestart){}
}


/*AR*/ Lot{

  Lot{
    LotId id;
    BidId[] bidIds;
    TimerId winnerTimerId;
    TimerId winnerTimerBefore2HoursId;

    void makeBid(
      int amount,
      BidderId bidder,
      TimerId winnerTimerId,
      TimerId winnerTimerBefore2HoursId
    ){
      //check business invariants of #AR# within the boundaries
      //make Bid and add to bidIds
    }

    void restartTimers(TimerId winnerTimerId, TimerId winnerTimerBefore2Hours){
      //restart timers
    }
  }

  Bid{
    BidId id;
    int amount;
    BidderId bidderId;
  }

}

/*AR*/ Timer{
  Timer{
    TimerId id;
    Date: date;
  }
}

/*AR*/ Bidder{
  Bidder{
    BidderId: id;
  }
}

Aucun commentaire:

Enregistrer un commentaire