Monday, January 30, 2006

A case for Specifications

It has been a long time since I wanted to post about this, and now, finally, here I am.

In this post I want to talk a bit about Specification, a Domain-Driven Design pattern I think very interesting and useful in a lot of situations.

What is, so, a Specification?

Domain models are not only about entities, relations and collaborations. Domain models must also host a lot of implicit concepts and rules you must deal with, because they are important parts of your business domain : for example, booking policies, payment delinquent rules and so on.
The problem is to find a place for this concepts.
You can model and implement them inside your entities, your business objects, but doing so you couple your objects with concepts regarding them but not being part of them; more important :

  • You lose a lot of expressivity, because you sink your meaningful (but implicit) concepts into your object code.

  • You lose a lot of flexibility, because you cannot change or apply them regardless of your business objects.

The answer is the Specification Pattern.

Specifications, as said by Eric Evans, are a concept borrowed from logic programming: they are tiny classes with a method representing a boolean predicate.
The Specification models a particular concept that applies to a particular entity, providing a method which expresses the concept as a predicate; in particular, the method tests if a given instance of the entity satisfies the expressed predicate.

Let me show you a practical example.

Say you have an employee who issues some requests, for example permit requests.
The employee cannot directly request a permit for a number of days greater than those remaining; if he wants to request more days, he must ask the secretary, but even in this case he cannot exceed a certain limit.

How do you model this?

You'll have an Employee entity, a generic Request and a PermitRequest entity.
But what about all those concepts regarding the employee request?
Remember, a permit request which exceed the employee remaining days is not valid if made by the employee, and so on ...

If you don't use Specifications, you can implement a validation method inside your PermitRequest class :
public class PermitRequest
implements Request, ValidationAware {
private static final int limit = -10;
private Employee owner;
private int requestedDays;
// ...
public void validate() {
int remaining = owner.getRemainingDays();
if (remaining < this.requestedDays) {
// notice this ...
}
if ((remaining - this.requestedDays)
< PermitRequest.limit) {
// notice this ...
}
// ...
}
}
Doing so, however, you couple your rules and cannot separately apply them, breaking your requirements!
You can surely use two distinct validation methods:
public class PermitRequest
implements Request {
private static final int limit = -10;
private Employee owner;
private int requestedDays;
// ...
public void validateForEmployee() {
int remaining = owner.getRemainingDays();
if (remaining < this.requestedDays) {
// notice this ...
}
// ...
}
public void validateForSecretary() {
int remaining = owner.getRemainingDays();
if ((remaining - this.requestedDays)
< PermitRequest.limit) {
// notice this ...
}
// ...
}
}
But doing so you couple yourself with the particular Request entity, breaking a lot of design principles ... what if we want to validate a request without knowing its actual type? What method to call?

Implementing two distinct Specifications is simple and solves all your problems.
You'll have an ExceedDaysSpecification for the first rule (requested day cannot exceed remaining days), and an ExceedLimitSpecification for the second one (requested days cannot exceed a certain limit), each with the predicate method accepting a Request and testing the given rule over it.
public class ExceedDaysSpecification
implements RequestSpecification {
public boolean isValid(Request request) {
int remaining = request.getOwner().getRemainingDays();
int requested = request.getRequestedDays();
if (remaining < requested) {
return false;
}
else {
return true;
}
}
}

public class ExceedLimitSpecification
implements RequestSpecification {
private static final int limit = -10;
public boolean isValid(Request request) {
int remaining = request.getOwner().getRemainingDays();
int requested = request.getRequestedDays();
if ((remaining - requested)
< ExceedLimitSpecification.limit) {
return false;
}
else {
return true;
}
}
}
In this way :

  • Implicit concepts are powerfully expressed.

  • Specifications can be applied to every base type of entity (Request) : if you need to know the actual type inside the Specification predicate method, you can do a downcast or apply a simplified Visitor pattern.

  • Specifications can be easily combined : simply combine the evaluation of the predicate methods!

You have the obvious drawback of having to implement a given quantity (maybe a lot, for complex domains) of small classes, but I think the gained expressivity and flexibility well worth the effort.

What's your way of thinking about this?

4 comments:

Roni Burd said...

I think this is a good example of how to use specificaction. The only thing I believe is missing is how to actually use the specifcation pattern, and I mean not just a line of code like ExceedLimitSpecification.isValid(request) but something more meaningful like from where I obtain the specification (diffrent employee hierarchy??).

Sergio Bossa said...

Roni Burd said...

> from where I obtain the
> specification (diffrent employee
> hierarchy??)

Specifications can be created on the fly just when you need them.
The actual specification type can be defined at runtime, i.e. via dependency injection.

Regards,

Sergio B.

Alan Liu said...

Could the rising rule engines add some points to the Specification pattern? Instead of coding the logic in the ExceedDaysSpecification.isValid(), the method could delegate the calculation to rule engine. This way, users can configure the logic in a natural language manner like "if remaining is less than requested, then false." without engineers modify the source code.

Having singled out the logic, we can easily refactor the Specification class to use rule engine to calculate the value without affecting the rest of the code. Or we can have a RuleBasedExceedDaysSpecification class which uses rule engines to figure out the isValid().

$0.02

Sergio Bossa said...

Alan Liu said ...

> Could the rising rule engines add some points to the Specification pattern?

Hi Alan,

your proposal is interesting, but I think Rule Engines may introduce a lot of complexity.
You can read my response here:

http://groups.yahoo.com/group/domaindrivendesign/message/3674

However, as soon as I'll find some time I'll try to implement Specifications with some simple logic backed by a Rule Engine, just an experiment ...
I'll post more in my blog.

Thanks,
Regards,

Sergio B.