Controller Layer vs. Service Layer

A recent post on the Model-Glue list, and Sean Corfield's reply, got me thinking about how we decide what goes into a Controller/Listener/Circuit and what goes into the Model.

Sean's response was spot on: go through the thought experiment of having to switch frameworks. How would your application handle this change?

Well, if you have lots of business logic, conditional logic, validation, or calls to Reactor in your Controller, you're going to have a lot of work to do. All of that code will have to be copied over and reworked. That's no fun.

But if your Controller does nothing but call underlying model components (the Service layer) and make basic decisions about application flow (such as announcing events), you're in much better shape. My rule of thumb is that the Controller shouldn't be doing anything but calling some Service layer components to do the real work, and then doing anything related to application flow.

In Model-Glue and Mach-II, that also means that nothing past the Controller/Listener layer should know about the Event object. The more "shallow" the framework's tendrils are, the better.

I find it helpful to envision a different thought experiment than simply switching frameworks: What if we bypass the framework completely? Such is the case with Flex and AJAX front ends, or web services. Ideally, your Service layer should be able to handle any of these situations with no change at all. All you probably need is a simple facade CFC to allow your Service layer components to be called remotely. ColdSpring can even generate these for you using the Remote Factory Bean.

Conversely, as you might guess by now, if allowing something like Flex to call your Model looks like it will be a huge pain in the butt, there's almost certainly something wrong with your architecture.

Now here's the rub: planning this out during the architecture phase is quite easy. Refactoring an existing application that has murky boundaries between the Controller and Model (and View for that matter) is much more time consuming. However, the longer you wait, the worse it will be. In this regard it's like a band-aid: just rip it off quickly and get it over with.

How do other folks approach this? Do you try to keep your layers separate or have you never had a problem just mashing things up? Any horror stories related to overlapping application layers that came back to bite you?

Related Blog Entries

Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
Hi Brian,

All depends on what you're trying to do. I have never had a project where I needed to port frameworks or provide an alternate front end, but that is part of the spec for my current generator, so there days I make three distinctions.

Service layer handles of object specific functionality including validations and object relationships.

Feature facade acts as a thin facade to the service layer to handle orchestrations that are not controller specific. For instance, I have a "cart" feature with add to cart, update cart totals and other such methods. In my service layer I don't have a cart object at all - I use an order object as I find the overlap (for my implementation) pretty close to 100%. However, my cart feature abstracts that design decision, so if I was ever to create a CartService, I'd just change the orchestration code in the feature and everything would still work in all n potential front ends.

I see the controller as something responsible for handling technology specific plumbing (such as URL creation and HTML specific rendering), the orchestration level responsible for providing a consistent API and handling orchestration of the service level which is responsible for the actual saves and gets and other object specific methods.

Of course, for simple applications you may not need the seperate orchestration layer, but I find it useful as projects become more complex, as orchestration logic becomes non-trivial and as you find yourself providing an API that is not necessarily tightly tied to a set of actual objects.

Best Wishes,
Peter
# Posted By Peter Bell | 9/5/06 9:01 AM
Hey Brian,

I've been giving this a lot of thought lately. Most recently I've come to a debate as to where objects should be created. Since most persistent objects (i.e. daos, gateways, services, etc.) already exist in my application, I'm not to worried about them. What I'm concerned with specifically is entity or bean objects. When using a Factory like coldspring, which plays nicely with both MachII, ModelGlue and even Fusebox, where does the creation of these objects take place? Its very easy to create a non-singleton object in coldspring, so it seems easiest to let coldspring handle them, however if I do this, I run into a few problems. The most apparent is that the controller seems the most likely candidate for handle this. This isn't a problem when I'm using MachII or MG, however I'm not sure if this will become an issue when I'm designing Ajax or Flex applications using the same model (service layer).

I realize there may be many viable solutions, I just wanted to see if I could get some input.
# Posted By Andrew Duckett | 9/9/06 4:28 AM
Hi Andrew,

I don't see bean creation as a controller function at all. Here's a question - if you used a flex front end, would you still be creating beans in the same way (even if you used an adapter on the final data to format it in the way flex wanted). My answer to that is "yes". My model (including the beans that it generated and interacted with) would be the same, so the generation of beans is (for me) a part of the model.

I personally see bean creation as an integrated part of the responsibilities of the service layer within the model. I want to userService.getUser(23) and have user 23 returned to me as a loaded bean. Then question then is how does userService create the user bean?

Personally, I am moving towards using composition with a generic bean factory being called by all of the service layers. You could use ColdSpring for this, but unless you need the benefits (DI and/or AOP), you may want to just consider creating your own little factory to do it - even if you're using and accepting the overhead of ColdSpring for all of your singletons.

Either way, I'd argue the bean factory is definitely part of the model.

Best Wishes,
Peter
# Posted By Peter Bell | 9/9/06 8:08 AM
I would agree with Peter, the Controller shouldn't be creating these things. In fact, you mentioned a key giveaway that this shouldn't be done in the controller by asking about using Flex. If your Controller creates these and you ever need to call the service layer directly (from AJAX, Flex, or web services), you will have problems. I'd say keeping this responsibility in the model is the way to go.
# Posted By Brian Kotek | 9/9/06 2:29 PM
Just a comment regarding the terminology this page seem to be using about what a Controller is.
The controller is NOT equal to a GUI class such as a listener, according to the GRASP Controller (in "Applying UML and Patterns" by Craig Larman, which is claimed to be the world's most sold book about OO analysis and design). Rather, it is defined as "first object beyond the UI layer receives and coordinates (controls) a system operation".
As far as I understand, the GRASP controller is about the same thing as the Service layer as described by Martin Fowler.

http://davidhayden.com/blog/dave/archive/2004/11/2...
http://www.martinfowler.com/eaaCatalog/serviceLaye...
# Posted By Tom | 3/19/07 5:18 AM
BlogCFC was created by Raymond Camden. This blog is running version 5.9.1. Contact Blog Owner