Domain Driven Design - I find it hard to come up with a solution for this kind of business logic

StackOverflow https://stackoverflow.com/questions/9277573

  •  29-04-2021
  •  | 
  •  

Question

Introduction

Let's say I have three Domain Objects:

Proposition
Phase
Task

A Proposition can have one or more Phases. A Phases can have one or more Tasks.

If I completed the last Task in the last Phase, the Proposition must be set to 'Closed'.

In code I've created something like this to complete the last Task of a Phase

//My Business Layer does this:
--------------------------------------
pseudo:
var phase = _phaseRepository.GetById(id);
phase.LastTask.SetComplete();


// My Domain Entities look like this:
------------------------
public class phase()
{
   public Task LastTask { get; set; } // not real code of course
}

public class Task()
{
   public Phase Phase { get; set; }

   public void SetComplete()
   {
      Phase.IsFinished = true;
   }
}

Question

Where do I put the code to set the Proposition to 'Closed'?

Options

I think have a few options:

1) In the Domain Entity: Task.SetComplete

public class Task()
{
   public Phase Phase { get; set; }

   public void SetComplete()
   {
      Phase.IsFinished = true;
      Phase.Proposition.IsClosed = true;
   }
}

2a) In the Business Layer

var phase = _phaseRepository.GetById(id);
phase.LastTask.SetComplete();

var proposition = _propositionRepository.GetById(phase.PropositionId);
proposition.IsClosed = true;

2b) In the Business Layer, maybe a bit nicer way:

var phase = _phaseRepository.GetByIdIncludingProposition(id);
phase.LastTask.SetComplete();
phase.proposition.SetClosed();

3) Let everything pass thru Proposition:

//My Business Layer:
var proposition = _propositionRepository.GetById(id);
proposition.CompleteTask(taskId);

// Domain Object:
public class Proposition()
{
   public List<Phase> Phases { get; set; }

   public void CompleteTask(long taskId)
   {
      var task = // psuedo: select relevant task from Phases.Tasks, using taskid
      task.SetComplete();
      task.Phase.SetFinished();

      //psuedo: if task.Phase is last phase in proposition
      Phase.Proposition.IsClosed = true;
   }
}

About the options

Option 1 is problematic on the line

Phase.Proposition.IsClosed = true;

because Proposition doesn't have to be loaded, and if it's not loaded we get an exception.

Option 2a is problematic because after phase.LastTask.SetComplete() is executed the proposition is not in the correct state. And everywhere in code where one has access to Phase, "phase.LastTask.SetComplete()" can be executed without doing the relevant operations on Proposition.

Option 2b has the same problem as 2a.

Option 3 gives the Proposition class too much responsibilities.

Do you guys have any suggestions?

Was it helpful?

Solution

I'm guessing that Proposition is the aggregate root.A task is part of a proposition in the end and I think that the Tssk should notify that is completed i'd try this approach (basically option 3 a bit modified)

public class Proposition()
{
  public Task GetTask(int taskId)
  {
      //find and return task
  } 
}

//in business layer 
var p= _repository.GetProposition(id);
p.GetTask(taskId).SetComplete();

public class Task
{
  public event Action<Task> Completed;       


   public void SetComplete()
   {
        if (Completed!=null) Completed(this);
    }

The Phase should handle the completed event of Task and when it is triggerd, chek if it's the last task and notify the proporisiton to closeitself. NOw maybe using events is not the best implemetnation, probably the Observer pattern is better, but the main ideas are:

  • You get a task via a Proposition method (as Proposition is an AR)
  • Tasks notifies phase when it's finished
  • Phase notifies proposition when the last task is completed
  • Proposition should check if there aren't any phases in progress and close itself.
  • save Proposition in the repository

Come to think of it, this is basically the domain event pattern.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top