Extending Salesforce sObjects with Methods
Unlike classes in traditional programming languages such as Java and C#, Salesforce database objects (sObjects) cannot be extended with user-defined methods.
As a result, object processing code is scattered across triggers, lightning actions, batch processing and even REST API calls.
This can turn out to be error prone and expensive to maintain, especially for complex processing logic.
This post describes a design pattern that can circumnavigate Salesforce limitations, leading to clean code with low-touch maintenance.
The ideal scenario
The lack of extensible sObjects prevents writing APEX code like this (a custom contract object is used as an example):
Contract__c contract = [SELECT ...]; contract.start(...) contract.renew(...); contract.terminate(...);
In the scenario above, methods would encapsulate logic for each operation (such as contract renewal). As a result, triggers, Lightning actions and batch jobs would become much simpler.
An alternative approach
The following approach can overcome sObject limitations:
- Determine methods for the object. It is a good practice to identify verbs that stakeholders use to describe it (e.g., when a contract is signed, the contract is renewed) and convert them into method names.
Best practice Design methods as if designing an API to manipulate the object
- Create a static helper class with methods determined in #1 above with object as the first argument. This is exactly the same pattern as extension methods, e.g., in C#.
Best practice “Bulkify” methods (i.e., make them accept arrays rather than individual objects as arguments) to make them easily usable in Salesforce triggers
- Unit test the helper class.
- Update your triggers, batch jobs, aura classes to use the helper class, so there is only one place for testing & implementation of the processing logic.
- If need be, expose helper class methods via REST as an external API (more information here). If you did a good job in #1, you should have all methods you’ll need for easy integration.
This approach may be thought of as creating a microservice around a Salesforce object. |
Handling object status changes
Most useful objects have a state/status field. In case of the contract example above, it might look as follows:
Draft → Signed → Terminated
Let’s consider the following business requirement:
if Contract Status was changed to Signed, send an email to customer
Very often, the initial implementation of this logic would be to add or modify the trigger code to look for status change and send the email.
This is an anti-pattern leading to unmanageable code and many admin interventions (could you please change this status but disable trigger for the moment, so email is not sent?).
The correct way to address state changes it to drive them via actions. For example, in the scenario above, create a Sign action which calls the sign() method and all the logic is in the method (send mail, save log, re-calculate non-formula fields, etc.). An example is presented on a screenshot below – Start, Complete and Restart are actions invoking helper methods:
Conclusions
The pattern outlined in this post enables extension of Salesforce sObjects with an API that is easily consumable via triggers, quick actions, batch jobs and REST API classes.
Additional benefits include:
- Clean, easy to maintain design
- Compact code with well-defined entry points
- Easily testable
All of the above mean lower cost of development and maintenance.
Nextian is a vendor of Quote-to-Cash (QTC) software for cloud and communications helping providers accelerate growth and increase customer lifetime value.
Contact us today to find out how we can help you!