{ by david linsin }

January 12, 2009

Technical and Business Aspects in one Domain Model

We recently had a discussion at work about mixing technical and business aspects in your domain model. In the following post, I want to elaborate on why we had this argument, how we solved it and what conclusion I drew from this discussion.

In our domain model we have a Customer class, which has multiple Contracts. In order to keep it simple let's say the Customer class has a member called contracts of type Collection.

uml_cust_contract.png

Our application is an Eclipse RCP client with a Java EE backend. In order to support the "Eclipse way", we allow the user of our application to modify multiple contracts of a customer and save those in one batch. Since those Contract instances only live within the context of a Customer, we pass the Customer instance for persistent storage to the server-side and that's where the fun begins.

Customer alfons = customerService.getFromServer("alfons");
Collection<Contract> contracts = alfons.getContracts();
for(Contract c : contracts) {
c.setEndDate(today);
}
contracts.add(newContract);
customerService.saveToServer(alfons);


Usually this is straight forward. You would leave it to Hibernate or some other O/R mapper to save those changes for you. It's no problem for Hibernate's proxy-collection to keep track of what happened. The framework can write those changes for you to a persistence storage of your choice. However, what if you want to know about those changes?

Well as you might assume, we do want to know about the changes made on client side. We need to process and send each modiefied Contract instance individually to an external backend-system. Thus we had the choice to either piggybacks the Hibernate proxy-collection somehow or come up with a design, which supports tracking those changes. We decided to do the latter and frankly, I'm not too sure if it was the right decision.

My idea was very straightforward: we designed an API for the Customer class, which allows transparent changes to Contracts. Transparent in the sense that the client of the API doesn't know what happens behind the scenes. This way we could push the responsibility for keeping track of changed Contract instances to the Customer implementation.

Customer alfons = customerService.getFromServer("alfons");
Collection<Contract> contracts = alfons.getContracts();
for(Contract c : contracts) {
c.setEndDate(today);
alfons.addContract(c);
}
alfons.add(newContract);
customerService.saveToServer(alfons);


So I added a Customer.addContract method and Customer.getContracts would return a immutable Collection. The client now works explicitly with a Contract instance and adds it to the Customer, after it was modified. In the Customer.addContract method changes are being tracked with a separate Collection. This very decision, using another Collection to track the change set, caused an argument of whether it is a technical detail and thus shouldn't be part of the Customer class.

public class Customer {
private Collection<Contract> contracts;
// tracks changes to contracts
private Collection<Contract> contractsChangeSet;

...
}


I do agree that the change set is a technical detail of how Customer organizes its Contract instances. However, I argue that it is hidden behind an API, which doesn't cause any overhead for the client. It might not be a very clean solution, but from an API point of view, I think it's a reasonable design.

You could argue that the implementation is rather pragmatic. I could have used something like AOP to track changes instead of doing it manually. However, I think from a maintenance point of view the implementation is easy to handle. Even using the Customer class in a context where no change set is necessary would work.

Since we all agree, that mixing responsibilities is evil, I'm asking myself when is it okay to compromise and when should you strive for a better solution? Consulting Domain Driven Design, which usually enlightens me on such topics, I couldn't find anything related to this problem. As I mentioned before, I'm not quite sure anymore, if this solution is the best way to tackle this particular problem.

Maybe I should take a step back and look at this in a more general way: when is something technical and when is it related to business?

2 comments:

Anonymous said...

Well, in a 3-tier archtitecture one could consider client side objects as local copies or cached objects. Instead of directing each and every single access to an objects attribute back to the server (and further to the database), which would of course ruin performance, you keep a cached copy of the objects in the client.

This in mind it's straightforward that you need all the fancy operations caches have like flushing, re-synchronisation, dirty-management, conflict management etc).

Of course this is a pure technical aspect of your domain model, but well, that's life. So are equals(), hashCode() and some more fun stuff like handling data differently client side vs. server side (read: without or within a hibernate session).

To give a general answer to your question "when is something technical and when is it related to business": It's technical when it's related to the architecture (3-tier), the frameworks (hibernate, eclipse) or the programming language. It's related to business when you have this problem no matter which kind of implementation you would use, even if it were done in a 2-tier access based VBA application :-)

Kendrick Brown said...

Great reead thankyou


com_channels

  • mail(dlinsin@gmail.com)
  • jabber(dlinsin@gmail.com)
  • skype(dlinsin)

recent_postings

loading...