Design for Testability and “Domain-Driven Design”

March 16th, 2009 · 5 Comments ·

Dave Gladfelter has written a great question which I think a lot of people may be asking an therefore I am sharing the letter with the answers here…

Misko,Thanks for all your interesting posts on testability.  I’ve been using DI and other techniques for some time for both testability and for maintainability and readability, but you’ve helped me understand some subtleties that I think will really help me write better code.

I have a question about your distinction between “newable”, value classes and “injectable” or “service” classes.

Domain-Driven_Design by Eric Evans divides classes/objects into basically 3 categories, SERVICE objects, ENTITY objects and VALUE OBJECTS.  VALUE OBJECTS are leaf classes like string classes and are obviously “newable”.  SERVICES represent external infrastructure, they don’t model domain state, and they tend to be singletons.  This makes them very similar to injectable objects.  My main concern is with ENTITY objects.  ENTITY objects in Eric’s methodology represent domain concepts that have specific lifetimes and identity.  Eric is primarily focused on enterprise/database style applications where the primary concern is data integrity, so the concept of the ENTITY is key to his modeling technique.

I have not read his book, so don’t take my comments as authority. Entity objects to me are newables, sort off.. First off they ore not injectable since you can’t say injector.getInstance(CreditCard.class). the injector simply does not have enough information to create one (Specifically, it is missing the ID). But you could say injector.getInstance(HibernateSession.class).get(CreditCard.class, 123). This will fetch the factory, which will fetch the CreditCard from the database by ID. Now to keep to things testable, I want to make sure that I can create CreditCard in my test without a database. So in my test it will be important that I can say new CreditCard(), otherwise I will have to constantly inject mocks into the credit card processor in my tests. Further more, if you are using ORM layer such as Hibernate, hibernate can’t inject anything into the CreditCard and it will try to persist any services on it. The reason I say sort of, is because in my code i will not just new one up, i will fetch it from the factory, but that is not the same as fully injectable.
The domains I’m working in at present are more functional / operational and aren’t concerned with identity, so I haven’t had an opportunity to put Eric’s methodology through the wringer yet to see what leaks out.  After reading your articles I am now confused about how to fit ENTITY’s into the compelling design-for-test methodology you’re advocating.

In your post “Writing Testable Code”, you say that a CreditCard class would tend to be a value object.  In Eric Evan’s methodology, I would think it would be an ENTITY.  I get the impression you advocate using value objects to hold domain data.  This would make maintaining domain-dictated identity and lifetimes hard, since value objects are newable, often copyable, and generally not too concerned with lifetime or identity.

Whether you call it Value or Entity, I think is irrelevant to the point I am trying to make. The CreditCard is an Entity since it has on ID and is persistable, but it is not a service. My definition of newable simply accounts for anything which is not a injectable hence a  service, Entities included.
I get the impression you are okay with treating domain data as dumb data which service objects manipulate based on the application domain logic.  In my mind, this creates an impedance mismatch between the object hierarchy and the domain under modeling.  I’ve always thought it a good rule of thumb to place an operation on the class whose state is most queried/modified by the operation.  In the case of processing a credit card transaction, it would be the credit card that is most affected by the transaction, not the credit card transaction processor service, and it would therefore be natural to place the operation on the credit card object.  The card would still need to collaborate with such a service for aspect-oriented binding for services such as fraud prevention, but it would be the credit card’s responsibility to form the messages and operations that comprise a credit card transaction and to pass them to the appropriate players.
I agree that the method should have affinity to the class which is most affected by it, in this case it would be CreditCard. But here is the real question of testability. If the method ‘charge’ is on CreditCard, how does it get a hold of CreditCardProcessor? Globals/Singletons are out of the questions, which leaves us with constructor or a parameter on the charge method. Constructor is out since that would interfere with the persistence layer (Hibernate would either try to persist the CreditCardProcessor or it will not be able to instantiate a new one from the database.) This leaves us with charge method taking a parameter to CreditCardProcessor. If you do that than you are all set form the testability point of view and you can have your business logic on the domain/entity/value class. The important thing to remember is that CreditCard can not have a field reference (it can only have a stack reference) to any services since that will interfere with the serialization / de-serialization process. It is not as important as where the charge method lives as which instance has reference to which other instances. Again, CreditCard can not have a field reference to CreditCardProcessor or it will interfere with persistent layer.
So, if I understand Eric’s approach properly and if he were trying to design for testability as well, I think he would advocate creating the credit card with a factory that would tie it to whatever services its various methods would need, and internal fields would be set during construction-time in the factory.  The credit card would then use internal logic to determine what messages to send to the services to respond to application requests (Charge transaction, generate monthly late notice batch script, etc.)
I would be against this approach as it would give CreditCard field reference to CreditCardProcessor as pointed out above and would require to write a custom factory for each persistable entity, the factory would than have to inject additional fields. I prefer hibernate approach where hibernate setter injects the state to CreditCard and persist all of the fields. Having both persistable and non-persistable fields smells of mixing of concerns. It is not the responsibility of CreditCard to know about the CreditCardProcessor. As a matter of fact I can imagine lots of scenarios where I have different CreditCardProcessor instances. Lets say you have online and offline CreditCardProcessor and at runtime you want to chose one depending on the availability of internet connection. Having the CreditCard know about the CreditCardProcessor would be a liability.
If I understand your methodology, there would be several global credit card servicing objects with the business logic for the various operations, and the application would pass dumb value objects to those services as needed to fulfill requests.
I never said dumb. OO says that behavior should live with the data. In this case it is perfectly fine to have the behavior of charging on the data (CreditCard) just make sure that CreditCardProcessor reference comes from the stack. But lets go to a real world for a second. Have you ever seen a CreditCard which knew how to charge itself? I have not. But I have seen a lot of CreditCardProcessors which when you punched in amount and slide the card through have made me poorer. So perhaps the charge should be with the service. :-) From a testability it makes no difference thought.
Now, imagine one logical credit card operation required several orthogonal services to complete.  Where would the business logic for that operation live?  Would there be yet another service object responsible for coordinating subordinate service objects?  What if one of the operations failed and the transaction needs to be rolled back.  Who is responsible for coordinating this?  Following Eric Evan’s methodology, the credit card would have all the information and logic needed to keep track of these higher-level concerns and would use the services as needed to create a valid application state even in the face of failures (the strong exception guarantee.)  The credit card would not allow multiple simultaneous operations to create a race condition in multithreaded environments because it would be simple to add locking to the operations on the credit card class.  In the test-driven model you describe, who would be responsible for detecting multiple simultaneous operations on the same card?   If a service had to do it, then it would have to maintain internal state corresponding to all the active credit cards in the system to detect such conditions, which would be duplicative and would decrease data coherence in the system.  You couldn’t put locking on the value-object-CreditCard class because it could have been copied (or deserialized multiple times) and therefore there would be no connection between the domain concept of serialization of transactions and the behavior of multiple credit card value objects with their own mutexes.
I have always let Hibernate deal with these issues. I fees strongly that CreditCard should be unaware about transactions, locks, etc. Look in your wallet, does your CreditCard know about any of these? Yet our financial system works just fine, (well maybe not if you read the news, but it is not for lack of transactions.) Hibernate solves your problem very simply. It creates two copies of the CreditCards. One for itself (private) and one for you (public). The CreditCard has an additional field version which Hibernate uses for locks. When hibernate commits it compares public and private versions to see if anything is dirty, if it is it than compares the version number with the one in the database. If versions match, than the version is incremented and data is committed, your public copy becomes stale (versions don’t match) and you need nod worry about someone keeping a reference to it accidently across the transactions. If versions do not match the database is rolledback and exception is thrown.
If you place all of these responsibilities onto the CreditCard, the system will be hard to test, not because you violated some injectable vs new rule, but because you violated single responsibility principle and you will be in mocking hell trying to instantiate it.
Are you familiar with this book?  Do you see its design methodology as being compatible with design for testability?  If so, how do you map the concepts in the two methodologies?


Dave Gladfelter

Hope this helps…
A day later I got a response form dave which I think is worth sharing…
Hi Misko,

Sorry in advance for another long message.  There aren’t any questions in it, and it is purely for your benefit, so feel free to read it whenever or never.  I’ve been thinking about your comments and I reviewed some key sections of Evan’s book.  I think there is not as much of a conflict as I thought.  It is remarkable to me that the testable design methodology and the domain-driven design methodology are so compatible since they serve somewhat differing goals.

Anyway, I think I got hung up on “newable” as meaning “value object”.  Entities need to be aware of their external, long-lived identities, but I think it is okay for the purposes of testability to make them newable.  I think it would be bad for anyone other than a “repository” (Eric’s term for a persistent-storage-backed factory) to create a credit card object.  Except during testing!  ;-)

Also, Eric does anticipate that some services will peform purely domain operations.  He agrees with you that keeping the set of operations on entities relatively uncluttered is crucial.  Some domain operations are simply defined by a set of procedural business rules, and they belong in a stateless service.

I was initially confused at how newable entities would get re-serialized.  At first, it seemed to me, since one doesn’t want (usually domain-state-free) services holding references to domain objects, and one doesn’t want domain objects holding references to services, that the only way to commit a transaction would be to have a method call that spans every transaction.

If an entity becomes unreachable from all threads in the process, then it will be unable to commit because it will not have access to its repository and there is no other object that can give it access to the repository, since no object has a reference to it other than the GC.  This means that for a testable, domain-driven system, either:

1. All “write” operations need to occur within the context of at least one, continuous thread of execution.
2. There must be some injectable service that needs to hold references to domain objects that are in-use.

The first choice is not scalable and the second choice violates the literal definition of Eric Evan’s definition of a SERVICE (“A SERVICE is an operation offered as an interface that stands alone in the model, without encapsulating state, as ENTITIES and VALUE OBJECTS do.”). However, since moving transaction state from the stack to the heap is arguably just a change in execution strategy for performance reasons, I guess I could argue that the spirit of Evan’s methodology is not violated because a service that holds suspended / waiting transactions could arguably be said to simply be executing those transactions temporarily off-thread. Modern OO libraries even have such services pre-defined for just this purpose.

Anyway, thanks for your help, After hearing from you and thinking a bit more about this, I think the two techniques actually match up incredibly well.  I do recommend the book if you get a chance, and I would look forward to reading about your thoughts on it in your blog posts.


Dave Gladfelter

Tags: Uncategorized

5 responses so far ↓

  • Igor Brejc // Mar 17, 2009 at 12:11 am

    Miško,This is a very interesting topic, which I was raising in my head ever since I read Martin Fowler’s post about anemic domain models ( – this got me into DDD area, so I started reading Eric’s book (I’m halfway through it). What’s your opinion about anemic domain models? BTW I’m not sure relying on a specific technology (like Hibernate) helps the discussion. I come from the .NET sphere and I (usually) do not use NHibernate for DB persistence. But I still want to be able to understand the implications of using either Eric’s DDD approach or some alternatives.

  • » Fresh Catch For March 17th // Mar 17, 2009 at 4:04 am

    [...] Design for Testability and “Domain-Driven Design” [...]

  • misko // Mar 17, 2009 at 6:55 am

    @Igor, After reading I agree with Fowler, your objects should have appropriate behavior on them. As he puts it “The logic that should be in a domain object is domain logic – validations, calculations, business rules – whatever you like to call it.” The point I am trying to make is that it is not where the behavior is, but rather how this behavior gets a hold of its collaborators. What if your DomainModel is an Invoice and the calculation behavior need to get a hold of TaxTable to do the job. How should the Invoice get a hold of TaxTable? Here my point is that the TaxTable should not be a field of DomainModel, therefor TaxTable can not be constructor injected.

  • Igor Brejc // Mar 17, 2009 at 2:19 pm

    @Miško, I guess it depends on the nature of the behavior (and the domain it tries to describe) – sometimes it is appropriate to put that kind of domain logic into an Invoice object. Sometimes a separate service or strategy pattern is more suitable. As for your reservations about having non-persistable fields, I would say the best way would be to hide the domain from the persistance technology (like Hibernate) through some kind of factories and repositories. Then you wouldn’t have to worry how these fields get filled (at least not from the domain point of view).In the case of invoicing (of which I’m not an expert): maybe a ITaxation service which would accept Invoices as arguments in the Tax method would be a solution? In that case an Invoice would not care about the tax table in the first place.

  • David Stull // Sep 23, 2009 at 6:00 pm

    Misko, I really enjoy your articles. I have learned a lot. This post deals with some questions that I had thought a small, but complete sample app would be very helpful to clarify. Any interest in providing one?

Leave a Comment