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.

We're trying to move data from our bloated Service layer into our Domain layer using a DDD approach. We currently have a lot of business logic in our services, which is spread out all over the place and doesn't benefit from inheritance.

We have a central Domain class which is the focus of most of our work - a Trade. The Trade object will know how to price itself, how to estimate risk, validate itself, etc. We can then replace conditionals with polymorphism. Eg: SimpleTrade will price itself one way, but ComplexTrade will price itself another.

However, we are worried that this will bloat the Trade class(s). It really should be in charge of its own processing but the class size is going to increase exponentially as more features are added.

So we have choices:

  1. Put processing logic in Trade class. Processing logic is now polymorphic based on the type of the trade, but Trade class is now has multiple responsibilites (pricing, risk, etc) and is large
  2. Put processing logic into other class such as TradePricingService. No longer polymorphic with the Trade inheritance tree, but classes are smaller and easier to test.

What would be the suggested approach?

share|improve this question

migrated from stackoverflow.com Nov 22 '11 at 22:19

This question came from our site for professional and enthusiast programmers.

    
No problem - I'm happy to accept migration! –  djcredo Nov 22 '11 at 11:53
1  
Beware of the reverse: martinfowler.com/bliki/AnemicDomainModel.html –  TrueWill Nov 22 '11 at 19:52
1  
"the class size is going to increase exponentially as more features are added" - any programmer should know better than to misuse the word "exponentially" like that. –  Michael Borgwardt Nov 23 '11 at 12:56
    
@Piskvor that's just stupid –  Arnis L. Nov 30 '11 at 9:04
    
@Arnis L.: Thank you for your thoughtful comment. Note that this was, quote, "migrated from stackoverflow.com Nov 22 at 22:19", together with my comment thence. I have now removed my comment that "this would be better off at programmers.SE"; now, do you have anything to add, or was that the only idea you wanted to express? –  Piskvor Nov 30 '11 at 12:27

4 Answers 4

up vote 8 down vote accepted

If you're going Domain Driven, consider treating your Trade class as an aggregate root and break its responsibilities out into other classes.

You don't want to end up with a Trade subclass for each combination of price and risk, so a Trade may contain Price and Risk objects (composition). The Price and Risk objects do the actual calculations, but aren't visible to any class except Trade. You get to reduce the size of Trade, while not exposing your new classes to the outside world.

Try to use composition to avoid large inheritance trees. Too much inheritance can lead to situations where you try to shoehorn in behaviour that doesn't really fit the model. It's better to pull those responsibilities out into a new class.

share|improve this answer
    
I agree. Thinking of objects in terms of behaviors that form the solution (Pricing, RiskAssessment) rather than trying to model the problem avoids these monolithic classes. –  Garrett Hall Nov 22 '11 at 20:26
    
Also agree. Composition, lots of smaller classes with specific, single responsibilities, limited use of private methods, lots of happy interfaces, etc. –  Ian Nov 23 '11 at 13:32

Your question definitely makes me think of the Strategy Pattern. Then you can swap in various trading/pricing strategies, similar to what you're calling a TradePricingService.

I definitely think the advice you'll get here is to use composition instead of inheritance.

share|improve this answer

One possible solution I have used in a similar case, is the adapter design pattern (the referenced page contains lots of sample code). Possibly in combination with the delegation design pattern for easy access to the main methods.

Basically, you divide the Trader functionality into a number of disjunct areas - e.g. handling of prices, risks, validation all could be different areas. For each area, you can then implement a separate class hierarchy that handles that exact functionality in the different needed variants - all the a common interface for each area. The main Trader class is then reduced to the most basic data and references to a number of handler objects, that can be constructed when needed. Like

interface IPriceCalculator {
  double getPrice(ITrader t);
}
interface ITrader {
  IPriceCalculator getPriceCalculator();
}
class Tracer implements ITrader {
  private IPriceCalculator myPriceCalculator = null;
  IPriceCalculator getPriceCalculator() {
    if (myPriceCalculator == null)
      myPriceCalculator = PriceCalculatorFactory.get(this);
    return myPriceCalculator;
  }
}

One major advantage to this approach, is that the possible combinations of e.g. prices and ricks are completely separated and can thus be combined as needed. This is rather difficult with the single-threaded inheritance of most programming languages. The decision of which combination to use can even be calculated very late :-)

I usually try to keep the adapter classes - e.g. the sub-classes of IPriceCalculator above - stateless. I.e. these classes should not contain any local data if possible, to reduce the number of instances that has to be created. So I usually provide the main adapted object as an argument in all methods - like in getPrice(ITrader) above.

share|improve this answer

can't say much about your domain, but

We have a central Domain class which is the focus of most of our work - a Trade.

... it's a smell to me. I'd probably try to sketch the different responsibilities of the class and eventually decompose it to different aggregates. Aggregates would then be designed around roles and/or points of view of the stakeholders/domain experts involved. If Price and Risk are involved in the same behavior/use case, they'd probably belong to the same aggregate. But if they're decoupled they maybe belong to separate aggregates.

Maybe RiskEvaluation might be a separate entity in your domain, eventually with a specific lifecycle (I can't really say, I am merely speculating ...you know your domain, I don't), but the key is to make implicit concepts explicit and to avoid coupling that's not driven by behavior, but only by legacy data coupling.

In general, I'd think about the expected behavior, and the different life cycles of the components involved. Just adding behavior on top of grouped data creates bloated objects. But the data has been grouped according do an existing data-driven design, so there's no need to stick to that.

share|improve this answer

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.