Sponsored By Aspose - File Format APIs for .NET

Aspose are the market leader of .NET APIs for file business formats – natively work with DOCX, XLSX, PPT, PDF, MSG, MPP, images formats and many more!

DDD: Specifications, Language, and Locality

Consider the following code.

public class Customer {
     .
     .
     .
     public bool IsPreferredCustomer {
            get {
return (this.TotalSales > 10000 || this.TotalVisits > 50) || (this.TotalSales > 5000 && this.TotalVisits > 25);
}
}

In this example a common pattern is being followed where an attribute IsPreferredCustomer has been exposed directly from the Customer object. The attribute in terms of language is being used to abstract the concept of a customer who has spent ten thousand dollars, had over fifty visits, or has over five thousand dollars in sales and twenty-five visits to the location.

 

There are other options in how to implement this however, namely by using the Specification Pattern

public class IsAPreferredCustomer : Specification<Customer> {
    public bool Matches(Customer customer) {
           if(customer == null) return false;
           return customer != null && (customer.TotalSales > 10000 || customer.TotalVisits > 50) || (customer.TotalSales > 5000 && customer.TotalVisits > 25);
}

 

So the question quickly becomes which of these is correct under what circumstances? In order to answer this question one must look at the strengths and weaknesses of each.

 

Language

The main difference between the two examples can be seen in how they are represented in terms of the ubiquitous language.

 

When dealing with the attribute approach in the ubiquitous language the attribute is applied to every instance when discussing the entity. It is treated just like any other attribute, the name of the customer as an example. By simply listening to the language it is unspecified whether this represents a calculation being performed or is a value associated with the entity.

 

The Specification maintains a subtly different linguistic representation. The specification applies a name to a constraint. Since it is defining a name to a constraint it is known based on its usage that it is a calculation as opposed to a denormalization. It is also made clear that because it is defined as a specification, that it’s purpose is to constrain. When an attribute is available upon an entity, constraints can be but do not necessarily have to be made upon it. In other words, the attribute is available to constraining code but may have another purpose in general. The specification makes the intent of constraining inherent in the language which is a primary goal of the ubiquitous language, making the implicit explicit.

 

Code Locality

When an attribute is added to the entity it being part of the entity is necessarily located near the rest of the code associated with that entity. This can be an advantage in terms of maintenance as the code associated with the entity is localized and can be easier to find/follow by a developer traversing the source base.

 

The localization of the validation logic can also be a hindrance. Because the code maintains its locality one can run into code explosion when there are many of these attributes. The area continues to grow as new code gets added eventually reaching a point where it has crossed the threshold of being able to be kept straight in a single location. Refactoring away from attributes at this point can be a pain.

 

Another problem with maintaining the locality is that we can only reasonably have a single implementation of the attribute. If one were faced with a multi-tenant situation or having multiple deployments with varying rules the specification would be preferred as it provides a seam for replacement.

 

The C# programming language offers some interesting ways of dealing with the possible explosion of code within the original entity. Partial classes allow a class to be defined across multiple files and extension methods allow static methods stored elsewhere to “appear” to be a part of the entity while they are in fact just static methods. In the case of constraints this is actually a good thing as the constraints don’t really “belong” in the entity but are describing it. These types of syntactical sugar can make things much easier to deal with in terms of dealing with possible code explosion and should be considered as options if they are available in a given language. As an example consider the following C# code that uses both the specification pattern and extension methods to create what some may consider a more concise API around the previous example.

 

Encapsulation

Many bring up encapsulation as a key difference between the two patterns shown. The attribute-based example encapsulates the logic representing the constraint within it. One must question whether the entity is in fact the proper place to put this logic. At first smell it would seem that it is as in order to write a constraining specification the specification needs access to the internal state of the entity.

 

The need of a constraining specification often leads to the exposing of the state globally from the entity that as illustrated previously [see Getter/Setter Anti-Pattern] can cause other problems within the domain. The solution to this issue is to adjust the tools being used as opposed to the way modeling is performed; some languages have constructs such as friend classes that handle this case in a more elegant manner.

 

Analysis

Upon analyzing the various usages it becomes apparent that the use of an attribute to expose the constraint is usually an anti-pattern. A specification will always better model a constraint in the ubiquitous language. The intention of the modeler to constrain is also made explicit while remaining implicit with the attribute version. While the [Programmer Pornography] of encapsulation or especially code locality may end up with an advantage to the attribute based version it is also a long term risk as it can easily explode and is difficult to refactor.

 

Rule of Thumb: Avoid the use of attributes on entities that are constraints. Prefer to use a specification as it makes the intent to constrain explicit.

This entry was posted in DDD. Bookmark the permalink. Follow any comments here with the RSS feed for this post.

15 Responses to DDD: Specifications, Language, and Locality

  1. Colin Jack says:

    Great stuff, one alternative is to keep the member on the entity but have it delegate to the specification.

    On encapsulaton, Evans was quite clear that entities should be stripped down (pp 93 on “Modeling Entities”) and fulfill their responsibilities by co-ordinating the operations of objects they own.

  2. savaş oyunu says:

    ı have followed your writing for a long time.really you have given very successful information.
    In spite of my english trouale,I am trying to read and understand your writing.
    And ı am following frequently.I hope that you will be with us together with much more scharings.
    I hope that your success will go on.

  3. redgreenrefactor says:

    Greg, Thanx.

    From M.Fowler’s problem statement ‘You need to select a subset of objects based on some criteria,’

    My question. Can you be more specific. Because in you’re sample if you want a list of all preferred customers you will need to load them all and then run the specification don’t you?

  4. Greg says:

    redgreenrefactor:

    It seems to me that you may want to revisit the specification pattern as you seem to have it confused with a query object. They are not always equivalent and specifications have further uses than querying data (business rules come to mind).

    This has long been an area of misunderstanding in DDD (is this a specification or a query object?) as often you want them to be both. LINQ is actually a great solution to this problem but it is not possible to have a complete solution. I will try to put a post on this soon.

    Greg

  5. redgreenrefactor says:

    Second try. My first comment didn’t show up. In my experience the specification pattern is nice on paper but when working in the real world with real numbers of data it’s not practical because of the load on the databasea. Most of the times we use ICriteria from NHibernate to get the results. If there’s another solution to overcome this problem please show it.

  6. redgreenrefactor says:

    The specification pattern is a nice pattern on paper, but what happens if you have a lot of ‘Customers’ and i mean really a lot. In my experience it’s not a very practical pattern and should be avoided most off the times. We solve this throught in our case NHibernate criteria’s which is must faster.

  7. Jonathan says:

    The biggest hurdle that we hit with the specification pattern was the sharing of state, specifically state that we weren’t entirely comfortable exposing. The issue was solved in the same way as you have stated above in your article: through friend assemblies and the use of the “internal” keyword.

  8. jdn says:

    “As an example consider the following C# code that uses both the specification pattern and extension methods to create what some may consider a more concise API around the previous example.”

    Either I’ve gone blind or you forgot to include it (or both).

    I still think the Ubiquitous Language is an impossibility for philosophical reasons (there are only various Shared_Languages in drag), but that’s a much longer discussion.

  9. G-Funk says:

    Yo Greg-

    Gimme a shout bro, 598.4959 you know the area code.

    Stafford

  10. Gerry says:

    Although I accept the arguments you make, I’m left wondering what else will be going into the IsAPreferredCustomer class other than the Matches method. Does this approach not tend to lead to a “Lazy class” smell?

  11. GAlexander says:

    Although I like the Specification pattern, I can see two downsides.
    1-the need to provide additional getters and setters, simply to give the spec class access to the required data.
    2-extracting too much logic in this way will lead to an Anemic Domain Model.

  12. Jason Pettys says:

    Pingback from Jason Pettys

  13. Ken Egozi says:

    Well written.

    just a little note though:
    ” … As an example consider the following C# code … ”
    but the code bit appear to be missing

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>