Salesforce’s platform is designed to be a shared multi-tenant environment, so there are quite a few strictly enforced limits. These limits are called governor limits and for the most part, most of the errors can’t be handled which can result in a poor employee or user experience.
Most governor limit errors are a result of poorly understanding how Salesforce works, so they can be prevented by designing a better architecture and by taking advantage of the platform. For example, too many SOQL queries can be avoided by writing bulk-friendly code or using caching.
Spend Time Designing the Architecture
Rushing into coding a new solution or configuring a new solution should be done with hesitancy. In almost every situation I’ve been on a team that hits a governor limit that requires reworking things. Spending an extra few hours or maybe a few days on diagraming and documenting the solution could have likely saved a lot of rework.
Focus on deciding if you are primarily using clicks vs code and knowing the quirks of the platform: order of execution, governor limits, and some of the apex best practices.
There are a number of ways to make our triggers more performant and to avoid errors. In the blog article Apex Trigger Best Practices we cover them in more detail.
One Trigger Per Object
A single Apex trigger should exist for each object type because you don’t have a way of controlling the order of execution for Triggers.
An Apex Trigger Framework can help make your development easier and make your life a lot easier.
Triggers Have No Logic
Triggers can’t be directly tested – so it’s important that they contain very little logic. Instead, create services or utilities that can be called directly and tested.
Bulkify your code
Loops and unoptimized queries are one of the most common causes of hitting governor limits. By utilizing collections and doing bulk queries we can make our methods more efficient and more reusable.
In a lot of cases, I see errors because developers forget that triggers operate on batches of up to 200 records at a time instead of on just one single record.
The blog article Salesforce Apex Bulkification In 3 Easy Steps covers ways to make our code handle more records without spending a lot of mental effort.
Use Collections and Datasets
By using apex collections we can efficiently query data and store data in memory. By using the right data structures we can reduce our memory footprint or speed up our execution.
A Set is unordered and unique. To access elements in a set, you must iterate through all of the items.
I don’t generally use Sets unless I’m using it for storing a bunch of Ids or some strings that I need to work with where there’s a potential for duplicates.
Lists are the easiest collection to create and you’re probably already aware of them if you have written any SOQL. SOQL by default returns a list.
A Map is a data structure that allows us to really quickly index individual elements – it consists of a key and the data values.
Each Map entry contains exactly one unique key and its value. The key values can be any primitive value but are primarily a string or Id.
Any time I need to look up two pieces of data that can’t be queried at the same time, I generally use a map – it reduces the amount of code that needs to be run and allows much more efficient look-ups.
Use Batch Apex for Large Quantities of Data
There are really only a few different ways to be able to process large quantities of records on the Salesforce platform – all of the different methods pretty much involve asynchronous apex or more specifically batch jobs.
Batch apex runs asynchronously based on available resources and can chunk up the data per batch OR we can provide our own batch sizes. Using a Batch Job with the Query Locator, it’s possible to process up to 50 million records (50,000,000).
The blog post How to Process Thousands Of Records on Salesforce covers some of the different asynchronous methods that we have available for processing data or doing long actions.
Use Asynchronous Apex Methods Wisely
Asynchronous processing provides some really good advantages like
- Scalability: because the calls are queued up there’s a lot less limits that Salesforce Programmers need to be worried about.
- User Efficiency: employees, customers, and partners don’t necessarily need to sit around waiting for a long running process to finish.
There are times when asynchronous programming doesn’t necessarily make sense, find out more in the blog post Asynchronous Programming in Salesforce
Wrapping It Up
As frustrating as the governor limits can be, I know they have forced me to be a better software developer on Salesforce and in general. Spending some time upfront designing, before jumping into coding, can save dozens of hours of debugging and solving governor limits.
Bulkified code, using the right data structures, and Asynchronous Apex allow us to easily overcome a lot of the limits of the Salesforce platform.