I often get asked to write triggers to detect the existence of certain types of data in Salesforce and, when such data exists, make a modification to some other data.
The only problem is, writing "a trigger" isn't always easy to do in a well-normalized database (that is, a database that leverages master-detail and lookup relationships to avoid redundant data entry).
Take, for example, an architecture where "App Document" records have a master-detail relationship to a parent "Admissions Application" and the "Admissions Application," in turn, has a master-detail relationship to a parent "Contact" record.
The other day, I was asked to automatically flip the "Status" to "Waived" on any "App Document" records that meet the following criteria:
- The record is of type "English Proficiency" and is in blank/"Required" status
- The record's parent "Application" has an "application citizenship category" of "International" and a "level" of "Undergraduate"
- The record's grandparent "Contact" has a "foreign citizenship country" of "United Kingdom," "Ireland," "Canada," "Australia," "New Zealand," (etc.)
This is ill-suited to a Trigger/Process/Workflow because I would actually need THREE "insert"/"update" automations, each with relatively redundant code:
- one for all Contacts
(in case the citizenship country changes ... then go looking for appropriate "child" apps and "grandchild" documents) - one for all Applications
(in case the "application citizenship category" or "level" changes ... then double-check the parent Contact's citizenship and go looking for "child" documents) - and one for all App Documents
(check the parent & grandparent details and change self if appropriate)
Yikes! That's a lot of redundant trigger code, and some of those operations aren't very efficient against Salesforce governor limits.
Especially since just one SOQL query can easily fetch the ID of all "App Document" records whose "Status" needs to be set to "Waived":
SELECT Id FROM AdmDocument__c WHERE Type__c='English Proficiency' AND (Status__c = NULL OR Status__c = 'Required') AND Application__r.Level__r.Name='Undergraduate' AND Application__r.Citizenship_Category__c='International' AND Application.Contact__r.Foreign_Citizenship_Country__c IN ('Australia','Canada','Ireland','New Zealand','United Kingdom')
When someone asks you to "write a trigger" or "write a process builder" or "write a workflow" to automate data migration inside of Salesforce, be sure to ask yourself, "How many tables' values changing could cause a scenario to arise that would make this data need to be modified as requested?"
If the answer is "2 or more," and especially if it's "3 or more," think hard about whether "every 15 minutes" / "daily" is frequent enough for your end users to see "automatic fixes," and whether a SOQL query could extract the IDs of the records that need to be changed.
If you can come up with a SOQL query that represents the "problem records," you should be able to use a schedulable ETL tool or scheduled Apex to "extract and load back" with much lower overhead against governor limits than triggers/processes/workflows would incur. Your future self will also thank you when someone (inevitably) asks for a change to your script.