In the previous blog post, SOC (Separation of Concerns) was discussed as a means to focus software architects into thinking about layering application logic. This next article in the series focuses on arguably the most important layer of them all, the Service layer. This is because, it is the entry point to the most important development investment and asset of all. Your applications business logic layer, it’s very heart!
Service Layer, “Defines an application’s boundary with a layer of services that establishes a set of available operations and coordinates the application’s response in each operation.” Martin Fowler / Randy Stafford, EAA Patterns
Continue reading more at developer.force.com…
February 18, 2013 at 9:25 pm
Reblogged this on Sutoprise Avenue, A SutoCom Source.
March 12, 2013 at 2:06 pm
Andy,
Again, this is a great series of articles. Can’t wait for the Domain Model write up!
Your examples of the “Data Mapper” and the concept of bulkification bring up a question for me. Martin Fowler talks about the following in his book “Patterns of Enterprise Application Architecture”:
“A simple Data Mapper would just map a database table to an equivalent in-memory class on a field-to-field basis.”
Your examples seem to suggest this pattern. What I mean is, the “Selector” classes will return standard Opportunity (and related) objects. The Opportunities class is a domain model “wrapper” around the standard Opportunity SObject (please correct me if I am wrong here). While the Opportunities are the “domain model” they are still only working with the standard SObjects.
My question is around what your experience has been when the Domain objects differ considerably from their database SObject counterparts? In my experience, there have been times where I could have a single SObject that contains data from several different domain objects. In Java, I would take the mapper class and map the values from the resultset to the corresponding location in the object. This is not a big deal at all. When I run into this scenario in Apex, I find that this type of “complex transformation” could come at a cost. Specifically, if the resultset is large, transforming of the resultset into the equivalent domain objects can eat away at the “max number of lines executed in the request” governor limit.
Have you run into similar issues? If so, do you have any advice about how to manage that the most efficient way?
I appreciate the feedback.
Cheers,
@JohnDTheMaven
March 14, 2013 at 10:49 am
Hi John,
Thanks for the feedback, much appreciated!
The Domain Model article is starting draft this weekend you’ll be pleased to know.
Your understanding of the Selector and Opportunities domain class construction is correct. These are examples of manifesting Domain classes around your applications physical data schema, and is most typical. However is not a hard and fast rule.
It is perfectly fine to have a logical Domain model (structured or flatten into a single class) encapsulating any logic around data that is an aggregate or mix of information from the database (or even some other data source such as a web service).
In this case a mapper class and methods on it would also encapsulate the various DB queries needed to retrieve this logical data into one. Such mapper methods would probably result in returning POJO type Apex classes or perhaps an interface that flattens a hidden set of SObject’s and/or AggregateResult objects for the consumers to access through. Using an interface will perhaps cut down on some of the transform cost, as your simply offering a facade over the underlying data your aggregating through it and not moving it around.
You might also consider that you might not need a domain class, if its purely read information, the POJO/Interface returned by your mapper could be considered a kind of “light weight” Domain class in this case.
This is certainly a good use case, I’ll look to weave an example of this into the upcoming article.
Cheers,
@andyinthecloud
January 20, 2015 at 12:11 pm
Hi Andy, really enjoying reading your book and I have a question around Service class vs. Domain class and where code should go. Normally service layer calls domain layer which has more granularity. But in some situations, what if triggers require ‘less granular’ operations, for example creating other objects? I guess I am not understanding fully the rules for what code goes in the Service class and what goes in the Domain class.
Cheers,
John
January 24, 2015 at 11:58 am
Hi!
Sorry for the delay in getting back to you, busy work week!
If it is part of the behaviour of one object to create records in another, i’d say that belongs in its domain class of that object, so in the domain / trigger method in that class. If its a common behaviour you might consider putting it as a kind of static factory method on the related object domain class and delegating to that from others in such use cases. Similarly in update scenarios its also reasonable to delegate to another domain classes instance methods. Note in both these cases, if your using it i would create a UOW scope in the top level domain class method and pass through to the domain methods called.
Generally if your finding your wanting to invoke code from the Domain layer you’ve already placed in the Service layer that implies its already being or available for use by something else as well. This can sometimes be kind of architecture smell. So when i see the domain layer calling a service layer it does give me pause for thought. I’m not a huge fan of making triggers do ‘task’ based logic, as the end user and platform API interactions are not hugely aware of the significance and it can lead to performance and governor issues. So be careful about what it is your doing and ask yourself if it is truly something that should be associated with a CRUD operation in your application or something else more task related like a VF page, custom button or scheduled job. Neither is wrong, but overused can result in an application that doesn’t respond well to being prodded from the numerous ways custom objects can be! 🙂
January 28, 2015 at 5:08 am
Thanks for the reply Andy – I understand the point about not having triggers do ‘task’ based logic as their impact can be unpredictable. But I guess that’s where good bulk tests come in?
I think the idea of the static method on the domain object would work – but I think I need to work through some real examples to be fully clear.
Thanks again – really appreciate you fitting this stuff in to your schedule.
Cheers
JD
June 2, 2015 at 1:00 am
Hey Andy,
I’ve been working on a project that is being built entirely on a service layer and custom rest resources. It’s a complete UI overhaul built on top of Salesforce data. I recently adopted your apex enterprise patterns to help add some maintainability to the code and reduce the number of decisions I have to make when adding code. It’s already paying dividends.
I have a question about querying data records through the service layer. Your examples take for granted that the caller already knows about the SObject (e.g. from a standard controller on a VF Page), and will be handling updates to the record itself (e.g. the Save action). That makes perfect sense when you’re on the golden path, but I’m having to bushwhack on this project.
If the caller doesn’t have it’s own way of getting and updating the SObject (i.e. custom rest resource consumer), how would you provide that ability to them? The pattern suggests this should all go through the service layer.
To mimic how the standard VF page does it, I have various service methods that return lists of SObjects obtained from selectors, and a service method that updates a list of SObjects passed to it through an argument. It doesn’t quite feel right though. I don’t really want the caller to be aware of the entire SObject, and I want to restrict what fields they can update through the service layer.
Cheers,
Logan
June 6, 2015 at 9:45 am
Hi, glad your getting results from the pattern usage, really encouraging. In terms of your service layer and SOBJect’s yeah, your spot on it kinda feels odd to trust the callers set the correct fields or even for new callers, they should not be expected to worry about which SObject fields to set. In these cases if you have a specific set of fields. In this case i’d be inclined to define a DTO (Data Transfer Object) (also a Martin Fowler pattern), using an Apex inner class in your service class. You can then have private methods in your service class to convert to/from this to the SObject as needed. Then the contract your exposing on your service layer is nice and clean and clear. You can also express read only properties this way, so if you happen to use the Apex class in method responses and as an argument you can help clarity which properties need to be set in the argument instance more easily. Hope this helps, great question and do let me know how you get on, it would be good to see some experiences in a blog of someone migrating an existing code base to the patterns. Cheers!
February 14, 2016 at 1:16 am
Hi Andy ,
I have been thoroughly enjoying reading your book . Its been so enlightening to know how to design enterprise scale application. Though most of the concepts are easy to comprehend , I tend to get confused between what should go into Service layer vs Domain layer. It will be very helpful if you can have provide cheat sheet explaining this part. Some times it appears service layer is only used as an entry point ,whereas domain layer has most of the logic . Can you please elaborate bit more on why should methods like awardChampoinshipPoints and applyDiscounts exist in domain layer . We can always have these in respective service layers and let one service layer call other service layer . I think question should be more around , what is the criteria that says this can be called as behavior of an object and can be part of domain layer
Thanks in advance !
February 14, 2016 at 9:07 pm
Thanks for the kind words. Yes his is a common question, will for sure deal with this in a future blog!
October 10, 2017 at 5:35 am
Hi Andrew, I am going through your book and finding it much informative and logical. However, I have once question around Batch Apex. I have a method in Service Layer which will insert into Usage custom object based on some logic. The method accepts Set of OrderItems Id. The method queries a record via SOQL (I have not yet reached selector layer) and based on business logic upsert Usages. If I call from the Batch Apex, I wil also have to query the OrderItems in Start Method and then get IDs of these records and pass that throught. Will that not be extra overhead?
October 18, 2017 at 6:43 am
Thanks glad your finding it a good read. In the performance chapter or service chapter I think I make reference in a tip call out that you can reuse the scope objects in the execute to pass to your service direct, but keep in mind they will be stale and not reflective of what’s currently on the database. Also not sure if you plan to make your service later your API or not, but sobjects make bad parameter types as it’s not clear to your API caller what to pass. Hence for both these reasons I tend to pass only ids and requery
October 10, 2017 at 5:43 am
Hi Andrew, I am going through your book’ Apex Enterprise Patters’ and am finding it very informative and interesting. I am trying to adapt the concept of Service layer in my current work, however i have a basic understanding question. I have a service layer which exposes a static function createUsageForFlatXXXCustomer(Set OrderItems){}. It receives a set of Order Item Id and queries the data and perform business logic to process Usage and do upsert at end. However, If I call the same form Batch Apex, would have to do the similar query in Start Method, and in Execute Method, would have to gather Ids from acutal object record to pass it to service layer. Isn’t that a overhead? Please suggest
October 18, 2017 at 6:46 am
I think I just gave an answer on your other comment that would apply to this as well. Keep in mind also that the start and execute methods are separate execution scopes, so you get fresh governors. Also keep in mind my other considerations in my other reply just now. Thanks 👍🏻
October 20, 2017 at 9:22 pm
Thanks Andrew for the clarification. Also, apologies for the repeat question . Probably the question got posted twice.
October 21, 2017 at 10:02 pm
Np