0

I have two panels, one for the admins and the other for partners. And there are two OrderController with Admin\OrderController and Partner\OrderController namespaces.

They both look very similar. What is the best way to avoid duplicate code in two controllers.

They have two parts, the first part in authorising and validating the input, and the second part is doing the logic like storing the order. the second part is the duplicate code. So what about using trait with an inner method like _store()

  • Are they similar enough for method templating? Or are they similar enough to make the differences parametrizable via configuration? – Laiv May 29 at 8:02
  • @Laiv Tahnks. They have two parts, the first part in authorising and validating the input, and the second part is doing the logic like storing the order. the second part is the duplicate code. So what about using trait with an inner method like _store() – Pouneh May 29 at 8:16
2

While I think @Christophe's answer is the simplest solution (and simplicity often prevails over everything else), I think there is, at least, one more alternative.

If OrderController is basically the same for all three contexts but for some specific behaviour, I would evaluate the possibility to make these specific behaviours parametrizable. In other words, make OrderController configurable so that I have only one Controller and N different configurations. In runtime, this's translated into 3 different instances of OrderController each of which with its own configuration.

If at some point, any of the contexts diverge so that the convention over configuration is not possible, we are still in time to extend the controller and implement a dedicated one. Or not extend it at all.

It's worth saying that polymorphism (or inheritance) is usually more coupling and constraining than composition.


They have two parts, the first part in authorising and validating the input, and the second part is doing the logic like storing the order. the second part is the duplicate code.

Controllers, ideally, have very little logic to override. Extending a super controller should result in 3 classes with almost no differences, so why not encapsulate the differences in components and make the controller configurable?

On one hand, validations and security are cross-cutting features that can be decoupled from controllers. On the other hand, business logic must be encapsulated in different components.

  • In view if the edited question, the suggestion for the component is excellent ! – Christophe May 29 at 11:46
  • And to sum up this answer: Move the common code into other classes, be they "service" classes, validators or "use case" classes. Separation of Concerns and favor composition over inheritance are applicable here. +1 – Greg Burghardt May 29 at 11:47
0

Since both are order controllers, it could make sense to define an abstract controller that defines the properties and behaviors common to all your OrderController, and let your role-specific controllers inherit from it.

Edit:

Your updated question seems to suggest that the controller does two different things: on one side it manages/controls the input; on the other it manages the (persistent?) data.

The second part would typically be handled by a model in an MVC design. In such a design, the model would be shared between the controllers, thus avoiding the repetitive part in the controllers.

But it all depends on what else is done in the duplicate part beyond the store(). If it’s more than maintaining the model, then Laiv’s component based approach would certainly be a sound and robust approach.

  • Thanks, I've updated to question, would you please take a look at it? – Pouneh May 29 at 8:17
  • @Pouneh I saw that Laiv already addressed your edit. I just wonder if you’re using an MVC approach or if it could be a valid candidate, so I edited. – Christophe May 29 at 12:04

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.