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.

Where do we draw the line between delegation and encapsulation of business logic? It seems to me that the more we delegate, the more anemic we become. However, delegation also promotes reuse and the DRY principal. So what is appropriate to delegate and what should remain in our domain models?

Take the following concerns as examples:

Authorization. Should the domain object be responsible for maintaining its access control rules (such as a CanEdit property) or should that be delegated to another component/service solely responsible for managing access, e.g. IAuthorizationService.CanEdit(object)? Or should it be a combination of the two? Perhaps the domain object has a CanEdit property which delegates to an internal IAuthorizationService to perform the actual work?

Validation. The same discussion as above relates to validation. Who maintains the rules and who is responsible for evaluating them? On the one hand, the state of the object should belong to that object and validity is a state but we don't want to rewrite the code used to evaluate rules for every domain object. We could use inheritance in this case...

Object Creation. Factory class versus factory methods versus 'newing' up an instance. If we use a separate factory class, we are able to isolate and encapsulate creation logic but at the expense of opening our object's state to the factory. This can be managed if our domain layer is in a separate assembly by exposing an internal constructor used by the factory but this becomes a problem if there are multiple creation patterns. And, if all the factory is doing is calling the right constructor, what's the point of having the factory?

Factory methods on the class eliminate the issue with opening up the object's internal state but since they are static, we aren't able to break dependencies through injection of a factory interface like we can with a separate factory class.

Persistence. One could argue that if our domain object is going to expose CanEdit while delegating the responsibility to perform the authorization check to another party (IAuthorizationService) why not have a Save method on our domain object that does the same thing? This would allow us to evaluate the internal state of the object to determine if the operation can be performed without breaking encapsulation. Of course it requires that that we inject the repository instance into our domain object, which smells a bit to me, so do we raise a domain event instead and allow a handler to perform the persistance operation?

See where I'm going with this?

Rockford Lhotka has a great discussion about his reasons for going the Class-in-Charge route for his CSLA framework and I have a bit of history with that framework and can see his idea of business objects paralleling domain objects in many ways. But trying to become more adherent to good DDD ideals, I'm wondering when collaboration becomes too much.

If I end up with an IAuthorizationService, IValidator, IFactory and IRepository for my aggregate root, what's left? Is having a Publish method that changes the state of the object from Draft to Published enough to consider the class a non-anemic domain object?

Your thoughts?

share|improve this question
    
Great question. I don't have an answer for you since I almost always end up completely anemic in design for the exact same reason -- using/consuming/exposing services from/to many different contexts or different applications. –  hromanko Apr 27 '11 at 17:58
    
Great question, would love to see unclebob, martinfowler, ericevans et al to chime in on this. Now for me to go away and have a long think –  Martijn Verburg Apr 27 '11 at 18:40
    
I find myself evolving to an anemic model all the time; and so I'm struggling with this exact same thing. Great question! –  Lud Sep 20 '11 at 9:38
    
This has been my experience with DDD as well. We're doing it where I work, and we always end up anemic. I previously (and still do actually) use Csla. Our architect doesn't like that we're anemic, but hasn't been able to give me a good answer to what the object should do if all the stuff you point out can't be done within the object. At the end of the day, trying to be purist DDD seems to create more work than its worth. I personally think Csla and DDD get along (they seem identical in principals), if you're willing to leave the DDD dogma behind. –  Andy Oct 22 '11 at 1:49
add comment

5 Answers

up vote 33 down vote accepted

Most of the confusion seems to be around functionality that should not exist in the domain model at all:

  • Persistence should never be in the domain model. Never ever. That's the reason you rely on abstract types such as IRepository if part of the model ever needs to do something like retrieve a different part of the model, and use dependency injection or some similar technique to wire up the implementation. So strike that from the record.

  • Authorization is not generally part of your domain model, unless it is actually part of the domain, e.g. if you're writing security software. The mechanics of who is allowed to perform what in an application are normally handled at the "edge" of the business/domain tier, the public parts that the UI and Integration pieces are actually allowed to talk to - the Controller in MVC, the Services or the messaging system itself in an SOA... you get the picture.

  • Factories (and I assume you mean abstract factories here) aren't exactly bad to have in a domain model but they are almost always unnecessary. Normally you only have a factory when the inner mechanics of object creation might change. But you only have one implementation of the domain model, which means that there will only ever be one kind of factory which always invokes the same constructors and other initialization code.

    You can have "convenience" factories if you want - classes that encapsulate common combinations of constructor parameters and so on - but honestly, generally speaking, if you've got a lot of factories sitting in your domain model then you're just wasting lines of code.

So once you turf all of those, that just leaves validation. That's the only one that's kind of tricky.

Validation is part of your domain model but it is also a part of every other component of the application. Your UI and database will have their own, similar yet different validation rules, based on a similar yet different conceptual model. It's not really specified whether or not objects need to have a Validate method but even if they do, they'll usually delegate it to a validator class (not interface - validation is not abstract in the domain model, it is fundamental).

Keep in mind that the validator is still technically part of the model; it doesn't need to be attached to an aggregate root because it doesn't contain any data or state. Domain models are conceptual things, usually physically translating to an assembly or a collection of assemblies. Don't stress out over the "anemic" issue if your delegation code resides in very close proximity to the object model; it still counts.

What this all really comes down to is that if you're going to do DDD, you have to understand what the domain is. If you're still talking about things like persistence and authorization then you're on the wrong track. The domain represents the running state of a system - the physical and conceptual objects and attributes. Anything that is not directly relevant to the objects and relationships themselves does not belong in the domain model, period.

As a rule of thumb, when considering whether or not something belongs in the domain model, ask yourself the following question:

"Can this functionality ever change for purely technical reasons?" In other words, not due to any observable change to the real-world business or domain?

If the answer is "yes", then it doesn't belong in the domain model. It's not part of the domain.

There's a very good chance that, someday, you'll change your persistence and authorization infrastructures. Therefore, they aren't part of the domain, they're part of the application. This also applies to algorithms, like sorting and searching; you shouldn't go and shove a binary search code implementation into your domain model, because your domain is only concerned with the abstract concept of a search, not how it works.

If, after you've stripped away all the stuff that doesn't matter, you find that the domain model is truly anemic, then that should serve as a pretty good indication that DDD is simply the wrong paradigm for your project.

Some domains really are anemic. Social bookmarking apps don't really have much of a "domain" to speak of; all your objects are basically just data with no functionality. A Sales and CRM system, on the other hand, has a pretty heavy domain; when you load up a Rate entity then there is a reasonable expectation that you can actually do stuff with that rate, such as apply it to an order quantity and have it figure out the volume discounts and promo codes and all that fun stuff.

Domain objects that just hold data usually do mean that you have an anemic domain model, but that doesn't necessarily mean that you've created a bad design - it might just mean that the domain itself is anemic and that you should be using a different methodology.

share|improve this answer
    
Excellent response. I'm with you for the most part. I threw persistence in there just to highlight another aspect but completely agree & have been preaching for years (before I knew anything about DDD) that our domain should be persistence ignorant. I still wonder about authorization, though, as security does play a role in the operations our domain objects perform. What about checking access before performing a task such as verifying a user is in the Publishers role before executing the Publish method? –  SonOfPirate Apr 28 '11 at 12:39
    
And given the scenario where we automatically increase a customer's line of credit in response to some criteria such as reaching an order level, I suspect that you recommend using domain events where the handler then evaluates whether a credit increase is applicable based on the customer's state and any other rules including authorization checks. Yes? –  SonOfPirate Apr 28 '11 at 12:41
    
@SonOfPirate: Your second question, about the line of credit, that's a business rule, not authorization. That is a domain concern, although the specific threshold might be externalized. For actions where the business/domain rules themselves change based on the security context, see my comment to qes' answer, specifically the one on State Pattern. –  Aaronaught Apr 28 '11 at 14:12
    
@SonOfPirate: Back to the first question, the problem with doing something such as "verifying a user is in the Publishers role before executing the Publish method" is that those kinds of rules change very frequently and you don't want those changes to cascade through the entire system and possibly break other things. Far better to perform authorization checks at the point of request; once an action gets to your domain model, it should already be authorized by the caller. –  Aaronaught Apr 28 '11 at 14:16
1  
@LaurentBourgault-Roy: Sorry, I don't believe you. Every company could say that about every application; after all, changing a database is hard. That doesn't make it part of your domain, and business logic that is coupled to the persistence layer just means poor abstraction. A domain model is focused on behaviour, which is exactly what persistence isn't. This isn't a subject on which people can invent their own definitions; it's pretty clearly spelled out in DDD. You often don't need a domain model for CRUD or reporting apps, but you also shouldn't claim that you have one when you don't. –  Aaronaught Jan 23 at 1:49
show 12 more comments

Authorization. Should the domain object be responsible for maintaining its access control rules

No. Authorization is a concern unto itself. Commands that wouldn't be valid due to a lack of permissions should be rejected before the domain, as early as possible - which means often we will even want to check authorization of a potential command in order to build the UI (so as to not even show the user the option of editing).

Sharing authorization strategies across layers (in the UI and further up in a service or command handler) is easier when authorization is componentized separate from the domain model.

One tricky part that can be encountered is contextual authorization, where a command may or may not be allowed not only based on user roles but also business data/rules.

Validation. The same discussion as above relates to validation.

I would also say no, not in the domain (mostly). Validation occurs in different contexts, and the validations rules often differ between contexts. There is rarely an simple, absolute sense of valid or not valid when considering the data encapsulated by an aggregate.

Also, like authorization, we utilize validation logic across layers - in the UI, in the service or command handler, etc. Again, it is easier to employ DRY with validation if it is a separate component. From a practical point, validation (particularly when using frameworks) requires exposing data that otherwise should be encapsulated and it often requires custom attributes to be attached to fields and properties. I much prefer these to be on other classes than my domain models.

I would rather duplicate some properties in a couple similar classes than try to force the requirements for a validation framework into my entities. That inevitably ends up making a mess of the entity classes.

Object Creation. Factory class versus factory methods versus 'newing' up an instance.

I use one layer of indirection. In my more recent projects, this is a command + handler for creating something, i.e. CreateNewAccountCommand. An alternatives could be to always use a factory (although that can be awkward if the rest of an entities operation are exposed by a service class that is separate from the factory class).

In general, though, I try to be more flexible with design choices for object creation. new is easy and familiar but not always sufficient. I think using judgement here and allowing different parts of a system to use different strategies as needed is important.

Persistence. ... why not have a Save method on our domain object

This is rarely a good idea; I think there's plenty of shared experience to support that.

If I end up with an IAuthorizationService, IValidator, IFactory and IRepository for my aggregate root, what's left? Is having a Publish method that changes the state of the object from Draft to Published enough to consider the class a non-anemic domain object???

Perhaps a domain model isn't the correct choice for this part of your application.

share|improve this answer
    
"One tricky part that can be encountered is contextual authorization, where a command may or may not be allowed not only based on user roles but also business data/rules." -- And how do you approach this? More times than not, for me at least, our authorization rules are a combination of role and current state. –  SonOfPirate Apr 27 '11 at 19:15
    
@SonOfPirate: event handlers that listen to domain events and update tables that are very specific to the needs of the queries that check authorization. Logic that looks at the state and determines if a role or individual is authorized or not lives in the event handler (so the tables are almost always a simple yes/no, making the auth check a simple lookup). Also, as soon as any of that logic is used in more than one place it gets refactored out of the handler and into a shared service. –  qes Apr 27 '11 at 19:21
1  
In general, over the last few years, I've moved further and further away from trying to consolidate everything into a domain or business object. My experience seems to be that making things more granular and less coupled is a long-term win. So while from one perspective this method is placing business logic outside the domain (to a degree), it also supports agile modifications later. It's all about striking a balance. –  qes Apr 27 '11 at 19:25
    
qes - at an architectural level you may expose a fairly large collection of classes and functionality as a single business object, i.e. through a service. There's nothing stopping you from writing loosely-coupled implementations underneath it. Of course that all calls into question what precisely is the definition of a "domain model" - is it the thing that's inside your application or the thing that you expose to the rest of the world? Fortunately for most developers, they never have to answer those questions because a business object isn't that big or complex, but it happens occasionally. –  Aaronaught Apr 27 '11 at 21:54
3  
Referencing the answer itself here: I've found the State Pattern very useful when dealing with validations that are dependent on both permissions and business rules. Create an abstract state which gets injected into the domain model and exposes methods which take the domain object as a parameter and validate domain-specific actions. This way if your permission rules change (as they almost always do), you never have to mess around with the model to accommodate it, because the state implementations live in your security component. –  Aaronaught Apr 27 '11 at 21:57
show 4 more comments

OK, here goes for me. I'll pre empt this by saying that:

  • Premature optimisation (and that includes design) can often cause problems.

  • IANMF (I am not Martin Fowler) ;)

  • A dirty little secret is that on small sized projects (even arguably medium sized ones), it's the consistency of your approach that will matter.

Authorization

For me Authentication and Authorisation is always a cross cutting concern. In my happy little Java world, that gets delegated to Spring security or the Apache Shiro framework.

Validation For me validation is part of the object, as I see it as defining what the object is.

e.g. A Car object has 4 wheels (OK there are some weird exceptions, but lets ignore the weird 3 wheeled Car for now). A Car simply isn't valid unless it has 4 (in my world), so that validation is part of what the definition of a Car is. That doesn't mean you can't have a helper validation classes.

In my happy Java world I use Bean validation frameworks and use simple annotations on most of my Bean fields. It's easy then to validate your object no matter what layer you're in.

Object Creation

I view Factory classes with caution. Too often I have see the xyxFactoryFactory class ;)

I tend to just create a new object as needed, until I run into a case where Dependency Injection is warranted (and since I try to follow a TDD approach, this does come up more often than not).

In my happy Java world that is increasingly Guice, but of Spring is still the King here.

Persistence

So this a debate that goes on in circles and roundabouts and I'm always in two minds about it.

Some say that if you look at object in a 'pure' way, persistence is not a core property, it's merely an outside concern.

Others take the view that your domain objects implicitly implement a 'persist-able' interface (yeah I know I'm stretching here). Therefore, it's fine to have the various save, delete etc methods on them. This is seen as a pragmatic approach and many ORM technologies (JPA in my happy Java world) deal with objects in this way.

From a cross cutting security concern I make sure that the edit/delete/add/whatever permissions are set correctly on the service that calls the save/update/delete method on the object. If I'm really paranoid I might even set the permissions on the domain object itself.

HTH!

share|improve this answer
add comment

Jimmy Nilsson touches on this topic in his book on DDD. He started with an anemic model, went to non-anemic models on a later project and finally settled on anemic models. His reasoning was that the anemic models could be re-used in multiple services with differing business logic.

The trade off is the lack of discover-ability. The methods you can use to operate on your anemic models are spread throughout a set of services located elsewhere.

share|improve this answer
    
Sounds like a specific requirement - reuse of data (stress 'data') structure - lead to that common part reduced to plain DTOs. –  Victor Sergienko Apr 29 '11 at 11:01
    
Anemic models allow better reuse? Sounds more like a DTO, and I personally don't give a damn about reusing property definitions. I'd much rather reuse behaviors. –  Andy Oct 22 '11 at 1:56
    
@Andy - I would agree however if your behaviors are within Domain Services and they operate on anemic objects (okay DTOs if you wish) then doesn't that increase the reuse of those behaviors? Just playing devil's advocate. –  jpierson Dec 16 '11 at 5:20
    
@jpierson I've found though that the behaviors are typically specific to a particular use case. If there's reuse, that would belong in another class, but the consumer wouldn't use those classes, they'd use the ones specific to the use case. So any reuse is "behind the scenes," so to speak. Additionally, trying to reuse models typically makes the models harder for the consumer to use, so you end up creating view / edit models in the UI layer. Often then you end up violating DRY to give a richer user experience (for example, DataAnnotations of edit models). –  Andy Dec 17 '11 at 1:18
1  
I'd rather domain modles built for the use case, reused where it makes sense (that is, reuse can be done without modifying the behavior much or at all). So instead of anemic domain model, service class and edit model, you have a single smart editable domain model. Much easier to use, and maintain, I've found. –  Andy Dec 17 '11 at 1:20
add comment

None of these, except for partially validation, sounds like a necessary domain model attribute.

Domain logic is a thing that's left when you remove infrastructure (read: computers).

A shop order retains its items, discounts, coupons, parcel's tracking number and so on. It IS persistent, it is created by some actor, it is valid (coupons and discounts either apply or not), it is performed by authorized personnel.

Why would it be anemic?

OK, if a problem statement is a dumb CRUD, it can be - but it's a problem statement itself.

share|improve this answer
add comment

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.