Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

The problem I continually face is how to deal with computed values driven by domain logic while still working efficiently against the data store.

Example:

I'm returning a list of Products from my repository via a service. This list is limited by pagination info from request DTO sent by the client. In addition, the DTO specifies a sort parameter (a client-friendly enum).

In a simple scenario, everything works great: the service sends paging and sorting expressions to the repo and the repo issues an efficient query to the DB.

That all breaks down, however, when I need to sort on values generated in memory from my domain model. For instance the Product class has an IsExpired() method that returns a bool based on business logic. Now I can't sort and page at the repo level --it would all have be done in memory (inefficient) and my service would have to know the intricacies of when to issue these params to the repo and when to perform sorting/paging itself.

The only pattern that seems to make sense to me is to store the state of the entity in the db (make IsExpired() a readonly field and update it via the domain logic before saving). If I separate this logic into a separate "read model/dto" and "reporting" repository, I'm making my model more anemic than I'd like to.

BTW, every example I've seen out there for computations like this really seems to lean on in-memory processing and glossing over the fact that it is far less efficient in the long run. Maybe I'm prematurely optimizing, but that just doesn't sit right with me.

I'd love to hear how others have dealt with this as I'm sure it's common on nearly project involving DDD.

share|improve this question

3 Answers 3

up vote 2 down vote accepted

I don't think that having two different domain models of the same data model makes your domain anaemic. An anaemic domain model is one where the business logic that changes often is hidden away from the domain in a service layer (or, worse, in the UI layer).

Separation of command and query domain models is espoused often and has a nice acronym that you can google in CQRS (Command Query Responsibility Segregation).

Employing the Domain Model Pattern, Udi Dahan

While I was "successful" in the past in creating a single persistent object model that handled both commands and queries, it was often very difficult to scale it, as each part of the system tugged the model in a different direction.

It turns out that developers often take on more strenuous requirements than the business actually needs. The decision to use the domain model entities for showing information to the user is just such an example.

[...]

For those old enough to remember, the best practices around using COM+ guided us to create separate components for read-only and for read-write logic. Here we are, a decade later, with new technologies like the Entity Framework, yet those same principles continue to hold.

CQRS with Akka actors and functional domain models, Debasish Ghosh

Greg Young has delivered some great sessions on DDD and CQRS. In 2008 he said "A single model cannot be appropriate for reporting, searching and transactional behavior". We have at least two models - one that processes commands and feeds changes to another model which serves user queries and reports. The transactional behavior of the application gets executed through the rich domain model of aggregates and repositories, while the queries are directly served from a de-normalized data model.

CQRS, Martin Fowler

The change that CQRS introduces is to split that conceptual model into separate models for update and display, which it refers to as Command and Query respectively following the vocabulary of CommandQuerySeparation. The rationale is that for many problems, particularly in more complicated domains, having the same conceptual model for commands and queries leads to a more complex model that does neither well.

In short, your idea of having the command model handle the expiration and pass it to the database is absolutely fine. Read through the first article above and you'll see similar but more complex scenarios.

share|improve this answer

SPECIFICATION

I know you've already accepted an answer, but, you asked about DDD, and the exact match for this is what Evans calls a 'specification':
direct google books link
If that link doesn't work check for the book in these results
It's page 226 if you have the book.

On page 227 are 3 uses for specifications: Validation, Seletion, Building a new special object. Yours is 'selection' - IsExpired.

Another thing about the 'specificaiton' concept is that it admits that - for efficiency's sake - you may need one version of code to operate on the in-memory objects, and another version of the code to efficiently query the repository without having to first get all the objects into memory.

In a simple world, this would mean putting a SQL version in your repository and an objects version in your model, of course that has drawbacks. The logic is in 2 places (bad, somebody's going to forget to update on of those places) and there is domain logic in your repository.

So the answer is to put both sets of logic in a specification. The in-memory version, obviously, but a repository version, too. If you are using for example n-hibernate you can use its built-in query language for the repository version.

Otherwise you'll have to create a special repository method for this specification that is used from the specification object. Calls for collecitons of objects matching the specification would go thru the specification, not the repository. And at least the code screams 'i'm in 2 places, don't forget it' to future maintainers. There is a wonderful example on page 231-232 for a solving very similar problem.

The specification is an 'allowed' leakage/slippage of the 'purity' of DDD. It still might not serve your needs for a variety of purposes. For example, the ORM might generate bad SQL; there might be too much extra coding. So you might have to call repository methods such that it's almost like putting SQL in the specification. A bad thing of course. But don't forget, your program has to work- at a reasonable speed. It doesn't have to win a DDD purity prize. So a reality of switching datastores might mean old fashioned surgury thoughout the program. Also a bad thing. But not as bad as a slow (aka SUCKing) program. If running out of the box on various DBs is a reality, obviously, you'll be duplicating business rules for each datastore for each specification. At least you have your finger on the matter and you can make use of the strategy pattern when you swap repositories. But if you're using a specific DB already remember YAGNI.

Regarding CQRS: Fowler's quote by pdr above still holds true here: "having the same conceptual model for commands and queries leads to a more complex model that does neither well" ... and you may need to use CQRS or similar. But it is much more expensive from a development and maintainence standpoint. If you are a packages vendor in competition with others, it might pay. If you're writing a custom LOB app for one customer, shooting for perfection is a poor choice. You need to decide if the value in having a completely or mostly double model is worth the extra effort. Specification is a good compromise because it allows you to make this separation in just one little part of the program that needs it, with the (development) speed and simplicity of one model. Good luck!

share|improve this answer
    
That makes perfect sense. I think I need to bite the bullet and read Evans' book :-) I'm seeing now that having a shallow understanding of these concepts can really paralyze you! –  drogon Feb 6 '12 at 20:22

I guess I would question what the business logic is that determines whether isExpired is true or not. Can this logic be performed by a query as the data model stands? If so, can you make your repository intelligent enough to use the "isExpired" logic when you ask it for Products in a certain way? If not, perhaps you do need to reexamine your data model.

DDD doesn't mean that your repositories need to be stupid--it just means your domain needs to know how to talk to your repositories.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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