As an Agile Coach, Miško is responsible for teaching his co-workers to maintain the highest level of automated testing culture, allowing frequent releases of applications with high quality. He is very involved in Open Source community and an author of several open source projects. Recently his interest in Test Driven Developement turned into http://TestabilityExplorer.org with which he hopes will change the testing culture of the open source community. Misko is a DZone MVB and is not an employee of DZone and has posted 38 posts at DZone. You can read more from them at their website. View Full User Profile

Design for Testability and "Domain-Driven Design"

03.17.2009
| 6246 views |
  • submit to reddit

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?

Thanks,

Dave Gladfelter

Hope this helps…
From
http://misko.hevery.com/
Published at DZone with permission of Misko Hevery, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Tags:

Comments

Mladen Girazovski replied on Tue, 2009/03/17 - 7:01am

DDD is compatible with design for testability, in fact Eric Evans advocates it as well, the book is just great, imho one of the best books about modelling.

 The piece that is missing here is the "Repository", an abstraction for Database access, similar to the DAO Pattern but without the flaw of having domain logic leaking into the persistence tier. In fact, most people will argue that Repositories are DAOs and the only difference is that they are part of the Domain tier.

In DDD, the entities themselves are talking to the repository and are able to retrieve other entites that they would need, this approach is avoiding procedural programming style known from Spring "Manager"  and EJB SessionBeans where the Domain logic resides inside the Managers/SessionBeans that using DAOs to fill "dumb" POJOs.

Services in DDD (there is two kinds of them in DDD) are just a thin layer on top of the domain tier that represent the border to "the outer world".

 

Daniele Gariboldi replied on Tue, 2009/03/17 - 10:24am

Hibernate persistent objects can be injected using an interceptor. Look here for JPA and Spring and here for pico.
So there's no need to limit ourself about how rich hibernate objects can be. This makes hibernate objects “injectable” according to your naming standard.
There's no problem having references to service objects, as far as you set them as @Transient. As regards to testability, either you use a test db with test entities, or you configure hibernate to employ a xml file based repository or standalone embedded db.
I would stick with the database used in production, otherwise you could get different transactional behaviour and other differences hibernate cannot hide you.
I read this post only, so I could have missed something.

Daniel Delatorr... replied on Wed, 2009/03/18 - 10:26am

"In DDD, the entities themselves are talking to the repository and are able to retrieve other entites that they would need"

Are you sure of that?I'm not very familiar with DDD, but I was sure that the entities had no knowledge of the repository.

Mladen Girazovski replied on Thu, 2009/03/19 - 4:50am in response to: Daniel Delatorre Vanzin

Are you sure of that?I'm not very familiar with DDD, but I was sure that the entities had no knowledge of the repository. 

Yes, that's one of the important aspects  of repositories that let you model your domain in an OO way instead of the procedural way.


 

Daniel Manchester replied on Thu, 2009/03/19 - 9:07am in response to: Mladen Girazovski

Yeah, it can feel "wrong" to have entities that rely on repositories, but if you're doing domain-driven design, it's sometimes unavoidable.

Chris Richardson's book, "POJOs in Action", which nicely lays DDD on to the Java space, has a discussion of this. (For those who have a copy, see page 88, the "Options for accessing a repository" discussion under "Implementing a domain entity method".) He lays out the example of an entity modeling a food delivery order. The entity includes a public method for updating the order's delivery address and time. Rathering than blindly making the update, the method needs to ensure that a restaurant is available that can handle the update, and to do that, the method (and therefore the entity) must rely on the repository for restaurants.

It's a separate question of how an entity method's need for a repository is satisfied. Chris also discusses possible solutions to that. In the above example, he opts to pass the repository as a method parameter.

Mladen Girazovski replied on Thu, 2009/03/19 - 9:30am

 Yeah, it can feel "wrong" to have entities that rely on repositories, but if you're doing domain-driven design, it's sometimes unavoidable.

With DDD it is completely normal that Entities access Repositories, "sometimes unavoidable" sounds like it would be a problem, but instead it is the whole point about repositories.

 

 

 

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.