A developer should not only focus on delivering something that works, but likewise or even more important, focus on something that is maintainable, can be understood in half a year from now and is written to be reused. Two key principles to support those ambitions are DRY (Don’t Repeat Yourself) and Separation of Concerns (each method should only focus on one purpose and each class should have a certain cohesion amongst the methods).

As a big fan of readable and maintainable code, I (eventually) really liked when my team started to apply the Enterprise Design Pattern per mid-2018. This lovely coding pattern allows to organise even the most complex and extensive code-bases. Enabling to:

  • …significantly reduce ramp-up time of new colleagues;
  • …apply one coding structure and naming convention which speeds up debugging and other analyses;
  • …increase reusability of existing code, as all comparable code can be found in the same class and therefore more easily altered to suit future needs.

In this article I’d like to share an introduction to the Enterprise Design Pattern, where in particular I’ll refer to the FinancialForce Library (FFLIB): Apex Commons (Github). They started sharing their thoughts on DreamForce around 2012/2013 (slides) and have been extending their library constructively. This pattern has nowadays even been adopted by Salesforce Trailheads as ‘Apex Enterprise Patterns’ (see: Service Module & Domain and Selector Module)

The principle

Enterprise Design Pattern (EDP) introduces a structure to organise your code into different ‘buckets’/layers/classes:

  • Selector class (SEL_*) – Object-specific, including all queries for that specific object in that code-base;
  • Domain class (DOM_*) – Object-specific, containing constants, methods and Trigger Handlers for that specific object in that code-base;
  • Service class (SRV_*) – Business logic specific, grouping methods which together support/shape a certain business logic; e.g. Integrations, User Access management, or other reusable logic like Platform Caching, centralised Request & Response classes, etc.

Example

Imagine the need to set the RecordType on Account instantiation. This would involve: 1) specifying the RecordType DeveloperName, 2) querying that RecordType Id.

Best-practices:
1) RecordTypes are often queried by Name. However one should be conscious that Names can change over time and might contain spaces, since they are shown to the end-users. Best-practice is to always query by DeveloperName, as those will never change;
2) Often, multiple RecordTypes are required in the same transaction and therefore it might be worth storing those in a static or even Platform Cache to prevent database interactions (queries);

Applying the Enterprise Design Pattern to the example above, could result in the following (simplified) code snippet.

public with sharing class SRV_NewCustomer{
  public void createNewAccount(){
    Account acc = new Account(
      RecordTypeId = DOM_RecordTypes.getRecordTypeId( Account.sObjectType, DOM_Accounts.RECTYPE_ORGANISATION )
	);
  }
}

public with sharing class DOM_Accounts{
  // domain constants
  public static final String RECTYPE_ORGANISATION = 'Organisation_Account';
}

public with sharing class DOM_RecordTypes{
  // static Map to prevent querying RecordType on each call
  private static Map<String, RecordType> recordTypeMap{
    get{
      if( recordTypeMap == null ){
        recordTypeMap = new Map<String, RecordType>();
        List<RecordType> recTypeList = SEL_RecordTypes.selectAllRecordTypes();
        for( Integer i = 0, j = recTypeList.size(); i < j; i++ ){
          RecordType rt = recTypeList[ i ];
          recordTypeMap.put(
            ( rt.SobjectType + '_' + rt.DeveloperName ).toLowerCase(), 
            rt 
          );
        }
      }
      return recordTypeMap;
    } set; }

  public Id getRecordTypeId( SObjectType objectType, String developerName ){
    String searchKey = ( String.valueOf( objectType ) + '_' + developerName ).toLowerCase();
    RecordType rt = recordTypeMap.get( searchKey );
    return rt != null ? rt.Id : null;
  }
}

public with sharing class SEL_RecordTypes{
  public List<RecordType> selectAllRecordTypes(){
    return [SELECT Id, DeveloperName, SObjectType FROM RecordType];
  }
}

Let’s have a brief look over the code:

  • SRV_NewCustomer is the Service class, which apparently supports the full business-process of creating a new Customer in this org. This class will most likely perform all checks and initiations of records to make sure the customer is properly created (and informed);
  • DOM_Accounts (yet) only contains the static for RecordType DeveloperName. Imagine how easy it is, when all Account related statics can always be found in the Domain class for that object?! E.g. DOM_Opportunities.STATUS_CLOSED_WON;
  • SEL_RecordTypes only contains queries to the RecordTypes object. Hence, all queries to RecordTypes will be found in SEL_RecordTypes;
  • DOM_RecordTypes shows (simplified) logic to query all RecordTypes, convert those into a static Map (only constructed once per transaction). Allowing easy RT retrieval based on the combination of SObjectType name and the DeveloperName of the RecordType.
    • Note, when querying all RecordTypes, it is highly recommended to store this in some Platform Cache (future article), else the performance benefit of this static Map might not be satisfied.

Impact

As mentioned, there are many positive consequences of applying the Enterprise Design Pattern. Personally, I believe the most important ones are:

  • Easy to find code
    • All layers are nicely grouped in any IDE or Salesforce UI, since the prefix is the same.
  • Untangled logic
    • Separation of Concerns, a class is now responsible to only the scope of EDP (Object or Business process specific)
    • Even in very complex process-specific classes, the code is untangled and easy to read. One easily sees the RecordTye Id is fetched, without being forced to read and understand the process of using a Map and so on. Only when interested, that person can decide to have a look at the definition.
  • Simplified Mocking (Test performance impact)
    • Each well-scoped method can be easily mocked (StubProvider or ApexMocks) preventing the need to setup Test Data and query per Test Method. For example think of the ability to fake the response of any query / Selector methods. (Before, queries were often tangled inside large methods, preventing to mock the result of that separate operation).
      • Mocking allows overriding a method to not perform the inner-method-code, but simply return that locally initiated response. With this queries can be faked and prevented to be even performed.
    • Thanks to this mocking, the runtime of Unit Tests can be significantly reduced, both due to the reduction of database interactions, but also by allowing @isTest( isParallel = true );
  • Significant increase in ‘reused methods’
    • Each method is untangled and has only one purpose (Separation of Concerns). And for that purpose it is ready to be called!
    • Since methods are grouped in logical places, like queries for one object, one can easily scan whether his/her required query has already been written out (instead of searching the whole code base) and re-use that (Don’t Repeat Yourself)

How to start

To implement Enterprise Design Pattern to your code, you could setup the logic and structure yourself, but I would highly recommend to have a look at the Apex Commons code-base and start with that. There are really clever techniques applied to simplify your life, but also keep track of performance.

To start applying the Enterprise Design Pattern, a fresh/new project is of course the easiest. However, for sure it is possible for (long-)running projects. My experience there: “just start“. There I’d suggest the following order:

  1. Queries – Move any new or altered query to the responsible Selector class;
  2. Constants – Move all new or altered constants to their responsible Domain or Service class (either per object or business process);
  3. Force EDP for all new code – Make sure all new methods are untangled and the Enterprise Design Pattern is fully satisfied;
  4. De-duplicate code – See your code-base for duplicated methods and move those to the correct class, updating all references (e.g. queries, instantiations of records, calls for RecordTypes, Error handling in DML Catch bocks, Security checks and so on);
  5. Untangle methods – When altering existing logic, start to untangle those methods, calling the correct Service, Domain or Service class (call existing, or create new methods);
  6. Force EDP for all code updates.

Note, the start might be challenging as you’ll have to consciously think of where to put the code. However, I can assure you this will become way easier over time and then every team member will understand where to find what kind of logic and code.

But where do I put…?

While this Pattern helps you structure your code significantly, it is not a holy grail which defines an answer for each scenario. Most important is to find alignment within your (project) team. Discuss the pros and cons to get on the same page/approach.

To help you get started, I’ve listed some common re-occurring scenarios below, including my considerations of where to put the code:

  • Utility methods, like ‘verifyNotNull()‘ or ‘generateRandomString()
    • I prefer to put those in an App class. The methods do not really share a common purpose. You could argue by EDP this should be in a Service class, but I personally like to really keep those for the larger (business) logic, which have a common goal (and not introduce a SRV_Common or SRV_Utils;
  • Custom Exception classes, e.g. public class MissingDataException extends Exception{}
    • Same applies here, I always put them in an App class to have an easy overview of all Exceptions. But when you have a specific SRV_Exceptions class to process Exceptions in the same way, or facilitate a certain logging or such, that could also be a very good place;
  • Page Controllers, either for Visualforce, Aura or Lightning Web Components (LWC)
    • Most likely the best fit is Service class, as it facilitates the process of that page, but you could discuss with your team to keep this a separate controller class;
    • Important: within Lightning Web Components (LWC) we can now very easily call methods from different classes, allowing to query one method from the SEL_Accounts and the other from SEL_Opportunities, instead of having those combined in one Apex Controller class (limitation of Visualforce and Aura Components). However, one should pay attention on the access that should be granted. If you grant access to SEL_Accounts in your LWC, every Guest User in Salesforce will have access to all @AuraEnabled methods in your SEL_Accounts class. So be cautious! (For this reason, one might argue the benefit of sticking to one Controller/Service class to reduce the risk of exposing too much).

Hopefully, you’ve seen there is not always one final answer. Do you have any scenario you feel challenged with? Feel free to reach out so we can weigh the pros and cons.

Conclusion

Hopefully, you’ve seen the impact of structuring your code and the significant benefits it might give you and your team. When implementing, I’d highly suggest to have a look at the fflib framework (Apex Commons), since this will get you up-to-speed within a day!

In addition, it is definitely not bad to have an ‘in-between’ period where part of your code is structured by EDP and another part is not. However, I’d like to emphasise it is important to try to get rid of that technical debt in the near future. Elaborate to your customer / product owner this will benefit everyone and capacity will be needed as investment.

Finally, the Enterprise Design Pattern is not to simply make code look better, but will have significant impact on readability, maintainability and adoption of code, reduce both unit test runtime and duplicated code and with that result in less bugs and more efficient delivery.

Happy (structured) coding! 🙂

How useful was this post?

Average rating 5 / 5. Vote count: 5

No votes so far! Be the first to rate this post.

We are sorry that this post was not useful for you!

Let us improve this post!

Tell us how we can improve this post?

One thought to “Enterprise Design Pattern (fflib)”

  • Cropredy

    Thank you for writing this. I couldn’t agree more with the sentiments expressed. The last 4 orgs I have worked on were all converted to fflib pattern to great success. SoC and mocking have been the biggest benefits; Whenever I look at code that is not fflib; I ache to migrate it.

    Reply

Leave a comment

Your email address will not be published. Required fields are marked *