Extending Salesforce sObjects with Methods
Unlike classes in traditional programming languages such as Java or C#, Salesforce database objects (sObjects) cannot be extended with user-defined methods. As a result, object processing code is often scattered across triggers, Lightning actions, batch processes, and REST API calls, leading to fragmented and error-prone implementations.
This fragmentation can make maintaining complex processing logic both challenging and expensive. This post outlines a design pattern that circumvents Salesforce’s limitations, enabling cleaner code and easier maintenance.
The Ideal Code Structure
The lack of extensible sObjects in Salesforce prevents writing Apex code like this (using a custom Contract__c
object as an example):
Contract__c contract = [SELECT ...]; contract.start(...) contract.renew(...); contract.terminate(...);
In this scenario, methods would encapsulate the logic for each operation, such as contract renewal. As a result, triggers, Lightning actions and batch jobs would become much simpler.
An Alternative Approach
As mentioned earlier, Apex does not directly support extension methods; however, the following approach can help 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. In that case, the equivalent of code above would look as:
Contract__c contract = [SELECT ...]; ContractHelper.start(contract, ...) ContractHelper.renew(contract, ...); ContractHelper.terminate(contract, ...);
- 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 can be seen as creating a microservice around a Salesforce object.
Handling Object Status Changes
Most useful objects have a state or status field. In the case of the contract object example shown above, it might look like this:
Draft → Signed → Terminated
Let’s consider the following business requirement:
if Contract Status changes to Signed, send an email to customer
A common initial implementation of this logic is to modify trigger code to detect the status change and send the email. However, this approach is an anti-pattern that often leads to unmanageable code and frequent administrative interventions (e.g., “Could you please change this status but temporarily disable the trigger so the email isn’t sent?”).
The correct way to handle state changes is to drive them through actions. For instance, in the scenario above, you can create a Sign action that calls a sign() method. This method encapsulates all the related logic (e.g., sending the email, saving logs, recalculating non-formula fields).
An example is illustrated in the screenshot below: Start, Complete, and Restart are actions that invoke corresponding helper methods:
Conclusions
The pattern outlined in this post enables the extension of Salesforce sObjects with an API-like methods that are 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 testability.
These advantages lead to lower development and maintenance costs.
Nextian has extensive experience in implementing complex Salesforce customizations with Apex and Lightning, helping our clients unlock the full potential of their Salesforce.
Contact us today to find out how we can help you!