Service Layer in Web applications

Posted November 26th, 2009 by Juozas

Service Layer SketchIn my professional live I mostly work with enterprise web applications which are quite demanding for big layer of business logic (that’s another article I guess) and decoupling of application layers. During this year I invested quite a lot for a search of a good ways to architecture a big application and make it simply good. Quite a while ago Matthew Weier O’Phinney introduced service layer in one of his great talks about models, since then service layer become one of the key architectural component one my applications. Here I’m going to show a few examples and use cases where it’s very useful.

“Old-style” interaction with data

I’ve used it for different projects, but one of the best examples of how great this concept is SaaS or any other users-based application. Some years ago I used to have code which worked like this (let’s say this is controller action):

public function userInfo()
{
     $userDao = new Users();
     $user = $userDao->getUser($_SESSION['id']);
}

And then in my database access class Users I just execute sql query with a given user id. However, after some thinking I looked at it again and though – why does controller need to know the userId? I mean, of course it’s a job of controller to process requests and control application flow, but logically – if an action is named userInfo and we got to the point where we need the user info (hence the user is authenticated and validated) why do we need to pass user id? It’s clear that some part of code already knows it.

One more case: if a site is a e-commerce it’s clear that user has only access to his orders, addresses information etc. but in a basic MVC you either fetch by Id and then check if it’s in fact user’s order or create a method like in a first example. Again, not very clear and not easy to maintain. There are more problems too: by passing user id and id of a record you assume that controller knows that this is a key to get the information. But it’s wrong – business layer knows that user has orders; controller only knows that there is such a thing like orders and it can be retrieved by id. That’s it.

Service layer

For such things I use service layer: it has user info injected from bootstrap (or directly to a constructor) and operates with data only accessible to the user. So previous method becomes to:

public function userInfo()
{
     $service = new UsersService();
     $user = $service->getUser();
}

of course you would have a separate method to fetch other users data, but for sake of simplicity let’s just say that this method returns some private info (like address for example). Here my action is completely unaware of what user id actually is – it expects a user object, it gets it. Very simple, very clean and very easy to maintain.

Getting back to the e-commerce example, action for a view order would look like this:

public function viewOrder()
{
     $service = new OrdersService();
     $order = $service->getOrder($_GET['id']);
}

Again – this controller action doesn’t care what user id is in current session, it just gets an order by its id. If this action returns false (or throws exception with error type) then it means order cannot be retrieved, or in other words – service cannot return id by given id. It can be permissions problem, it can be something else – but controller is completely freed from checking all this unnecessary things.

Practical usage

As you might have noticed, service layer is intermediate layer between models and controllers – in the same way as you would use Flickr or Youtube API to work with remote data, you use service layer API to work with application resources. All the business logic resides in service layer, where also using other service layer, models are retrieved, changed, saved, returned etc. Controller has zero lines which contain a word Doctrine (or any other database layer class). None.

Service layer

Another advantage of using a service layer – it’s a good place to merge information sources. I think it’s more like a style of mine, but I tend to have models very clean – only with logic on that model. This is mainly because I usually use Doctrine models and I don’t want to put anything in them. For example just yesterday Adam from jazzslider.org posted a very good article about using Acl with models by creating custom listeners. With all respect, even though it works really great, I don’t think it’s a clean approach – I see models and permissions control as separate layers.

Furthermore, having this layer makes replacing database layer (or even models layer) a little bit easier – because all the other code communicates with data using given API (from service layer) so as long as results returned are the same, they don’t care how they are actually retrieved (for example they can come from cache, text file or created on-the-fly). But if you would have Zend_Db_Select calls all other the place, migrating to Doctrine’s DQL can be a pain. From my personal experience, I successfully migrated my own ORM code with about 50 models to Doctrine in about 4 days without changing a line in controllers (also because of tests I had).

To be honest, I’ve only tried various service layer implementations with Zend Framework. Even a default autoloader has a resource namespace Service_ with services folder inside application, so I didn’t need to do any hacking to get it working. Nevertheless, this pattern doesn’t require any specific framework futures, but if a framework has good dependency injector (like this one from Symfony) it can make things even cleaner.

Conclusion

I don’t know if I have convinced you to look at this pattern, but I definitely recommend looking at it. Especially when your application gets quite big and you need some sort of functionality to work with all these models (on average, I used service layer with applications having roughly 80 models). Nevertheless, there are tons of different ways to do this, so I definitely recommend reading a book by M. Fowler called “Patterns of Enterprise Application Architecture (P of EAA)”. One of the best sources for enterprise applications I’ve read so far.

* Image copyright: http://martinfowler.com/eaaCatalog/serviceLayer.html and http://www.tutorialspoint.com/images/soa-additional-service-layer.jpg

Trackbacks/Pingbacks

  1. Zend Framework University — Blog — Juozas Kaziukenas' Blog: Service Layer in Web applications
  2. Service Layer in MVC | Developer's Kanundrum

Comments (23)

  1. Giorgio Sironi

    PoEAA is indeed one of the best books on this subject.
    Personally I prefer considering some services part of the Domain Layer, in which adapters for different infrastructures (Doctrine for instance) can be injected.

  2. Fedyashev Nikita

    Hi, Juozas

    I really like your idea about separation of validation layer.

    And a this one:
    >>For such things I use service layer: it has user info injected from bootstrap (or directly to a constructor) and operates with data only accessible to the user.

    But can you please explain how this can help in terms of code testability?

  3. Exception e

    Good article. I am in the same process as you, letting separate factories to inject required resources into my models. Alhough my work isn’t yet as complicated and big, I still strive to improve my code like you do.

    I however wonder if it is a good idea to put ‘Service’ into the name?
    Until now I had resisted to put the word ‘Model’ into my model classes for example.
    My initial feelings are that a class is a service or model by function, not by name, and that class name should only reflect what entity or duty it represents.

    Also, I am higly influenced by the writings of padraic brady about fat models thin controllers.

    Your controller code

    public function viewOrderAction() // I think you meant ..Action
    {
         $service = new OrdersService();
         $order = $service->getOrder($_GET['id']);
    }

    looks already nice. But how you feel about creating a view helper like Myns_GetOrderForCurrentUser which proxies to a Factory that grabs the current id from $_GET and creates the order for you?

    Currently my controllers don’t pass (almost) no data to the view; the view scripts uses view helpers which in turn ask a factory to get the data. This part is ‘under discussed’ I think. :-)

  4. Juozas (author)

    Nikita, It helps to test because I can do something like this:

    $service = new Service(1);
    $service->getSomething();

    1 – userId for example. So service has no dependency on authentication or acl at all. Furthermore, because service has userId’s injected, I can test controllers more easily (without emulating auth, session etc) by invoking something like App_Service::setIdentity(1). Even though the best way would be to injected also the actual service to controller, however I’m not doing it yet for a few reasons.

    Exception, this is how it’s called, a Service. Usually they work on models, but in the same fashion you can get data straight from SimpleXML or twitter feed (without even using a model). Usually I have names like Products_Service_Images where Module_Service_Package.

    Yes, Padraic is very good! However, I kind of try to avoid using helpers too much. Especially when they hide things from you. I pass data from controller to view – so view can display it without any modifications and I can also test the controller more easily (to test if it does return what it needs to). Futhermore, getting a data from view is something what I try to avoid, even though I still use it :) Mostly for widgets, sub-menus or something like that.

    Nevertheless, this article and actual architecture is very open for discussions and comments. Please let me know any of your ideas – we can both learn to do great things!

  5. Exception e

    I too favor some discussion. Unfortunately there are not too many people out there in the zf world who discuss these kind of things.

    So service has no dependency on authentication or acl at all.

    Don’t you mean “controller” instead of “service”? To me it sounds reasonable for a service to check permissions before handing out an object etc.

    To be honest, I had yet to dive into tdd. But I am trying to think how a meager controller would hinder testability. I am inclined to think that controller tests are even smaller, since the only thing you need to test on is the output of the controller, which is usually html or json.

    In order to test if the data used in the view is correct, you are creating separate tests for the view helpers. Or is this difficult?

    I am really eager to learn more about these things.
    Everything goes fine, but I’m kind of a perfectionist. :D

    Like you said, widgets and menu’s are great for view helpers. I think view helpers are inevitable for cross-action cutting concerns. Controller plugins are also possible of course, but to me this seems to solve the problem at the wrong place.

  6. Juozas (author)

    I think I wasn’t clear about “no dependency” (or maybe it wasn’t a right words to say) :)

    By that I mean, that service can work without authentication part of application, because it (or userId) can be injected so there is dependency injection, but for the test you don’t need to do:

    $auth = Auth::getInstance();
    $auth->setIdentity(1);
     
    $service = new Service(); // here service get's identity from auth

    this is wrong – service has a dependency on authentication, but get’s it from somewhere else. As Misko Hevery likes to say – “API lies”. You are creating a service, which needs identity, but it doesn’t say so (so you are needed to look at the code to find it). Correct way is:

    $service = new Service(1);

    or

     
    // get mock and set id
    $mock = getMock("Auth");
    $mock->setIdOnAuthMock();
     
    $service = new Service($mock);

    In both ways you can actually test code in a pure unit-testing way.

    Speaking of view helpers – I somehow find then very nasty to test :) Mainly because usually I’m returning a html snippet and the actuall view helper has only method – get that snippet. So to test if it works I need to make view helper, for that I need to create methods for all data inputs and stuff like that. For me it’s easier to make view helper very skinny – one call to service/somewhere else and return html. No logic, hence nothing much to test.

    I’m studying testability and making test code testable quite a lot now, but usually the key moment – dependency injection. Your code (class) should be written in a such way, so it has ZERO “new” statements, and all these objects are inserted from outside code, using dependency injection. I definitely recommend looking at it.

    I’ve been playing with view helpers for a while – now even with ZF I have them in a very cool fashion – you can use dependency injection. My App_View injects needed objects/config when you call a view helper so the actuall view helper looses the dependency. Again, not very easy to do, still working on it.

    Exception, do you have a blog? I’m following about 100-150 php blogs and always looking forward to add new minds. Especially because you can find so many good content.

  7. Exception e

    Thanks for sharing your thoughts.

    $service = new Service(1);

    and

    $service = new Service($mock);

    strikes me a bit in the sense that they seem to have incompatible types. But I get your point I think, if you’d expected an Auth object, you could also pass it an mocked Auth object.

    > ZERO “new” statements
    That would be cool but for this I would need a di-container like from symphony I’m afraid. [Actually a cool project, with nice graphics.:)]
    Currently I do have new-statements in some code like this:

    class ShoppingCartService    {
        function __construct()    {
            $this->session = new Zend_Session_Namespace('ShoppingCart');
        }
    
        function getShoppingCart() {...} /etc
    }
    

    Yeah, I know, this is a hidden dependency. But it is at least on one discernable place.:P I am sure the next project will also change this practice, but I can sleep yet with this state of affairs so far.

    I am glad you are willing to read more of my thoughts. Opening a blog has been on my mind often times, yet I don not have one. I think within a few weeks I will create one. I’ll leave you a message, ok?

  8. Juozas (author)

    Exception, sure, let me know when it’s ready!

    Speaking of those examples – they are for different constructors. Constructor shouldn’t expect different types, especially where in PHP they are not overloadable. I wrote it because in some cases userId is not enough, for example there is some other data required which is sometimes stored in auth component, OR your service layer could work on both logged in and not user, so by passing auth component you make it work very nicely :)

    Dependency container is very nice, though I would like to have it integrated in the actual framework (ZF for example), mainly because it’s too much work to get it yourself without some hacking. And because I’m usually fighting with deadline I can’t spend too much on it.

    That’s why I’m using only Locator now in controllers. I call App_Locator::locate(‘interface/class’) and it gives me that object. Next step – making locator to work without me instantiating it, but this is for the future projects :)

  9. Exception e

    Yeah the last DI-container proposal for zf has failed. Maybe a proposal to integrate the work from sf will suceed, since the scope will then be more defined—the previous proposal failed because it lost direction.

    I am a bit curious whether there is some intelligence within ::locate()? Does it only instantiate the class for you, or is there also some configuration going on there? (Never heard about locators)

  10. Juozas (author)

    Locator can work in any way you want. One of the most important things about it – it has container, so

    locate()

    method gets new instance OR old one from container. This helps to inject things into code where it’s hard to do it in other way.

    Configuration is not required, although can make interesting things. You can also use reflection, though, because what you need to know is:

    1. Dependencies
    2. Optional params
    3. Configuration
    4. Maybe something more

    So it’s really helpful when you know these things and your locator can get them too.

  11. William Chang

    Can you please elaborate or go in-depth on how to pass user authentication checking, cookies, $_SESSION['foo'], $_GET['bar'] to the service layer without going through the controller and for unit testing?

    In my opinion, web frameworks doesn’t discuss much about how to properly deal with authentication checking, cookies, $_SESSION['foo'], $_GET['bar'].

    Service layer
    For such things I use service layer: it has user info injected from bootstrap (or directly to a constructor) and operates with data only accessible to the user. So previous method becomes to:

    Thank you very much!

  12. Juozas (author)

    William, I’m happy that it interested you! I will try to write more about this topic soon.

  13. Adam Jensen

    Thanks for the link; was kind of fun to be reading through your post and suddenly discover my own name :)

    Actually, in the original design of my application, I did use service layers quite a bit: one service object for each of my Doctrine models. These service classes handled caching and access control logic pretty much everything.

    There were a couple of reasons I decided to change this. First, I noticed that the service layer’s public API was little more than a wrapper around Doctrine_Table’s…e.g., it was full of method like find(), save(), findOneBySlug(), etc…the caching and ACL logic was the only added benefit.

    Second, it kept me from taking advantage of Doctrine’s built-in accessors for related records. Consider:

    $post = $postservice->find($id);
    $comments = $post->Comments;

    In this example, the service layer takes care of access control and caching for the post object, but what about its comments? No service layer invoked, no protection…I’d have to do this instead:

    $post = $postservice->find($id);
    $comments = $commentservice->findAllByPost($post);

    The approach I described in my blog circumvents this problem by applying just-in-time ACL checks (I’m letting Doctrine handle its own caching) no matter how the query is initiated.

    It’s also still pretty testable, since the ACL logic is applied in a sort of plugin object rather than inside the model object itself.

    I am, however, still using dedicated service layers for things like XML-RPC…but in the standard web frontend controllers i’ve found it simpler just to use the table AS the service…of course, I’m still learning, so I may regret it later :)

  14. Juozas (author)

    Adam, I understand your reasoning, however I came across some articles and posts (don’t remember exact sources) proving that exposing such things like Doctrine models actions are just wrong.

    I have worked with NHibernate before too, and we tended to hide the actual hibernate API using our own classes. Especially in Doctrine case (1.X branch) you are exposing way too much functionality to controller. And even though it’s very practical and nice to use, it creates problems, mainly those that controller has access/is doing too much.

    Having a service API makes controller work completely independent from Doctrine and gives you control over things. Sometimes I just hate all these magic methods, because they are impossible to track and control. Basically it’s considered a good practice to have layers of applications isolated and separated and only communicating using API’s, and not invoking some sort of direct methods.

    So, I liked your solution very much, however, after studying recommendations for enterprise apps I decide to limit Doctrine access to only-service. It’s working fine :) Nevertheless, it’s not some kind of final design or way everyone should do things – I’m always looking forward to ways to improve it.

  15. Federico

    Hi Juozas,

    So, how do you inject dependencies? The way I see it you are wiring the objects manually, for example:


    // Create an instance of OrdersService and inject User
    $service = new OrdersService();
    $service->setUser($user);
    $order = $service->getOrder($id);

    // ... instead of ...

    // Locate class and inject dependencies
    $injector = new Injector();
    $locator = new Locator();
    $locator->setInjector($injector);

    $service = $locator->getService('Orders');
    $order = $service->getOrder($id);

    Is that how you are doing it?

    Cheers

  16. Juozas (author)

    Federico, I’m playing with different locators right now.

    Currently I’m using a registry to store identity, and service’s constructor calls identity container method to obtain it. OR in tests i inject it (or null) manually.

  17. Federico

    I think the most important is to exlpain what a service layer is and when to use it. In the OrdersService example you provided, you shouldn’t be using a service. The service layer doesn’t supply access to data/objects, it coordinates other services. A service usually refers to some domain logic which does not belongs to entities or repositories. What you can do is inject a repository into a service. Repositories are a type of service and deal with data access. If your method OrdersService::getOrder($id) returns an Order or some procedural data, then it should be moved to OrdersRepository.

    Cheers

  18. Exception e

    @Federico

    The service layer doesn’t supply access to data/objects, it coordinates other services

    This means that no service could exist, or some of them need to do mutual coordination.
    Myabe you could explain it a little more.

    What you can do is inject a repository into a service.

    So what you propose is that if you want to get an Order in your controller, you need to have one extra level of indirection?

    OrderService -> OrderRepo -> {source}

    Would you consider Doctrine_Table a repository?

  19. Giorgio Sironi

    Strictly Doctrine_Table is a Table Data Gateway, not a Repository. They both are data access patterns.
    I consider the Service layer as a thin layer to support mundane tasks which do not fit in the Domain Model, like authentication/authorization, logging, http request management, and similar.

  20. ed

    Hello Juozas.

    First your say “I looked at it again and though – why does controller need to know the userId?”

    Ok with this phrase you say there’s no dependency injection.

    After you say :

    “For such things I use service layer: it has user info injected from bootstrap (or directly to a constructor) and operates with data only accessible to the user.”

    Ok here you keep with no dependency injection. What i understard that is you set the user sessionId direct to the conctructor.

    But at the end you say this is wrong because the service can get the auth instance inside himself:

    “$auth = Auth::getInstance();
    $auth->setIdentity(1);

    $service = new Service(); // here service get’s identity from auth”

    Ok as i have understood. You saying this is wrong. Service layer always should has dependency injection.

    So i ask why in your first 2 examples you said that the controller doesn’t need to know the session id (passing directly to the controller) ? This is not a contradiction ?

    Please clarify how to handle session Ids and pass them to service layer.

  21. ed

    “(passing directly to the controller) ” i mean

    (passing directly to the constructor)

  22. Juozas (author)

    Ed,

    Auth class was kind of example how to configure authentication which is used by service.

    In controller that class is not touched at all, because authentication is configured in bootstrap. This class can be used in tests, to set and unset user id/other properties.

    Now how it was written in a last example, is by something like:

    public function _construct()
    {
        $this->_setId(Auth::getIdentity());
    }

    Here we have dependency to Auth class, so ideally you’d want to either inject user object/id/whatever to constructor with help of DIC or inject auth class as object. Maybe even like this (use this myself usualy):

    public function __construct($userId = null)
    {
        // handle null case somehow/disallow it
        $this->_setId($userId);
    }

    In all cases, dependency to session doesn’t exist. Services (and Auth class if used) have ID, maybe some other properties, but they are just variables: cookies, sessions or any other logic you use to authenticate is decoupled.

    This post was mostly referring to controller which uses session to handle logic. So the goal was to remove it and make controller session-blind. Is it clearer now? (confused whether I’m clear)

  23. ed

    Hi Juozas, thanks for quick response.

    Lets see if i got it.

    My app is an ecommerce application. The user is not authenticated yet, but i already have an id in the session to identify the shopping cart.

    So in the bootstrap i could do:

    Zend_Registry::set("transactionId","here can be a cookie value")

    And then in my controller to retrieve the order i do:

    public function viewOrderAction()
    {
    $service = new OrdersService();
    $order = $service->getOrder(Zend_Registry::get("transactionId"));
    }

    Is that correct, right? In this case i am letting my service with dependency injection, how it should be.

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">