James
James

Reputation: 1277

DDD time based state transition

I have an aggregate root with a "startTime" value object. At various points I need to determine if the AR has "started" to enforce different behaviour (both internally and externally to the AR). I also need to be able to filter aggregate roots at the storage layer by their "started" state, for performance reasons.

I'm not sure how to implement this in a DDD friendly way. I have considered exposing the state change to an external source (a scheduled event handler) and having the state defined explicitly:

public class AggregateRoot {
    private Time startTime;
    private boolean started;
    ...
    public void start() {
        started = true;
    }
    public boolean isStarted() {
        return started;
    }
}

This has the benefit of being easy to query at the storage layer, but seems odd as the startTime value object becomes redundant and there is nothing in the domain to enforce that the AR switches state at the defined startTime.

I have also considered having the state defined implicitly based on a comparison of "now" versus "startTime" (either at AR construction or on getter, example is on getter). This means the AR is fully in control of its own state etc. but means that I can't filter queries at the storage layer by state without duplicating this logic (bad for maintainability):

public class AggregateRoot {
    private Time startTime;
    ...
    public boolean isStarted() {
        return now().isAfter(startTime);
    }
}

Are there existing patterns for handling timed based state change? Is there a better way to approach this?

Upvotes: 2

Views: 329

Answers (1)

JefClaes
JefClaes

Reputation: 3373

Interesting. I know nothing about your domain, but I'm wondering how much different the behavior of your aggregate is after it has started? Is it possible that you actually have two different aggregates, which have a dependency on the same state? Instead of putting that behavior in the aggregate itself, could it be extracted into - do I dare to suggest it - a factory?

public class MyAggregateBeforeItHasStarted : IMyTemporalAggregate
{
    public MyAggregateBeforeItHasStarted(State state) { }
}

public class MyAggregateAfterItHasStarted : IMyTemporalAggregate
{
    public MyAggregateAfterItHasStarted(State state) { }
}

public class MyTemporalAggregateFactory 
{
    public IMyTemporalAggregate(StartTime startTime) 
    {
        if (startTime.LaterThan(x)) 
            return new MyAggregateAfterItHasStarted(state);

        return new MyAggregateBeforeItHasStarted(state);
    }
}

Upvotes: 1

Related Questions