views:

596

answers:

6

Edit: This is not a conflict on the theoretical level but a conflict on an implementation level.

Another Edit: The problem is not having domain models as data-only/DTOs versus richer, more complex object map where Order has OrderItems and some calculateTotal logic. The specific problem is when, for example, that Order needs to grab the latest wholesale prices of the OrderItem from some web service in China (for example). So you have some Spring Service running that allows calls to this PriceQuery service in China. Order has calculateTotal which iterates over every OrderItem, gets the latest price, and adds it to the total.

So how would you ensure that every Order has a reference to this PriceQuery service? How would you restore it upon de-serializations, loading from DBs, and fresh instantiations? This is my exact question.

The easy way would be to pass a reference to the calculateTotal method, but what if your Object uses this service internally throughout its lifetime? What if it's used in 10 methods? It gets messy to pass references around every time.

Another way would be to move calculateTotal out of the Order and into the OrderService, but that breaks OO design and we move towards the old "Transaction Script" way of things.

Original post:

Short version: Rich domain objects require references to many components, but these objects get persisted or serialized, so any references they hold to outside components (Spring beans in this case: services, repositories, anything) are transient and get wiped out. They need to be re-injected when the object is de-serialized or loaded from the DB, but this is extremely ugly and I can't see an elegant way to do it.

Longer version: For a while now I've practiced loose coupling and DI with the help of Spring. It's helped me a lot in keeping things manageable and testable. A while ago, however, I read Domain-Driven Design and some Martin Fowler. As a result, I've been trying to convert my domain models from simple DTOs (usually simple representations of a table row, just data no logic) into a more rich domain model.

As my domain grows and takes on new responsibilities, my domain objects are starting to require some of the beans (services, repositories, components) that I have in my Spring context. This has quickly become a nightmare and one of the most difficult parts of converting to a rich domain design.

Basically there are points where I am manually injecting a reference to the application context into my domain:

  • when object is loaded from Repository or other responsible Entity since the component references are transient and obviously don't get persisted
  • when object is created from Factory since a newly created object lacks the component references
  • when object is de-serialized in a Quartz job or some other place since the transient component references get wiped

First, it's ugly because I'm passing the object an application context reference and expecting it to pull out by name references to the components it needs. This isn't injection, it's direct pulling.

Second, it's ugly code because in all of those mentioned places I need logic for injecting an appContext

Third, it's error prone because I have to remember to inject in all those places for all those objects, which is harder than it sounds.

There has got to be a better way and I'm hoping you can shed some light on it.

A: 

Perhaps what you want is a kind on reference object, that would serialize as a global reference (an URI for instance) and that would be able to resurrect as a proxy when de-serialized elsewhere.

Maurice Perry
A: 

The Identity Map pattern may help with your scenario. Check the article Patterns In Practice written by Jeremy Miller where he discuss about this pattern.

Aleris
+3  A: 

I would venture to say that there are many shades of gray between having an "anemic domain model" and cramming all of your services into your domain objects. And quite often, at least in business domains and in my experience, an object might actually be nothing more than just the data; for example, whenever the operations that can be performed on that particular object depend on multitude of other objects and some localized context, say an address for example.

In my review of the domain-driven literature on the net, I have found a lot of vague ideas and writings, but I was not unable to find a proper, non-trivial example of where the boundaries between methods and operations should lie, and, what's more, how to implement that with current technology stack. So for the purpose of this answer, I will make up a small example to illustrate my points:

Consider the age-old example of Orders and OrderItems. An "anemic" domain model would look something like:

class Order {
    Long orderId;
    Date orderDate;
    Long receivedById;  // user which received the order
 }

 class OrderItem {
     Long orderId;      // order to which this item belongs
     Long productId;    // product id
     BigDecimal amount;
     BigDecimal price;
 }

In my opinion, the point of the domain-driven design is to use classes to better model the relationships between entities. So, an non-anemic model would look something like:

class Order {
   Long orderId;
   Date orderDate;
   User receivedBy;
   Set<OrderItem> items;
}

class OrderItem {
   Order order;
   Product product;
   BigDecimal amount;
   BigDecimal price;
}

Supposedly, you would be using an ORM solution to do the mapping here. In this model, you would be able to write a method such as Order.calculateTotal(), that would sum up all the amount*price for each order item.

So, the model would be rich, in a sense that operations that make sense from a business perspective, like calculateTotal, would be placed in an Order domain object. But, at least in my view, domain-driven design does not mean that the Order should know about your persistence services. That should be done in a separate and independent layer. Persistence operations are not part of the business domain, they are the part of the implementation.

And even in this simple example, there are many pitfalls to consider. Should the entire Product be loaded with each OrderItem? If there is a huge number of order items, and you need a summary report for a huge number of orders, would you be using Java, loading objects in memory and invoking calculateTotal() on each order? Or is an SQL query a much better solution, from every aspect. That is why a decent ORM solution like Hibernate, offers mechanisms for solving precisely these kind of practical problems: lazy-loading with proxies for the former and HQL for the latter. What good would be a theoretically sound model be, if report generation takes ages?

Of course, the entire issue is quite complex, much more that I'm able to write or consider in one sitting. And I'm not speaking from a position of authority, but simple, everyday practice in deploying business apps. Hopefully, you'll get something out of this answer. Feel free to provide some additional details and examples of what you're dealing with...

Edit: Regarding the PriceQuery service, and the example of sending an email after the total has been calculated, I would make a distinction between:

  1. the fact that an email should be sent after price calculation
  2. what part of an order should be sent? (this could also include, say, email templates)
  3. the actual method of sending an email

Furthermore, one has to wonder, is sending of an email an inherent ability of an Order, or yet another thing that can be done with it, like persisting it, serialization to different formats (XML, CSV, Excel) etc.

What I would do, and what I consider a good OOP approach is the following. Define an interface encapsulating operations of preparing and sending an email:

 interface EmailSender {
     public void setSubject(String subject);
     public void addRecipient(String address, RecipientType type);
     public void setMessageBody(String body);
     public void send();
 }

Now, inside Order class, define an operation by which an order "knows" how to send itself as an email, using an email sender:

class Order {
...
    public void sendTotalEmail(EmailSender sender) {
        sender.setSubject("Order " + this.orderId);
        sender.addRecipient(receivedBy.getEmailAddress(), RecipientType.TO);
        sender.addRecipient(receivedBy.getSupervisor().getEmailAddress(), RecipientType.BCC);
        sender.setMessageBody("Order total is: " + calculateTotal());
        sender.send();
    }

Finally, you should have a facade towards your application operations, a point where the actual response to user action happens. In my opinion, this is where you should obtain (by Spring DI) the actual implementations of services. This can, for example, be the Spring MVC Controller class:

public class OrderEmailController extends BaseFormController {
   // injected by Spring
   private OrderManager orderManager;  // persistence
   private EmailSender emailSender;    // actual sending of email

public ModelAndView processFormSubmission(HttpServletRequest request,
                                          HttpServletResponse response, ...) {
    String id = request.getParameter("id");
    Order order = orderManager.getOrder(id);
    order.sendTotalEmail(emailSender);

    return new ModelAndView(...);
}

Here's what you get with this approach:

  1. domain objects don't contain services, they use them
  2. domain objects are decoupled from actual service implementation (e.g. SMTP, sending in separate thread etc.), by the nature of the interface mechanism
  3. services interfaces are generic, reusable, but don't know about any actual domain objects. For example, if order gets an extra field, you need change only the Order class.
  4. you can mock services easily, and test domain objects easily
  5. you can test actual services implementations easily

I don't know if this is by standards of certain gurus, but it a down-to-earth approach that works reasonably well in practice.

javashlook
What you're describing works fine, but I'm hitting walls on more complex examples. What if your Order needs to send out an e-mail every time the total is calculated? Sure you could bring this into your Service, but that's not real OOP, right? Martin F. doesn't even use a Service layer
rcampbell
Please see my "Another Edit". I'd really like to hear your thoughts
rcampbell
+1  A: 

The simplest approach that I can think is to add some logic into your data access layer that will inject a domain object with its dependencies before returning it to a higher layer (usually called the service layer). You could annotate each class's properties to indicate what needs to get wired up. If you're not on Java 5+, you could implement an interface for each component that needs to be injected, or even declare this all in XML and feed that data to the context that will do the wiring. If you wanted to get fancy, you could pull this out into an aspect and apply it globally across your data access layer so all methods that pull out domain objects will wire up them up just after they are returned.

cliff.meyers
Your first suggestion (inject it in DAO) I am doing now, but as I said there are issues with serialization, factories, etc. I _really_ like your suggestion of using an aspect + interface. This would separate out the injection logic and make it cleaner/more manageable...
rcampbell
Dealing with the other two scenarios is challenging. You could instrument the class when it's loaded into the JVM. Basically another AOP approach but very different in terms of implementation. Here's some info about how they do this in Terracotta:http://tinyurl.com/cgx8ne
cliff.meyers
A: 

Regardinig

What if your Order needs to send out an e-mail every time the total is calculated?

I would employ events.
If it has some meaning for you when an order computes its total, let it raise an event as eventDispatcher.raiseEvent(new ComputedTotalEvent(this)).
Then you listen for this type of events, and callback your order as said before to let it format an email template, and you send it.
Your domain objects remains lean, with no knowledge about this your requirement.
In short, split your problem into 2 requirements:
- I want to know when an order computes its total;
- I want to send an email when an order has a (new and different) total;

+1  A: 

I've found the answer, at least for those using Spring:

6.8.1. Using AspectJ to dependency inject domain objects with Spring

rcampbell