4

I have business logic that could either sit in a business logic/service layer or be added to new members of an extended domain class (EF T4 generated POCO) that exploits the partial class feature.

So I could have:

a) bool OrderBusiness.OrderCanBeCancelledOnline(Order order) .. or (IOrder order)

or

b) bool order.CanBeCancelledOnline() .. i.e. it is the order itself knows whether or not it can be cancelled.

For me option b) is more OO. However option a) allows more complex logic to be applied e.g. using other domain objects or services.

At the moment I have a mix of both and this doesn't seem elegant.

Any guidance on this would be much appreciated!

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Mark Chidlow
  • 1,432
  • 2
  • 24
  • 43

4 Answers4

6

The key thing about OO for me is that you tell objects to do things for you. You don't pull attributes out and make the decisions yourself (in a helper class or other).

So I agree with your assertion about option b). Since you require additional logic, there's no harm in performing an operation on the object whilst passing references to additional helper objects such that they collaborate. Whether you do this at the time of the operation itself, or pre-populate your order object with those collaborating entities is very much dependent upon your current situation.

Brian Agnew
  • 268,207
  • 37
  • 334
  • 440
  • Thanks Brian. Just to clarify the example I gave 'CanBeCancelledOnline' might be a requirement to enable/disable a 'cancel order' button on a form - so in this case I do need to 'pull attributes out and make the decisions yourself' (which I would argue does not go against the OO paradigm in many cases). – Mark Chidlow Oct 03 '10 at 11:35
  • ... Let us say (for example only) that for an order to determine whether it can be cancelled or not, it needs to know something about a customer contract. Again two options. a) an OrderBusiness class uses information (or logic) from both an Order and a Contract to determine whether the order can be cancelled. Or b) I implement order.CanBeCancelledOnline(Contract contract) and the logic remains in the Order class. I presume you would lean toward b) as the best approach? – Mark Chidlow Oct 03 '10 at 11:46
  • If the order is related to a customer contract, then perhaps it has a reference to that contract implictly. So that's a third option (and the one I would prefer if valid) – Brian Agnew Oct 03 '10 at 11:48
  • Yes I guessed you might say that! If however - for the sake of this discussion - that there was no way of obtaining the Contract from the Order object would you still prefer option b)? – Mark Chidlow Oct 03 '10 at 11:56
  • 1
    Yes. Absolutely. The intelligence is still in the Order object. – Brian Agnew Oct 03 '10 at 16:16
2

This is likely to depend on the complexity of your application and does require some judgement that comes with experience. The short answer is that if your project is anything more than a pretty simple one then you are best off putting your logic in the domain classes.

The longer answer:

If you place your logic within a service layer you are affectively following the transaction script pattern, and ending up with an anaemic domain model. This can be a valid route, but it generally works best with simple and small projects. The problem is that the transaction script layer (your service layer) becomes more complicated to maintain as it grows.

So the alternative is to create a rich domain model that contains the logic within it. Keeping logic together with the class it applies to is a key part of good OO design, and in a complex project pretty essential. It usually requires a bit more thought and effort initially, which is why for very simple projects people sometimes use the transaction script pattern.

If you are unsure about which to go with it is not normally a too difficult job to refactor your logic to move it from your service layer to the domain, but you need to make the call early enough that the job is not too large.

Contrary to one of the answers, using POCO classes does not mean you can't have business logic in your domain classes. POCO is about not applying framework specific structures to your domain classes, such as methods and interfaces specific to a particular ORM. A class with some functions to apply business logic is clearly still a Plain-Old-CLR-Object.

Co7e
  • 1,008
  • 10
  • 17
2

You can also use extension methods to the POCO's to wrap your bll methods. So you can keep using your current bll's. in c# something like:

public static class OrderBusiness <- everything must be static, class and method
{
  public static bool CanBeCancelledOnline(this Order order) <- notice the 'this'
  {
    logic ...

And now you can do order.CanBeCancelledOnline()

Aralmo
  • 21
  • 1
0

A common question, and one that is partially subjective.

IMO, you should go with Option A.

POCO's should be exactly that, "plain-old-CLR" objects. If you start applying business logic to them, they cease to be POCO's. :)

You can certainly put your business logic in the same assembly as your POCO's, just don't add methods directly to them, create helper classes to facilitate business rules. The only thing your POCO's should have is properties mapping to your domain model.

Really depends on how complex your business rules are. In our application, the busines rules are very straightforward, so we use Option A.

But if your business rules start to get messy, consider using the Specification Pattern.

RPM1984
  • 72,246
  • 58
  • 225
  • 350
  • Thanks. I have read about the 'Anemic Domain Model' which seems to be what you are proposing. I have to say this seems to go against my OO background but I can understand whay you might want to keep the POCOs clean in this way. – Mark Chidlow Oct 03 '10 at 11:51
  • 3
    Sorry but the statement that [POCOs](http://en.wikipedia.org/wiki/POCO) shouldn't contain business logic is completely wrong. They can and usually do contain behaviour and logic, what they shouldn't include is framework specific elements such as ORM specific base classes. What you seem to be describing almost seems like a DTO: [DTO vs POCO](http://stackoverflow.com/questions/725348/poco-vs-dto). – Co7e Jul 29 '13 at 15:59
  • @Steve - you're 100% correct. It's funny coming back to answers i gave a long time ago. :) – RPM1984 Jul 30 '13 at 21:27