views:

48

answers:

2

So we have a PHP+Zend Framework+Doctrine 1.2 application that has the following structure:

Controller -> Action -> Service -> Model

Not all models are interacted with through a service. Our current opinion is that a controller could use a model directly and a service could possibly use other services.

My question is: If you have a piece of business logic, what guidelines do you use to determine if the code that implements that logic should be in the Model, Controller, or Service layer? I am specifically interested in distinctions between the Controller and Service layer.

Here are the guidelines that our development team have come up with, but I am very interested in any feedback/input about them:

  1. Services and controllers contain logic for tying various components together to accomplish a task. This logic might not be in the model to avoid dependencies and make the model more reusable. This logic might also not be in the model because we think the model should avoid consuming things up the application stack to avoid unnecessary dependencies (ex: the model would not consume a service or controller).
  2. Use a service rather than a controller when the code may be used by multiple modules or controllers.
  3. A model should contain as much logic as possible but avoid referencing application-specific functionality. Usually a model contains at least validation logic.
  4. For any piece of functionality consider placing it in the model first. If there is a compelling reason not to, consider a service (also consider the overhead and purpose for maintain a new service). If a service is not desired and the code won't be reused in this application use a controller.
+2  A: 

I believe you should place your business logic inside the service layer. The reasoning behind this is that business logic should be a separate concern from data structures/model.

As with most cases you often find that the data structure and the business logic are closely intertwined and hence may not have enough separation to justify my first statement. However, I would argue this generally points to code smell.

In a per instance optimization you would move the code to a location where it is optimal for performance but in the first iteration I would still position it in the service layer.

I agree that models should contain as much inwardly focusing logic as possible but the model needs to be non-specific. The business logic is a use case which consumes the model for your application so should be separate.

Michael Baker
+1  A: 

In your context, I'd see models and controllers as both being parts of the business logic; the models defining "what" things are, the controllers defining "how" they are accessed.

Services sit on top, potentially exposing the business logic to anything outside of the business logic layer. I agree with you that a service might encapsulate more than one specific component (or model to be more precise).

Services and controllers contain logic for tying various components together to accomplish a task.

Yes, I also agree with your statement on avoiding dependancies, etc. the model should not depend on anything excpet other closely related models (Common Closure Principle).

In addition, if the logic is specific to a model - then that's where it should go; if the logic is more generic it should be placed at the approriate level - possibly a controller or a common internal utility.

Use a service rather than a controller when the code may be used by multiple modules or controllers.

I agree. In terms of grainularity I would see services being at a higher level of abstraction - you're more likely to expose a service to an external system than your "internal" controllers.

A model should contain as much logic as possible but avoid referencing application-specific functionality. Usually a model contains at least validation logic.

It should only contain logic that's appropriate to be there, otherwise I agree. Validation - you could abtract that out; the model should definately contain the rules that validation uses but not necessarily the validation itself. I've seen both styles used and I don't think there's no wrong or right answer as long as you're consistent.

For any piece of functionality consider placing it in the model first. If there is a compelling reason not to, consider a service (also consider the overhead and purpose for maintain a new service). If a service is not desired and the code won't be reused in this application use a controller.

it depends what that "functinality" is, if it's specific to a model then it probably belongs in the model; if it's common to more than one model then it either belongs in a controller or a common utility class within the business logic.

As I started writing all of this I wanted to put a stake in the ground around the definition of the terms you've used; I thought I'd include it anyway - so correct me if I'm wrong :) And as you can see, I'm not clear on what you mean by an "action" in your context.

  • Model: (from Wikipedia - MVC) "The Model is used to manage information and notify observers when that information changes; it's also a domain-specific representation of the data upon which the application operates." To my mind this implies properties and the like - not methods.
  • Controller: (from Wikipedia - MVC) "Receives input and initiates a response by making calls on model objects. A controller accepts input from the user and instructs the model and viewport to perform actions based on that input."
  • Service: There are many different opinions on what a service is, I assume in your context a service is: an externally facing callable point (within the context of the layers of your system) that provides a specific answer to a specific question. (Services being usually based around business concepts not technical ones.)
  • Action: I don't know what you explicitly mean by this.
Adrian K
Thanks very much for your response. I believe that my opinion of a models differs slightly from yours. It's funny that if you speak to multiple developers there is almost always disagreement about what exactly a model is. Some people believe it is actually the database tables, some believe it is a class representing a table, some believe it should contain all model-specific logic (such as rules for validation - yes, not necessarily the validation code itself).
Dewayne
I tend to lean towards the heavy side of the model because, to me, it seems like the model could be more easily transferred to a new application as a single reusable entity rather than dispersing the methods that operate on that model. Also, just to clarify...in PHP the "Action" is just a method in a Controller.
Dewayne
Yes - there are so many loaded terms out there (RE Model); I find keeping things as simple as possible works best (in terms of what things mean). I also think your approach to a model is fine, and having a clear and justified approach is a great start :)
Adrian K