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?
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)
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:
Come to think of it, this is basically the domain event pattern.