2

We are currently having an internal debate on how our business logic classes should be structured. At the moment we structure our business classes like this:

public class OrderBL
{
    public void CreateOrder(OrderDTO order)
    {
        //save order
        //send email
    }

    public void CancelOrder(OrderDTO order)
    {
        //save order
        //send email
    }

    public void MarkOrderAsDispatched(OrderDTO order)
    {
        //save order
        //send email
    }

    //other private methods too
}

Using our current method above we find classes grow very quickly and can become confusing on big projects.

There is some debate as to whether we should change our business classes to look like the below:

public class CreateOrderBL
{
    public void RunLogic(OrderDTO order)
    {
        CreateOrder();
        SendEmail();
    }

    private voide CreateOrder()
    {

    }

    private void SendEmail()
    {

    }
}

The benefit to having this is that classes are easier to understand and are small, however the downside is that the number of classes increase.

What is the correcty way to approach this?

  • Your design violates the open/closed principle. It would be much better to raise an event and let listeners decide what actions should happen (i.e "A record was just saved. I need to send an email now.") – RubberDuck Mar 20 '16 at 15:14
  • @RubberDuck: OCP has to do with inheritance; I don't see any examples of inheritance in the question. – Robert Harvey Mar 20 '16 at 15:41
  • @RobertHarvey OP's design is not closed to modification. In order to add new functionality, the class must be modified. OCP isn't necessarily about inheritance. – RubberDuck Mar 20 '16 at 15:46
  • @RubberDuck: No, not necessarily. But the Wikipedia article states there are two solutions to the OCP problem, both involving inheritance. If you have an article that advocates a different point of view, I'd love to read it; but inheritance isn't really a factor here, and sealing all of your classes by default is a different debate. – Robert Harvey Mar 20 '16 at 15:49
  • No. I'm not talking about sealing classes. At least not in a C# definition of the word. I mean, right now we save and email. Next we need to log, but only under X condition. Then we need to Y under Z condition. Pretty soon we have 60 LoC and 10 responsibilities. Exposing an event would stop that from happening. – RubberDuck Mar 20 '16 at 16:42
4

The "correct" way is the one that most effectively satisfies your application's non-functional requirements for maintainability, performance, etc.

What you need is a Business Logic Layer or Service Layer. These layers translates CRUD methods into actual business operations. Yes, you'll have more classes, but those classes are going to be better organized and have better Separation of Concerns.

I would avoid the wholesale use of Execute() style methods. Group your classes into business aggregates such as OrderProcessing or Shipping, and give your methods meaningful names such as ProcessOrder() (which calls CreateOrder and SendEmail).

  • Thanks for replying. It looks like having lots of small classes is the way to go. You mentioned a business/service layer is needed, would this layer then call the individual classes? e.g. a class called Order would have a Create method, which would then call the CreateOrder and SendEmail class? So UI calls Business/Service layer, which calls the individual classes? – user1786107 Mar 21 '16 at 12:57
0

You are considering moving from a business object oriented model to a business operation/transaction oriented model. Many transactional systems are build on such an approach.

But how will you keep the advantages of object oriented approach ? The challenge will be to to keep track somewhere of the order's internals. And to control the visibility of these internals for the outside world.

So not only will you have an increasing number of classes. But you will as well have a significant increase of interaction between classes, for instance, between the CreatOrderBL and some OrderBL that has to keep the internals and eventually manage the persistance of the object.

Conclusion: By definition you'll increase the complexity of your model. To understand one of the simpler class, you'll need to have a good understanding of all the related classes.

0

"Correct" is subjective and everyone will have their own idea of what "correct" means. In my view, correct means the code works and is easy to maintain and extend. I favor a design pattern that separates workflow, actions, and entities.

In this example, "order" is an entity, and the actions are the things that one can do with the order (CRUD), and the workflow is the business logic that orchestrates the actions to achieve a business result. Ideally, you don't want your business logic to directly manipulate your entity, and only depend on the "action" layer (which knows how to manipulate the entities accordingly).

The reason is because down the road you can reasonably expect that the "order" object will change, for example it might migrate from one database platform to another. Having the business logic divorced from the entity object, you can accommodate changes to the order object without having to overhaul the business logic layer.

Along the same idea, it would be reasonable to design such that your business logic layer never touches anything and always goes through an "adapter" layer. For example, the bits of code that sends the email will need to be revisited if your email system is changed.

Because of these reasons, I favor the second design over the first. In the current (top) design, when the order system and/or email and/or persistence (database) layers change, you have a lot of places to change accordingly in your business logic. This will hamper flexibility in accommodating changes, and increase the complexity required to change the app in response to business requirements.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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