Andy in the Cloud

From BBC Basic to Force.com and beyond…

Apex Enterprise Patterns – Domain Layer

32 Comments

In the previous article, the Service Layer was discussed as a means to encapsulate your application’s programmatic processes. Focusing on how services are exposed in a consistent, meaningful and supportive way to other parts your application, such as Visualforce Controllers, Batch Apex and also public facing API’s you provide. This next article will deal with a layer in your application known as the Domain Layer.

Domain (software engineering).“a set of common requirements, terminology, and functionality for any software program constructed to solve a problem in that field”

Read more at developer.force.com!

AEP_figure0

32 thoughts on “Apex Enterprise Patterns – Domain Layer

  1. Andy, you state that the place to do validation logic is in the after of the trigger and that it is a best force.com practice. Is there any additional documentation to support this view? Most people I have chatted with say that they do the validation logic in the before of the trigger which is where I have always thought is the best place to put it.

    • The main reason for this, especially if your building a managed package (as apposed to a customisation in an org you own), is that you can be sure no other trigger has tampered with the field data (since in the after phase the records cannot be changed). Multiple Apex Triggers can be assigned to one object and are executed in a none deterministic order, so if you do your validation in the before, someone could get lucky by adding a trigger and change the value after your validation has fired and you would end up with invalid data stored in your records.

  2. Hi, Andrew

    This is great, I saw this in a developer.force.com post a couple of months ago and I am using some of the patterns in my projects.

    Currently I am taking the Advanced Developer certification assignment (501), but I am not sure if i should implement this patterns, i don´t know if the judge might get confused by this or think is not necessary.

    I want to ask you your opinion, and if you think is a good idea, or should i keep it simple and do it only in the trigger and services.

    • Excellent great to know! As you’ve read many of the patterns, design guidelines and base classes provided help promote and enforce things they will be looking for such as bulkification and security considerations, however I would expect as it is an exam condition they may want to be completely confident that is all your own work and that you understand the principles rather than just inherit them from using the base classes etc. So I would stick to the principles broadly but not explicitly reference or include them for your exam submission, purely to avoid them misunderstanding of your understandings if that makes sense?

  3. With those pattern-orientated design where do you put your tests? Imagine you want to expose functionality on a page, so you have code in a Controller class delegating to a Service class, itself delegating to a Domain class.

    Do you create a slightly adapted test method for each of them (assuming you also use the pattern to have one Test class per regular class)?

  4. Hi Andrew, I have been reading and rereading your design pattern as I am trying to ensure that I fully understand the base principals and how everything connects before trying to implement anything. I’m still a ways away and I have one question that I hope you might answer for me. When using the domain layer and overriding the base methods such as onAfterInsert and onAfterUpdate, is best practice to create a help class class to hold repeatable logic? I find myself needing to perform the some of the same functions in an AfterUpdate/AfterInsert or BeforeUpdate/BeforeInsert and want to know how you would handle that.

    Thanks for your time!

    Regards,
    Tyler Mowbrey

    • Hi Tyler, great question!

      For this i would be inclined to create a base class (which extends fflib_SObjectDomain) and have your domain classes extend it.

      There is an example here, https://github.com/financialforcedev/fflib-apex-common-samplecode/blob/master/fflib-sample-code/src/classes/Chargeable.cls and here https://github.com/financialforcedev/fflib-apex-common-samplecode/blob/master/fflib-sample-code/src/classes/DeveloperWorkItems.cls. This example also uses virtual methods to customise the behaviour of the base class, you may or may not need this.

      • Hi Andy,

        Thanks for the quick response! Let me provide some background on what I am doing as well as what I believe the design should look. If you have some time to provide some feedback it would be most appreciated!

        Currently the system I am working in has a need to display three data points on the case detail page. Lets call these points SumA, SumB, and SumC. SumA is the total number of cases with a set value that the case account owns. SumB and SumC are representative of the number of subscriptions that the case account currently has with use (of two different types). This calculation needs to be completed when any new case is created and on subsequent updates.

        So ultimately I will have my Cases domain class override the SObject base class onBeforeInsert and onBeforeUpdate. Those methods would call an internal method which would ultimately be responsible for completing the calculations of Suma, SumB, and SumC (using selectors to pull data as necessary from Accounts and Subscriptions).

        Hopefully this makes sense. Let me know if I am understanding the pattern correctly.

      • Hi Andy,

        In going through this exercise, I would amend what I said below. My understanding now is that I would actually create a new base class to encapsulate the calculations, lets call it SubscriptionCalculation. Within that base class I would then create my domain class, Cases, which would extend SubscriptionCalculation. Now I can use my domain class to set the specific fields I need to update and and pass the required information to the base class to perform the actual calculation work. I see that this also help significantly if I need to expand the scope of work to show the subscription calculations on the account or another related object as the relevant domain class would just extend this base class.

        Hopefully this sounds like I’m getting the flow of the pattern.

        Thanks so much for your feedback!

      • You are indeed, spot on! Feel free to share (privately if you prefer) a Gist if you want a code review.

  5. Hi Andrew,

    Another question as I work my way through my test example. What happens down the road when I want to implement other trigger functionality related to cases? My understanding is that I can only extend one base class. So if I have Cases extends SubscriptionCalculation, I need to create a separate domain class to handle anything that would require dealing directly with the base class, is this correct? Would I be better off creating a separate domain class called CaseSubscription and extend SubscriptionCalculation and a general Case domain and extend SObjectDomain? My confusion is really stemming from the understanding that my domain class should be tightly coupled with a physical object.

    Look forward to hearing your thoughts!

    Tyler

    • Yes Apex does not support multiple inheritance, most OO languages these days don’t either. It was determined that interfaces (you can also see an example of this on the Opportunities domain class example) and single inheritance covered most OO use cases, so thats what Apex, Java and .Net go with. Note you can extend and extend multiple times, if you find you have shared behaviour between a number of domain classes, you can engineer this through layered base classes if you wish.

      I’m not sure i fully understand what you mean by “i need to create a separate domain class to handle anything that would require dealing directly with the base class”, if i am interpreting this correctly, no its not correct, classes extending another can see its public and protected methods, members and properties, so if you have a common utility method in the base class extending classes can access it no problem. Is this what your trying to do?

      It may be better to do this over a Skype call though, if you follow me on Twitter and me you, i can direct message you my contact details.

  6. Hi Andy,

    Quick heads up, in your SObjectSelector() when using the standard selectbyid, because of getOrderBy() always returning name, you will get failures if you use any object without a name column, such as OpportunityLineItem.

  7. Hi Andy, thanks for the nudge that the getOrderBy is overridable (I’m kicking myself now for missing that!).

    I have inherited a system at a new position (a few months in now) and there have been some design choices that I may have pushed back on. We currently have a site that allows guest users to purchase products. Those products result in a case being created for the order and then custom line items being added for fulfillment. As a guest user profile does not have access to update/delete records, I found myself in somewhat of a bind when I implemented a Case Domain Class and accompanying Case trigger. My question goes to handling this exception, I was thinking about modifying the SObjectDomain class to ignore the Site User ProfileId in the conditional statements. Do you think this is a good workaround? Any other ideas you might have?

    As always I really appreciate your help and ideas!

  8. As I use these patterns, I now realize the brilliance of the Domain Layer. Whether constructed via a Trigger with OOB transaction scope of 0-200 records or manually constructed by a method in a service layer (or other domain object) with the results from a selector, the methods within the domain layer always work against the super class’s Records variable so one can share logic and not care about invocation context. This truly breaks up the trigger + handler class mindset so common in the Apex world. Very nice!

  9. Question from a noob (if this thread still gets responses). We have a large org (10K users, 1000+ objects… 20+ objects with multi-million record counts). We need to start refactoring due to hitting limits and just overall poor structure. I’m new to Apex (from .NET world) and trying to build the foundations for refactoring using the SOC / Ent Patters model. The question I have right now is about the domain layer.
    Supposedly all CRUD (sans R) events happen there. I’m trying to understand if there is any value in adding a primary sObject insert/update/delete method in the domain layer as opposed to having external entities (controllers, batch classes, etc…) just call the native insert/update/delete methods and allow the trigger handler mechanisms to do their thing?

    The only thing I can think of, is it could allow enforcement of the uow… but is there any other reason?

    • Keep in mind triggers are invoked from other contexts that manipulate record data, sf rest API (and thus all manner of integrations), native UI’s, workflow and process bulkier tools etc… So as a minim you may want logic / validation / defaulting that protects the domain specific integrity of your data regardless of how it’s manipulated. Sometimes folks go to far and try to do to much in triggers, this logic either belongs in the controller or service layer (more task / process based logic). Hope this helps!

  10. an interesting nuance: Domain classes (as per the fflib_apexcommon-samples have this method:

    public static IOpportunities newInstance(List sObjectList)
    {
    return (IOpportunities) Application.Domain.newInstance(sObjectList);
    }

    If sObjectList happens to be an empty list of SObject (not an empty list of Opportunity), then Application.Domain.newInstance fails because an empty list of SObject has no SObjectType (val = null) . This can happen if one is chaining methods together where a method might return an empty list of Sobject. A good example of this is the following using the bluewolf beyond-selector github:

    Account[] accts = [select id, name from Account];
    Account[] acctsWithoutName = Select.Field.notNull(Account.name).filter(accts); // empty list of SObject is result
    Accounts.newInstance(acctsWithoutName).doSomething(); // throws exception as sobjecttype of acctsWithoutName is null

    This suggests that the standard fflib domain newInstance method should look like this:

    public static IOpportunities newInstance(List sObjectList)
    {
    return (IOpportunities) Application.Domain.newInstance(new List (sObjectList));
    }

    If sobjectList is empty and not of a concrete type, then the new List (sobjectList) will ensure that there is an empty list of Opportunity and hence getSobjectType() will be Opportunity, not nul — l and Application.Domain.newInstance will succeed

  11. aargh — wordpress mangled the method that should read:

    public static IOpportunities newInstance(List sObjectList)
    {
    return (IOpportunities) Application.Domain.newInstance(new List anglebracketOpportunityanglebracket (sObjectList));
    }

  12. Hi Andy

    Is there a blog post about choosing between Domain Layer and Service Layer when in doubt ?

    We have some much login built on triggers so, our domain classes are getting huge.

    For example

    1. we 25 field defaults based on the different criteria so we created a helper class for it

    2. We have to update related records from different objects
    3. we have complex validations

    so we created helper class for validations, helper class for applydefaults

    Is there a better design pattern to extend the domain classes ?

Leave a comment