8

First of all, I'm not asking where does business logic belong. This has been asked before and most answers I've read agree in that it belongs in the model:

Where to put business logic in MVC design?
How much business logic should be allowed to exist in the controller layer?
How accurate is "Business logic should be in a service, not in a model"?
Why put the business logic in the model? What happens when I have multiple types of storage?

However people disagree in the way this logic should be distributed across classes. There seem to exist three major currents of thought:

  1. Fat model with business logic inside entity classes.
  2. Anemic model and business logic in "Service" classes.
  3. It depends.

I find all of them problematic.

The first option is what most Fowlerites stick to. The problem with a fat model is that sometimes a business logic funtion is not only related to a class, and instead uses a bunch of other classes. If, for example, we are developing a web store, there should be a function that calcs an order's total. We could think of putting this function inside the Order class, but what actually happens is that the logic needs to use different classes, not only data contained in the Order class, but also in the User class, the Session class, and maybe the Tax class, Country class, or Giftcard, Payment, etc. Some of these classes could be composed inside the Order class, but some others not. Sorry if the example is not very good, but I hope you understand what I mean. Putting such a function inside the Order class would break the single responsibility principle, adding unnecesary dependences. The business logic would be scattered across entity classes, making it hard to find.

The second option is the one I usually follow, but after many projects I'm still in doubt about how to name the class or classes holding the business logic. In my company we usually develop apps with offline capabilities. The user is able to perform entire transactions offline, so all validation and business rules should be implemented in the client, and then there's usually a background thread that syncs with the server. So we usually have the following classes/packages in every project:

  • Data model (DTOs)
  • Data Access Layer (Persistence)
  • Web Services layer (Usually one class per WS, and one method per WS method).

Now for the business logic, what is the standard approach? A single class holding all the logic? Multiple classes? (if so, what criteria is used to distribute the logic across them?). And how should we name them? FooManager? FooService? (I know the last one is common, but in our case it is bad naming because the WS layer usually has classes named FooWebService).

The third option is probably the right one, but it is also devoid of any useful info.

To sum up:

  • I don't like the first approach, but I accept that I might have been unable to fully understand the Zen of it. So if you advocate for fat models as the only and universal solution you are welcome to post links explaining how to do it the right way.
  • I'd like to know what is the standard design and naming conventions for the second approach in OO languages. Class names and package structure, in particular. It would also be helpful too if you could include links to Open Source projects showing how it is done.

Thanks in advance.

1 Answer 1

6

I think you got Fowler wrong, he is advocating 3, not 1 (see http://www.martinfowler.com/bliki/AnemicDomainModel.html). Note that he is not talking about "business logic inside entity classes", he is talking about "business logic inside domain classes". And Service objects are domain objects.

In your example above: if you need to calculate the orders total, why not create a service class "OrderTotalCalculator"? Name the class accordingly for its purpose (and not OrderService or OrderManager, which would actually hide the purpose).

You already mentioned one criteria by yourself for when to introduce such a service class, and when business logic can stick inside entities: when "a bunch of other classes" is involved, then placing the logic in a specific entity is probably not the best design. You also mentioned the single-responsibility principle, so let yourself guide by this.

However, this does not necessarily lead to option 2 - since to my experience there are typically enough business operations for which an entity can take the full responsibility for itself, without introducing an extra service class for every operation. This will typically lead to a lean (but not anemic) entity classes.

The third option is probably the right one, but it is also devoid of any useful info.

Yes, it is probably the right one, but what do you mean by "is devoid of any useful info"? Do you miss an instructions manual on this? Software development is a design process, not like working at an assembly line. So making the right design decisions is not always easy and needs a lot of experience. And naming things is actually one of the hardest tasks.

7
  • So you'd create a dedicated OrderTotalCalculator class stateless and with only one method. I like the naming, but if we create a class per domain operation needed, wont they proliferate and became hard to find? Would you consider merging this class with all the different OrderXXXOperation classes? If so, how would you name it? And finally, would you put those classes in the same package as the entity classes? Aug 20, 2014 at 9:40
  • 1
    @MisterSmith: with only one public method (but probably many private methods if it is a complex operation). And I explicitly wrote not to introduce an extra service class for any operation, only for operations which cannot be placed into an existing entity without violating SRP.
    – Doc Brown
    Aug 20, 2014 at 11:17
  • On how to package service objects: this depends on how big your application is in general, which levels of abstractions make sense in your specific case and how your business cases are structured on a higher level of abstraction than the "class level". There is no "one size fits all" solution. For a small application, putting the service objects into the same package as the entity classes may be ok. For a bigger application, it may make more sense to create separate packages.
    – Doc Brown
    Aug 20, 2014 at 11:25
  • My suggestion is not to plan this too much ahead upfront, better start with just one package, and whenever you have implemented a bunch of classes for which you feel they could be better grouped into a separate package, do it.
    – Doc Brown
    Aug 20, 2014 at 11:29
  • 1
    @MisterSmith: when you put 10 unrelated public methods (each with 5 to 10 related additional private methods) into one single class, the result is definitely not a class with "one single responsibility"). And it does not matter if the class you use is an entity class like "Order", or a separate service class like "OrderService".
    – Doc Brown
    Aug 20, 2014 at 12:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.