SitePoint Sponsor

User Tag List

Results 1 to 21 of 21

Hybrid View

  1. #1
    SitePoint Addict bronze trophy
    Join Date
    Apr 2013
    Location
    Ithaca
    Posts
    351
    Mentioned
    6 Post(s)
    Tagged
    1 Thread(s)

    The usage of Service Layer with a data mapper, how is this necessary?

    Well I've just read a series of PHP articles on devshed about building a service layer. However, even after reading all these articles I still do not find much practical benefits of using a service layer, especially when you already have a data mapper that can pretty much do the same thing. Here is the class of Service and UserService from that article:
    http://www.devshed.com/c/a/PHP/PHP-S...er-Services/1/

    PHP Code:
    namespace MyApplicationService;
    use MyApplicationMapper,
        MyApplicationEntity;

    abstract class AbstractService
    {
        protected $_mapper;

        /**
         * Constructor
         */
        public function  __construct(MapperAbstractDataMapper $mapper)
        {
            $this->_mapper = $mapper;
        }

        /**
         * Find an entity by their ID
         */
        public function findById($id)
        {
            return $this->_mapper->findById($id);
        }

        /**
         * Find all the entities
         */
        public function findAll()
        {
            return $this->_mapper->findAll();
        }

        /**
         * Insert a new entity
         */
        public function insert(EntityEntityAbstract $entity)
        {
            return $this->_mapper->insert($entity);
        }

        /**
         * Update an entity
         */
        public function update(EntityEntityAbstract $entity)
        {
            return $this->_mapper->update($entity);
        }

        /**
         * Delete an entity
         */
        public function delete($id)
        {
            return $this->_mapper->delete($id);
        }
    }

    namespace MyApplicationService;
    use MyApplicationMapper,
        MyApplicationEntity;

    class UserService extends AbstractService
    {
        /**
         * Constructor
         */
        public function  __construct(MapperUserMapper $mapper)
        {
            parent::__construct($mapper);
        }

        /**
         * Save a user to persistence layer
         */
        public function save(EntityUser $user)
        {
            return $user->id === null ?
                   $this->insert($user) :
                   $this->update($user);
        }

        /**
         * Fetch all users in XML format
         */
        public function toXML()
        {
            $users = $this->_mapper->findAll();
            $xml = "<?xml version="1.0" encoding="UTF-8"?>n<users>n";
            foreach($users as $user) {
                $xml .= "<user>n<fname>$user->fname</fname>n"
                      . "<lname>$user->lname</lname>n"
                      . "<email>$user->fname</email>n</user>n";
            }
            $xml .= "</users>";
            return $xml;
        }
    }
    As you see, the service layer pretty much is just an adapter interface for the mapper, nothing more nothing less. Although the author stated that in the subclass UserService you can add some additional functionality such as save() and toXML() to distinguish it from a data mapper, but dont you think its perfectly fine just to write these methods inside a UserMapper class rather than create a UserService class? The usage of a Service Layer may work out for Active Record, but I seriously dont understand how it helps much when you already have Data Mappers. Anyone mind elaborating?

  2. #2
    SitePoint Guru
    Join Date
    Nov 2003
    Location
    Huntsville AL
    Posts
    689
    Mentioned
    4 Post(s)
    Tagged
    0 Thread(s)
    One reason might be that DataMappers are well known objects with a fairly specific responsibility i.e. they transfer data between objects and a database. If you started adding additional methods then you would violate the ever popular single responsibility principle.

    A second reason might be that inheritance should generally follow the IS_A notion. Is a UserService a DataMapper? Not really. The article does a poor job of defining exactly what all the UserService is supposed to do but in principle the UserService might not use a data mapper at all. Might consider asking the author.

    A third reason is testing. You can mock up a data mapper and then write some tests without having to actually hit a database.

  3. #3
    SitePoint Addict bronze trophy
    Join Date
    Apr 2013
    Location
    Ithaca
    Posts
    351
    Mentioned
    6 Post(s)
    Tagged
    1 Thread(s)
    Quote Originally Posted by ahundiak View Post
    One reason might be that DataMappers are well known objects with a fairly specific responsibility i.e. they transfer data between objects and a database. If you started adding additional methods then you would violate the ever popular single responsibility principle.

    A second reason might be that inheritance should generally follow the IS_A notion. Is a UserService a DataMapper? Not really. The article does a poor job of defining exactly what all the UserService is supposed to do but in principle the UserService might not use a data mapper at all. Might consider asking the author.

    A third reason is testing. You can mock up a data mapper and then write some tests without having to actually hit a database.
    I see, thanks for your explanation. Perhaps I should design a service layer in the next version of the script I am working on, still hesitating right now but it can be an option. XD

  4. #4
    Community Advisor bronze trophy
    fretburner's Avatar
    Join Date
    Apr 2013
    Location
    Brazil
    Posts
    1,411
    Mentioned
    45 Post(s)
    Tagged
    12 Thread(s)
    I can imagine the UserService being the place to put a register method, for example. This might deal with things such as firing off a welcome email (via an injected mail service), which wouldn't belong in the mapper. Alternatively, the author might be thinking more of the repository pattern, which would be used to encapsulate query logic and keep it separate from the mapper [See Fowler's description of the repository pattern].

    In any case, I don't agree with the inclusion of the toXML method, as this relates to output and should be in it's own class, otherwise the UserService is violating the single responsibility principle.. imagine at a later date you want to add JSON as an output format, now you have to modify UserService. Far better to keep the output transformations in separate classes I think.

  5. #5
    Non-Member
    Join Date
    Oct 2007
    Posts
    363
    Mentioned
    11 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by fretburner View Post
    I can imagine the UserService being the place to put a register method, for example. This might deal with things such as firing off a welcome email (via an injected mail service), which wouldn't belong in the mapper. Alternatively, the author might be thinking more of the repository pattern, which would be used to encapsulate query logic and keep it separate from the mapper [See Fowler's description of the repository pattern].

    In any case, I don't agree with the inclusion of the toXML method, as this relates to output and should be in it's own class, otherwise the UserService is violating the single responsibility principle.. imagine at a later date you want to add JSON as an output format, now you have to modify UserService. Far better to keep the output transformations in separate classes I think.
    You know, I use the repository model a lot now because Doctrine recommends it - but I have to say, reading Fowler's description is like trying to read ancient greek to me. I know a lot of people really respect that guy, but I find his writing almost impenetrable. Is it just me?

  6. #6
    Non-Member
    Join Date
    Oct 2007
    Posts
    363
    Mentioned
    11 Post(s)
    Tagged
    0 Thread(s)
    It's funny, because I'd started using a service layer myself a while before I realised there was a term for it. The problem I had at the time was that lots of my business logic was going straight into my models. It made sense to me at the time, but it turns out that when you do this, you end up with quite complicated models with coupling between function calls all over the place.

    The primary reason I started taking business logic out of my models and sticking it into separate classes (I called them "processes" at the time, because I didn't know what term to use) was to encapsulate the logic and make my models cleaner. It made a really big difference. It turns out that by doing this, you can also unit test your service objects as well, which gives you another great reason to do it.

    Nowadays, my models (or "entities", because I tend to work with Doctrine a lot now) are very clean and simple - I have nothing more than getters and setters in them really now. Anything that actually uses the models to do stuff is put into service layer objects, and it's made a big difference to the cleanliness and quality of my code.

    It's a good thing to do. Once you start doing it, you'll really start to see how clean your models stay, and how easy it is to isolate the logic for any given service (because that logic will exist only once, and in a clearly defined place). I'd also highly recommend unit testing your service objects as well.

  7. #7
    Community Advisor bronze trophy
    fretburner's Avatar
    Join Date
    Apr 2013
    Location
    Brazil
    Posts
    1,411
    Mentioned
    45 Post(s)
    Tagged
    12 Thread(s)
    Quote Originally Posted by aaarrrggh View Post
    Nowadays, my models (or "entities", because I tend to work with Doctrine a lot now) are very clean and simple - I have nothing more than getters and setters in them really now. Anything that actually uses the models to do stuff is put into service layer objects, and it's made a big difference to the cleanliness and quality of my code.
    What about model validation, do you usually put that in a service too?

  8. #8
    Non-Member
    Join Date
    Oct 2007
    Posts
    363
    Mentioned
    11 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by fretburner View Post
    What about model validation, do you usually put that in a service too?
    This is an interesting one. Until the project I've just started working on (literally started on it this week), I would typically put my validation directly inside my model. I'd do stuff like:

    PHP Code:
    <?PHP

    class User{
    ...

       
    setEmail($email){
     
        if (
    $email is not a correctly formed email address){
             throw new 
    InvalidArgumentException($email ' must be an email address'xxx);  

      }

    }


    ?>
    Obviously I removed the logic for checking the email here (xxx is whatever error code I'm assigning to the exception).

    However, in Symfony 2, there's actually a validation service that will validate entities based on certain rules you pass to it: http://symfony.com/doc/current/book/validation.html

    One thing I like about this model is the fact that you can have validation groupings, which means you can have different validation rules for the same model dependent on the context: http://symfony.com/doc/current/book/...idation-groups

    I also like the fact that you can stick your validation rules into an external yaml file (although you can use other methods if you wish - annotations, xml or plain php), which makes it quite easy to see all your validation rules in one place.

    It's early days for this method for me, but I like the idea in principle. The one downside that I can think of is that you could in theory bypass all validation if you just tried saving the model directly.

  9. #9
    SitePoint Guru
    Join Date
    Nov 2003
    Location
    Huntsville AL
    Posts
    689
    Mentioned
    4 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by aaarrrggh View Post
    Nowadays, my models (or "entities", because I tend to work with Doctrine a lot now) are very clean and simple - I have nothing more than getters and setters in them really now. Anything that actually uses the models to do stuff is put into service layer objects, and it's made a big difference to the cleanliness and quality of my code.
    I do the same thing but it's actually frowned upon by many "experts". It's called the "anemic domain model" anti-pattern.

    I have often struggled with how to make my domain business objects actually do something but keep coming back to just putting most of the functionality in domain services. Oh well.

    There is an interesting article here by the creator of Doctrine: http://www.whitewashing.de/2013/07/2...ainevents.html

    He basically added a Domain layer to doctrine which basically allows your domain (business) objects to send messages when they change their states. This in turn can allow listeners to do things like sending welcome mail.

    It's perhaps the first tiny step to creating "bloody" (as opposed to anemic) business objects.

  10. #10
    Non-Member
    Join Date
    Oct 2007
    Posts
    363
    Mentioned
    11 Post(s)
    Tagged
    0 Thread(s)
    Interesting. I didn't know some people consider it an anti-pattern. I will have to read up on the reasons for that.

    I can tell you that so far I've had nothing but success with it - it's made my code easier to read, maintain and test. I'll have to have a read up on why some people consider it an anti-pattern...

    Quote Originally Posted by ahundiak View Post
    I do the same thing but it's actually frowned upon by many "experts". It's called the "anemic domain model" anti-pattern.

    I have often struggled with how to make my domain business objects actually do something but keep coming back to just putting most of the functionality in domain services. Oh well.

    There is an interesting article here by the creator of Doctrine: http://www.whitewashing.de/2013/07/2...ainevents.html

    He basically added a Domain layer to doctrine which basically allows your domain (business) objects to send messages when they change their states. This in turn can allow listeners to do things like sending welcome mail.

    It's perhaps the first tiny step to creating "bloody" (as opposed to anemic) business objects.

  11. #11
    Non-Member
    Join Date
    Oct 2007
    Posts
    363
    Mentioned
    11 Post(s)
    Tagged
    0 Thread(s)
    Just read this now: http://www.martinfowler.com/bliki/An...mainModel.html

    Now object-oriented purism is all very well, but I realize that I need more fundamental arguments against this anemia. In essence the problem with anemic domain models is that they incur all of the costs of a domain model, without yielding any of the benefits. The primary cost is the awkwardness of mapping to a database, which typically results in a whole layer of O/R mapping. This is worthwhile iff you use the powerful OO techniques to organize complex logic. By pulling all the behavior out into services, however, you essentially end up with Transaction Scripts, and thus lose the advantages that the domain model can bring. As I discussed in P of EAA, Domain Models aren't always the best tool.
    The thing is, the entity/model relationship I was describing is something I use with Doctrine. Doctrine's entity manager takes care of mapping these anemic models to the database, so this actually isn't a problem for me at all.

    I've got to say, I actually disagree with him here. I've not noticed any of these problems at all (but then, as I say, I'm not having to take care of mapping anything to the database as this problem has been solved for me by Doctrine, so perhaps the argument isn't quite so straight forward).

  12. #12
    Community Advisor bronze trophy
    fretburner's Avatar
    Join Date
    Apr 2013
    Location
    Brazil
    Posts
    1,411
    Mentioned
    45 Post(s)
    Tagged
    12 Thread(s)
    Regarding the "anemic domain model" anti-pattern, my understanding was that most people are assuming domain model == entity, whereas you can have domain services, which are considered part of the model layer (at least, that's what the DDD stuff I've read seems to say). It makes sense when you think about it, as aaarrrggh pointed out you're violating the SRP in your entities otherwise.

    Edit: reading that last link to Fowler's article, this does seem to be what he's saying.

  13. #13
    Non-Member
    Join Date
    Oct 2007
    Posts
    363
    Mentioned
    11 Post(s)
    Tagged
    0 Thread(s)
    I just had a word with some of the Java guys in work. They're all saying they prefer the Service Oriented Architecture for the same reasons I described. As I say, I actually kinda "discovered" the pattern myself after encountering the problem with complicated models that were hard to manage and change.

    I'm going to continue using this method for the time being, because I cannot see the disadvantages. If anyone reading this can point further disadvantages out, feel free :-)

  14. #14
    Non-Member
    Join Date
    Oct 2007
    Posts
    363
    Mentioned
    11 Post(s)
    Tagged
    0 Thread(s)
    Don't want to hijack this thread too much, but I found myself agreeing with the comment by "Kishore" on this article:

    http://codebetter.com/gregyoung/2009...model-pattern/

    His comment:

    All,

    I agree, I’ve been using the Anemic Domain model for a while now and do prefer it for many of the reasons listed:

    1. Separation of concerns.
    2. Facilitates Code Generation
    3. Facilitates “Enterprise-Level” integration
    4. Logic placed in Services can be easily switched.
    5. Note: Extension methods in 3.5 can allow for an interesting hybrid between the two.
    6. Domain Model’s can become complex.
    7. Relationships / Aggregates can still be in the Anemic Model.

    Regarding #6 Above think of all the various “Services”/Functionality that can go into a Rich Domain Model.
    1. Security
    2. Validation
    3. Data Massaging
    4. Persistance
    5. Import / Export
    6. Serialization
    7. Event Handling
    8. Resource/Localization

    This can easily get quite complex.

    I’m using the Anemic Domain Model and various re-usable components that are part of an open-source library I’m building. And so far this approach is working quite well.

    http://commonlibrarynet.codeplex.com/

    Finally, I just want to say…. simply put.. things change. And what may be good in one-scenario may not work in another. Patterns change them selves.
    Regards,

    -Kishore

  15. #15
    SitePoint Addict bronze trophy
    Join Date
    Apr 2013
    Location
    Ithaca
    Posts
    351
    Mentioned
    6 Post(s)
    Tagged
    1 Thread(s)
    Oh yeah I remember this anemic domain model debate. I try to avoid anti-patterns, but I do agree there are times that you find the temptation in using them. Singleton is a well-known anti-pattern and I do not use it for database class like examples from many online articles, but I do have a registry class that applies part of the Singleton principles. Now Id say that in a general sense anti-patterns are to be avoided, but there may be circumstances that you will actually end up using it. I like writing elegant codes, but I also need flexibility for rare occasions.

  16. #16
    Non-Member
    Join Date
    Oct 2007
    Posts
    363
    Mentioned
    11 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Hall of Famer View Post
    Oh yeah I remember this anemic domain model debate. I try to avoid anti-patterns, but I do agree there are times that you find the temptation in using them. Singleton is a well-known anti-pattern and I do not use it for database class like examples from many online articles, but I do have a registry class that applies part of the Singleton principles. Now Id say that in a general sense anti-patterns are to be avoided, but there may be circumstances that you will actually end up using it. I like writing elegant codes, but I also need flexibility for rare occasions.
    Can you think of any reasons as to why the anemic models are actually a bad idea in practice though? Other than what seems like academic theory from people like Fowler, I can't see any actual real world drawbacks from using this method - in fact, I can only see benefits, and negatives from having models that also process business logic rules. Perhaps I am missing something?

  17. #17
    SitePoint Guru
    Join Date
    Nov 2003
    Location
    Huntsville AL
    Posts
    689
    Mentioned
    4 Post(s)
    Tagged
    0 Thread(s)
    Take a look at this article and the associated gist from the man himself: http://www.whitewashing.de/2013/07/2...ainevents.html

    PHP Code:
    $item = new InventoryItem('Cookies');
    $item->checkIn(10);
     
    $entityManager->persist($item);
    $entityManager->flush();
     
    $item->rename('Chocolate Cookies');
    $item->remove(5);
     
    $entityManager->flush(); 
    There are no generic getter/setters in InventoryItem. Each of the public methods actually do something for a reason.

    Consider the rename method. It's pretty obvious that by calling this method you are deliberating changing the name of your item. The semantics are very clear.

    Furthermore, after flush is called, a InventoryItemRenamed event is dispatched allowing anyone who happens to be interested to take further action. Equally important, if the flush fails for some reason then no events are dispatched.

    Basically, a bloody (non-anemic) object can support real operations.

    Can you do a rename from a service? Of course. But by letting the object do the work you can see exactly what operations an object can and exactly what the rules are. With services, there is no central place where you can see what an object actually do.

    Unit testing actual behavior is easier.

  18. #18
    SitePoint Addict bronze trophy
    Join Date
    Apr 2013
    Location
    Ithaca
    Posts
    351
    Mentioned
    6 Post(s)
    Tagged
    1 Thread(s)
    Sorry for bumping a thread that is already dead for about 2 weeks(hopefully this does not break the rules against bumping old threads). I was wondering though, in the article series on Devshed the Service Layer has lots of adapter methods to the DataMapper to some extent(for instance these CRUD operations, which it simply uses its mapper property and call the same method on the mapper), but this means a large increase in the number of method calls. Is there gonna be a serious performance penalty for writing this many adapter methods? If so, how much is the performance cost compared to standard database operations?

  19. #19
    SitePoint Guru
    Join Date
    Nov 2003
    Location
    Huntsville AL
    Posts
    689
    Mentioned
    4 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Hall of Famer View Post
    If so, how much is the performance cost compared to standard database operations?
    Wrong question. You should be asking: If so, how much will the performance cost impact my application?

    It's a CRUD app right? Throw an entity or two up on the screen, let the user makes some changes and press submit. Think the user will really notice if the response time is reduced by some tiny fraction of a second?

    But I let my users change hundreds or entities at time? Is that really a good user interface design? You really think a bit slower persistent layer will be notices after your hundreds of entities make it through the validation and sanitation process?

    But what if I had millions of users? You really think a simple crud app persisting to a single database will scale regardless of how you persist the data?

    But still, I want absolute maximum database performance. Then don't use auto generated crud. But consider the performance difference between a working auto-generated crud application and a non-working hand crafted application which was never finished because too much time was spent on optimizing the persistent layer.

  20. #20
    SitePoint Addict bronze trophy
    Join Date
    Apr 2013
    Location
    Ithaca
    Posts
    351
    Mentioned
    6 Post(s)
    Tagged
    1 Thread(s)
    I see, good point, thanks for your answer, I guess going for a database adapter or a service layer isnt gonna cost much on the performance compared to the actual database connection and query execution after all. XD

  21. #21
    SitePoint Addict bronze trophy
    Join Date
    Apr 2013
    Location
    Ithaca
    Posts
    351
    Mentioned
    6 Post(s)
    Tagged
    1 Thread(s)
    Well sorry for bumping this thread, I have an additional question about a service layer in a complex web application. I mean, should the service layer be domain-oriented or application-oriented. By domain-oriented I mean one service object per domain object/mapper object, and application-oriented implies one service object per controller object.

    One example I can think of is a CMS with a user system, in which the user can register, authentificate(login/logout), manage account and view profile. The domain model is User class, with UserMapper as its corresponding data mapper. The app controllers are register, auth, account and profile, which may have actions and params. In this case, would it make sense to define a UserService parallel to the User/UserMapper domain, or to define services like RegisterService, AuthService, AccountService and ProfileService associated with these app controllers? I know this can get confusing, service layer after all is an intermediary between Domain(model) and Application(controller) layer/logic.


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •