3

Situation:

I am implementing DDD in my first project and I would like to clarify how to correctly implement strategy pattern (in my case check if API token is active). This is a business rule of ApiToken instance but there could be various implementations of this strategy so I would like to delegate this logic to external implementation.

Implementation:

ApiToken class:

public abstract class ApiToken {
    public abstract boolean isActive(TokenActiveStrategy strategy);
}

and this is token strategy contract:

public interface TokenStrategy {
    boolean isActive(final ApiToken token);
}

And usage:

TokenStrategy tokenStrategy = new DatabaseTokenStrategy();

if (!token.isActive(tokenStrategy)) {
   throw new AuthenticationException(ExceptionCodeType.TOKEN_NOT_ACTIVE);
}

and concrete ApiToken class:

@Override
    public boolean isActive(final TokenStrategy strategy) {
        return strategy.isActive(this);
    }

Question:

Is it OK with respect to principles of DDD to delegate checking of domain business rule out of domain object?

2 Answers 2

6

A Domain Object is not responsible for providing information outside of it's own context. Whether or not an API token is active is not something the token itself can answer, but is instead a question for the API provider - the API provider is the source of truth.

A good real world analogy is: can a car tell you whether it is registered or not? No, even if there is a number plate or registration papers in the glove box, it cannot. Only your local Auto/Roads authority can answer that question truthfully.

To me, the functionality you are looking to implement (checking whether an ApiToken is active) should reside in a Domain Service. Then, when you make a concrete implementation of the Domain Service, it can call the API provider (or you can mock stub it if unit testing):

if (!apiTokenService.isTokenActive(token)) {
    throw new AuthenticationException(ExceptionCodeType.TOKEN_NOT_ACTIVE);
}

(Sorry for the lack of code, Java(?) is not my strong point)

1

There is unfortunately no objective single truth how to do these things. It always depends on your interpretation of DDD, and the context in which you are working.

Interpretations

In one interpretation, Entities are nothing more than Data holders or Records, with most or all logic in Services or other supporting classes. In this interpretation, your ApiToken wouldn't even have an isActive() method, instead it would publish all its data (via getters), and let other classes deal with it as they please.

If you work in an Object-Oriented context however, the interpretation can differ significantly. In this case your proposed solution would have two problems:

  1. The Strategy objects would have to have full access to everything in the ApiToken. In other words, they would be very tightly coupled. This is frowned upon in OO world.

  2. The Strategy classes are not part of the Domain. Not part of the shared vocabulary between developers and business. Not part of the Ubiquitous Language.

One possible solution with OO+DDD in mind

With the usual disclaimer that I don't know all of your requirements, how about doing this:

public interface ApiToken {
    boolean isActive();
}

public final class DatabaseApiToken {
    ...
    @Override
    public boolean isActive() {
        ...sql or whatever...
    }
}

This is much simpler, solves both problems mentioned above, compatible with both DDD and OO.

Other points

Also, look at why you need the method isActive()! Sometimes (not always) there is actually a single use-case for it, which itself can be moved into the ApiToken, thereby making isActive() superfluous, and having more complete logic in ApiToken, which is good!

Here is a presentation of mine about Object-Oriented Domain-Driven Design with some additional points.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.