Sunday, January 5, 2020

Curiosity Unlocked: Can You Guarantee the Order in Which Triggers Will Fire?

January 05, 2020 Posted by Pat Penaherrera 6 comments
"One Trigger to Rule Them All."  This has long been a best practice and fundamental design pattern on the Salesforce platform.  Instead of creating multiple Apex Triggers on a given object, you create only one, and instead hand off execution of your business logic to a Trigger Handler framework (or equivalent pattern) which will orchestrate the execution of said business logic.  There are many reasons why developers take these wise words to heart.  One specific reason for this is that we cannot know the order in which Apex Triggers will fire when there are two or more triggers implemented for the same trigger event on the same object.  Or can we?  The truth may surprise you!



The documentation is very clear on the matter.  Per the Apex Developer Guide, "the order of execution isn’t guaranteed when having multiple triggers for the same object due to the same event. For example, if you have two before insert triggers for Case, and a new Case record is inserted that fires the two triggers, the order in which these triggers fire isn’t guaranteed."  Let's test this statement, shall we?

First, Some Test Prep

First things first.  Before we experiment, make sure you do so in s a safe place, such as a scratch org, Trailhead playground, or a personal developer org.  I do not recommend testing within any client- or employer-owned orgs, for obvious reasons.  If you have not worked with scratch orgs before, check out this quick-start module on Trailhead.  And if you are new to Trailhead and Trailhead playgrounds, check out this trail which will walk you through getting started on this amazing (and free) learning platform.

Ready to go with a safe and fresh org?  Okay, let's do this.

Now for the Fun Stuff

You can run this test against any SObject, but I've used the Account object for the purposes of this demonstration.  Start by creating a simple trigger like the one shown below in your development environment of choice.  In my example below, I am creating a before insert/before update trigger.

trigger AccountTrigger1 on Account (before insert, before update) {
system.debug('Running AccountTrigger1...');
}

Create a few more triggers just like this one. I recommend numbering the triggers both in name and in the debug statements so that they can be easily identified later when we run our tests and view our logs.  For my testing, I created seven (7) triggers, e.g. AccountTrigger1, AccountTrigger2, ... AccountTrigger7.

Next, deploy the triggers to your fresh, clean test environment.  Navigate to Setup > Custom Code > Apex Triggers and you should see your triggers listed nicely on the page.  You should have something similar to the below.

Apex Triggers Menu in Setup

Open up the Developer Console and click on Debug > Open Execute Anonymous Window.  Since our triggers cover the insert and update events, creating or updating a record will suffice to trigger our tests.  Write a couple of lines to create a record for your SObject (the Account object, in this example), as shown below.  Check the option to Open Log and click Execute.


Filter the log to Debug Only and review the results.


Pretty interesting, huh?  It appears that our triggers ran in order!  We'll talk more about what that order may have been later.  But, perhaps this was a fluke.  Run another test using the Dev Console by inserting another record and generating another log.


Again, our triggers ran in the same order!  Two in a row, but perhaps still a fluke.  Run the test as many more times as you like.


Without a hitch, the triggers execute in the same order every time.  This is pretty amazing stuff considering that we've always been told that the order of execution in this scenario cannot be guaranteed.  We've been taught to expect (or at least, we've inferred) that the order would be random with every execution context.

What Does This Mean?

At this point, we can make a few educated guesses as to what may be happening here.  We can deduce that the platform may be using the Trigger Name, the Created Date, or the Last Modified Date/SystemModStamp to determine a fundamental order of execution.  We can't change the Created Date for any of these, so let's skip that for now.  Let's look at Last Modified Date/SystemModStamp and see if they are the culprit (as this is arguably the easiest to test of the three).  Modify one of your triggers with an arbitrary update like the one below, save, and deploy to your target environment.

trigger AccountTrigger3 on Account (before insert, before update) {
system.debug('Running AccountTrigger3... this one was modified most recently!');
}


In my example, I modified AccountTrigger3 and updated the debug statement so that it would pop in my logs.  If the Last Modified Date/SystemModStamp are what drives the execution order, then this trigger should jump to either the front or the back of the execution list when we run our next test (depending on the sort order used by the platform).

Now let's run another test and see what happens.


No change!  The order remains the same.  So, we know that the Last Modified Date/SystemModStamp is not the factor driving the execution order here.  What about the Trigger Name?  Could that be it?  Let's modify the name of one of our triggers and see what happens.

trigger AccountTriggerX on Account (before insert, before update) {
system.debug('Running AccountTriggerX... formerly known as AccountTrigger5!');
}

In my example, I changed the name of AccountTrigger5 to AccountTriggerX and updated the debug statement so that, like AccountTrigger3, it would pop in my logs.  If the server is using the Trigger Name to determine the order of execution, the results of our previous tests would suggest that the sort order being used is ascending order.  Therefore, I'd expect AccountTriggerX to drop to the bottom of the execution list, and be executed last when we run our next test.  Let's create another record and see what happens.


Amazing!  The order still hasn't changed.  AccountTriggerX is still showing as the 5th executed trigger in the list.  So we've ruled out two of the three obvious choices, with Created Date left on the list.  What happens if we create a new Apex Trigger and add it to the mix?

trigger AccountTrigger8 on Account (before insert, before update) {
system.debug('Running AccountTrigger8... this one was created after the original 7!');
}


In my example, I've introduced AccountTrigger8, created some time after the original 7 with which we started.  If Created Date is determining the execution order, then given that the first 7 triggers were deployed to the target org at the same time (and therefore have the same Created Date), I would expect this new trigger to be executed last for ascending execution order on Created Date (i.e. oldest triggers are run first), or first for descending execution order on Create Date (i.e. newest triggers are run first).  The moment of truth is upon us... let's create a record and see what happen.


[Editor's Note: At this point, Pat put on sunglasses so that he could take them off slowly, and dramatically.]

A Plausible Solution?

My word.  What it would appear we have here is a potential answer to our question.  It would appear that the Created Date is the key factor used by the platform to determine the execution order for our multi-trigger scenario.  Based on our findings, the oldest triggers appear to be executed first, and the newest executed last.  Let's add one more brand-new trigger to the mix, and then subsequently create a few more records to see what happens.


It holds up.  The newest trigger (now AccountTrigger9) was executed last, and the order of execution amongst our triggers remains consistent.  Could this be a mind-blowing discovery?  It certainly seems that way!

But Wait--- A Surprise Twist!

I decided to run one more test by again introducing a new trigger into the scenario.  This time, however, I gave the trigger another name outside of the convention I had be using.  I named the new trigger GammaTrigger, and ran a few more tests by creating records and observing the results.




Dang!  Our perfectly plausible solution has been debunked right before our eyes!  Notice how the GammaTrigger--- now the most recently created trigger of the bunch, and 10th overall--- has been executed in between the 7th and 8th triggers in our set.  This busts our theory that the Created Date is the driving force of our trigger execution order.

Wrapping Up What We've Learned

While our Created Date theory may have been debunked, it does not mean that our efforts were in vain.  Running a few more tests (i.e. firing our triggers again via the creation of new Account records) after the creation of the final GammaTrigger above confirmed that the order of execution for our triggers remained consistent.  Sure, we still don't know what the platform is using to determine the order of execution for our triggers in this scenario, but it does appear that it is using something consistently.  It seems that the order of execution for our triggers is reliably consistent until such time that you introduce another trigger into the scenario, at which point the order is adjusted and once again hardened until the next trigger is introduced (or removed).  

Our results suggest that you can guarantee the order of execution when having multiple triggers for the same object due to the same event.  That sounds like a success to me!

And with that said, sticking to one trigger per object is still by far the best advice on this topic. ;)

For the Exceptionally Curious

I did also test a few other scenarios which I did not cover in depth within this post in order to keep the post at a relatively reasonable length.  In case you were wondering what those were, below are a few bullets to summarize my additional findings.
  • Our results are consistent across other standard SObjects as well (I ran similar tests against the Lead object to ensure that this was not somehow a fluke isolated to the Account object).
  • The size of our triggers (without comments) does not appear to be a factor in determining the order of execution.  If you review our screenshots earlier in the post, you'll see that the order in which our triggers fire has no apparent correlation to the size of said triggers.
  • If you introduce a Workflow Field Update into the scenario (which then causes update triggers to run once more), debug logs show that the applicable triggers still run in the same order for their second invocation as well.
  • Running the tests with different trigger events produces the same results (although admittedly I did not test all trigger events).
  • Running the tests the next day (in order to account for any potential server-side caching effects) produces the same results.
  • Following my tests, I searched the web to see if anyone else had already stumbled upon similar findings, or perhaps if someone had already ventured further than I have and discovered the whole truth regarding what drives the order of execution for our scenario.  As of this publishing, I have not found any other articles or posts on this specific topic.

So what do you think of our findings?  Let me know your thoughts in the comments below, and feel free to share any findings if you consider running a few experiments of your own!  Excelsior!

Wednesday, January 1, 2020

Top 10 Unlocked: Spring '20 Release Preview

January 01, 2020 Posted by Pat Penaherrera No comments


The Salesforce Spring '20 Sandbox Preview is nearly upon us (for more information on the Spring '20 Sandbox Preview window, check out this blog post from Rohit Mehta on the official Salesforce Blog for all of the details).  If you're like me, you can't wait to get your hands on a sandbox preview instance.  You've also likely been diving into the Official Release Notes (currently in preview) to get a glimpse at all of the "cool new toys" that will come packed within this release, earmarking those that will likely have the most impact for you, whether that's due to your current role or active projects, or due to your personal interests and curiosities.

As this is my first official "Top 10" list, I'll share a little bit about what you can expect to see.  Firstly, these lists will be based on my personal opinions and nothing more, or nothing less.  Secondly, I'll be focusing more on sharing my unique opinions, thoughts, and insights related to the items in the list versus regurgitating the available source material.  In this case of this specific Top 10 list, it means I won't be rehashing the specs for any of the features that make the list unless it's relevant to the context of my opinions.  Instead, I'll link out to the feature summary within the Spring '20 Release Notes so that you can learn more.

Without further ado, here are my Top 10 Feature Picks for the Spring '20 Release!

#1 - Before-Save Updates in Flows

I'm truly excited about this one.  Flows have come a long way since they first hit the scene years ago (GA in Spring '12 and as a beta/pilot before that), and they have the capacity to be incredibly powerful automation tools.  I've been sharing within my circles that the Flow Builder, or rather what it has become, is essentially a Visual Trigger Builder.  With Spring '20, that statement has never been more valid (of course, it is more than that, too).  Admins and App Builders have been empowered to create super-efficient update procedures, essentially equivalent to Before Insert/Update Triggers, solely using Flow Builder (no development required).  What I find even more fascinating is the statement that "before-save updates in flows are executed immediately prior to Apex before triggers" in the Save Order of Execution.  How crazy is that?  Flow is now usurping Apex Triggers in terms of precedence!  Personally, I am curious to learn what this means for the future of development on the platform.  With so much investment from Salesforce in expanding the capabilities of the declarative automation tools on the platform, what will become of programmatic tools like Apex Triggers?  Could Salesforce be laying the groundwork for a future without Apex Triggers as we know them?  Probably not.  There are still plenty of use cases for Apex Triggers today, so this is likely not the case (or at least, not for quite a while yet), but the move definitely made me ask the question.

Another exciting enhancement for Flows!  And, if I might add, long overdue.  Old-school Workflows and Process Builder have long been running in System Mode when it came to things like Field/Record Updates, but not Flow.  If you wanted to do something like, say, update the Record Type of an Account based on the selections of a user in a Screen prompt, the user would have to also have permissions to create records with that Record Type, too.  If not, the Flow will thrown an error.  Previously, you could get around this with some ugly tactics (such as updating another field on the record that then triggers a Workflow or Process to flip the Record Type, or worse, create an Invocable Method in an Apex Class to do it, which you call as an Apex Action in your Flow), but who'd want to do that?  Now, you'll never have to think such ugly thoughts again.  Enter: System Mode for Flows!

Oh, remember what I said earlier about Flow Builder being a Visual Trigger Builder?  More evidence to support my bold claims.  Again, I cannot help but wonder what grand plans Salesforce has for the future of development on the platform when declarative tools like Flow Builder can now go toe-to-toe with programmatic tools like Apex Triggers.  The goal, I'm sure, is simply to empower Admins and App Builders to do more without the need for expensive custom development, but I continue to wonder.


#3 - Turn Off Automatic Preview Updates to the Lightning Report Builder

FINALLY!  I cannot tell you how frustrating it has been to create or update reports using the Lightning Report Builder.  Sure, reports look great in Lightning, but dang!  Talk about a painful experience.  I had previously requested this capability on the IdeaExchange a while back, and I'm just happy to see that it is finally coming.


#4 - Permission Set Groups are Generally Available

The future of permissions management is here!  Permission Sets were a game-changer when they first debuted, and now that Permission Set Groups are generally available, the game has changed again.  The release notes provide a great example of how you can organize permissions efficiently using Permission Sets and Permission Set Groups, but there is so much more value to this pattern than meets the eye.  Firstly, this pattern allows you to organize permissions in a meaningful way.  You can now break down the "happy soup" of permissions that used to be mixed together in a single Profile into reusable collections, which is a huge cost savings from a maintenance perspective.  This is more or less the same best practice followed by developers when managing popular snippets of code.  For instance, you never want to replicate or rewrite the same snippet of code within two or more Apex Classes.  This creates a maintenance nightmare.  Imagine if the requirements for that snippet change at any point in time.  You'd then need to update all Apex Classes where the code is replicated, which is many times more effort than should be needed.  Plus, if you forget to update one of those classes, then your business logic breaks for any application using that class.  Instead, a developer creates a single utility class that can then be referenced by any other applications or code that may need it.  If the requirements change, the developer updates the utility class once, and all consumers benefit from it.  It is now the same with permissions.  Instead of replicating the same permissions across multiple Profiles, use Permission Sets to centralize those permissions.  Group related Permission Sets into Permission Set Groups that represent job roles, and assign those Permission Set Groups to your users.  If access requirements change, update the applicable Permission Set once, and all consumers (i.e. your assigned users) benefit from it in one fell swoop.  Beautiful!  And secondly, with such a pattern, your dependency on Profiles is significantly reduced.  In fact, for my implementation, we've put out a "cease and desist" notice on the creation of any new Profiles going forward.  Unless there is an absolute need, we're investing instead in Permission Sets and Permission Set Groups, and the vision of the future I've outlined above.

Personally, I think the writing is on the wall: Profiles are the on their way out.  Granted, there are still some things that we rely on Profiles for today (such as Page Layout Assignments, IP Restrictions, etc.) but I suspect that will change with future releases.  We're already seeing less of a need for traditional Page Layouts with the new Dynamic Layouts feature in the Lightning App Builder, and that is another dependency down.  I predict that the sun will be setting for Profiles altogether; it is only a matter of time.


#5 - URL Hacking in Lightning Experience

Not too much to say about this one.  We had other options for creating the same type of behavior, but it took a little more work to accomplish.  I always appreciate a good "URL hacking" here and there (I know it is not technically a "hack" if it is a supported feature of the platform, but let's face it, they'll always be "hacks" to us!), and this will certainly make our lives easier.


#6 - Dynamic Invocable Actions

Flows make the list again!  This release truly has a lot of goodness baked in for Flows.  Programmatic and Declarative Developers both win with this deal.  The ability for a developer to build an Invocable Method in an Apex Class that will work with a generic SObject or collection of SObjects is huge.  It means improved scalability and reusability for our solutions.  Simply put, do more with less.  And when we are talking about custom code, less is good. ;)


#7 - Einstein Voice Assistant (Beta)

We all have digital assistants these days, and they can sure be handy for basic things like checking your calendar, checking the weather, and looking up some basic information.  If you want them to do anything super-impressive, however, you've got to wire them up to custom skills that you create to serve your specific needs.  Einstein Voice Assistant shows a lot of promise as the digital assistant for the platform, with amazing potential to transform how our users interact with Salesforce while on the go.  While we can create voice skills to do things like create or update records, log activities, and so on, what I'd really love to see is the ability for Einstein Voice to be wired up to a custom piece of business logic, such as a Flow or an Apex Class, for instance, such that custom business logic could be executed via a simple voice command.  With that type of flexibility, Einstein Voice Assistant could prove to be extremely powerful.  Either way, I'm excited for this new feature, and to get it into the hands of my mobile users to help simplify their day-to-day routines on-the-go.


#8 - Inline Editing for Collaborative Forecasts

I've been waiting for the feature for such a long time now!  This was the big feature on a very short list of gaps that I needed in order to sell the feasibility of the native Forecasting option on the platform.  The problem for my stakeholders was that end users could view their Forecasts conveniently using Collaborative Forecasts, but had to navigate away to make any changes to the Forecast (i.e. to the Opportunities themselves).  As such, a custom UI was required in order to provide the same visual aggregations along with convenient editing all from one screen.  With a previous release, Salesforce added the ability to launch the native Edit modal for an Opportunity, which was great, but now with inline editing, I feel that users can intuitively and completely manage their Forecasts from a single screen, and all via the native platform offering.  I'll definitely be revisiting Collaborative Forecasting for my current implementation, and advocating that we adopt it in lieu of keeping around the technical debt that we had acquired in the past.


#9 - Deliver Targeted In-App Guidance Using Profiles

The ability to conditionally execute a piece of business logic is a cornerstone of automation, especially for enterprise customers.  The reality is that, in most implementations, our users are not "one size fits all".  Different users have different needs.  Any automation tool that rolls onto the platform in an "all or nothing" state is handicapped right out of the gate. That was the case with In-App Guidance, a tool that had great promise but needed a little more flexibility in terms of defining our audience.  With the ability to now define your ideal audience by Profile, In-App Guidance takes a major step forward in viability.  It is a feature that I can now certainly consider for JIT (or Just-In-Time) education for my end users.


#10 - Einstein Opportunity Scoring at No Extra Cost

Well, it's about time!  Including AI as part of the core platform is a smart move for Salesforce, and Opportunity Scoring is arguably the most vital piece of intelligence available for a Sales organization. Opportunities are the bread-and-butter of any Sales app, and empowering your users with AI to know which Opportunities to go after, and all for free, is big.  That said, this is not only a tactic to make AI accessible for every customer, but it is also a viable marketing strategy.  Once customers get a fix of AI in the form of the now-free Opportunity Scoring, they may come back for some of the premium services that are still available at an additional cost.

Focus on the Right Deals with Opportunity Scores


So what did you think of my first Top 10 list?  Hopefully you found this post helpful and insightful.  I welcome you to share your thoughts, feedback, and any questions you may have in the comments below.  I also welcome any suggestions or recommendations you may have for these lists in the future.  My goal is to help the community with the content I share, so tell me what you'd like to see, and perhaps I can make it happen! ;)