November 24, 2015
Salesforce is an impressive platform for building powerful applications that transform businesses, but it needs to be built carefully if you want it to be scalable, secure, adopted by users, and adapted to meet specific business needs. Over the next few weeks, I will cover key principles of Salesforce design, from best practices to common pitfalls, in hopes that this series will serve as a reference for your design efforts.
How many times have you gotten to the end of a project, about just push it over the finish line, and realized that you’ve missed something big?
To save you from that sinking feeling, let’s dive into architectural considerations around automation. In Salesforce, there are a few options for reacting to end-user actions with automated actions: Flows, Lightning Processes, Workflows, and Apex Triggers. Only Apex Triggers require writing custom code; you’d typically go down that route if the business requirements are too complicated to stitch together in the former declarative (code-less) options.
If you choose to go down the Apex Trigger road because of the flexibility and power it offers, here are some questions you should be asking yourself:
- Have you confirmed that you can place a trigger on this object?
As of Summer 2015, you cannot place triggers on some standard objects, including account team members, case team members, sales (opportunity) team members, user roles, and groups. This means that code cannot immediately detect and respond to objects when they are inserted, updated, or deleted. This has implications in designing custom sharing architecture in Salesforce. You can check if it is possible to create a trigger on an object by going to the Developer Console and creating a new trigger there. If it is not possible to create a trigger, then you might want to consider a batch job that runs periodically.
- Have you confirmed that your trigger will fire for all use cases?
Let’s walk through a hypothetical example. Charlie’s client wants him to build aggregate summary fields on the account object which sum up details stored on contacts. His first thought is to create “roll up summary” fields, a declarative feature that Salesforce offers to build aggregate summary fields without using code. But he knows that won’t work, because the relationship between a contact and an account doesn’t qualify for using roll-up summary fields.
So, he opts to create custom fields on the account object to be maintained by an apex trigger on the contact object. He decides that this trigger needs to run when a contact is created, updated, deleted, or even undeleted. His idea is that whenever a contact is affected, automation will update the summary fields on the respective account.
This passes his brief testing, so he promotes the code from his sandbox to the live Salesforce instance. But after a few weeks, the client reports that the summary fields are inaccurate about 3% of the time. It seems to be working — but not always.
What could be happening?
Did you know that apex triggers don’t run on child records that are re-parented after a merge? In other words, if a data steward saw that there were “Acme Inc” and “Acme Incorporated” accounts in Salesforce, and then merged the accounts together, when the losing account’s contacts are re-parented to the winning account, the contact trigger is not fired. This means that some contacts sneakily changed accounts without triggering the automation that keeps account summary fields up-to-date.
How could you have accounted for this use case?
Although triggers do not fire for re-parented contacts, they do fire for the winning and losing account records. You can build an account trigger that fires when the losing account record is deleted, and there update the winning account’s summary fields. In doing so, you need to keep in mind that there are salesforce limits on how many records can be queried and updated.
There are more end-user actions that don’t fire apex triggers and can trip you up. Salesforce keeps track of operations that don’t invoke apex triggers: http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_trigge...
- Is your trigger targeting the right fields?
Watch out to make sure your trigger is on the right object and the right field(s). Let’s say that you have a formula field on contact that is derived from data on the account. You are told that whenever the value calculated by the formula changes (because relevant fields on the respective account were updated), you need to do something automatically on the contact.
You can’t build a trigger on the contact object and have the trigger watch for when the calculated value in the formula field changes. These “calculated” values do not persist in the database, and therefore it will not be possible in a trigger (or, for that matter, a workflow) to see that there has been a change.
In a nutshell, don’t build triggers that should fire upon changes to values in formula fields — this is a common pitfall. Rather than building a trigger on a reflection, you may consider building it on the source, while bearing in mind that there are Salesforce limits on the number of records that can be updated by a trigger.
Hopefully this blog has helped your trigger design efforts. To learn more about Salesforce design, connect with a Bluewolf expert.