This is the seventh article documenting what I’ve learned from a series of 12 Trailhead Live video sessions on Modern App Development on Salesforce and Heroku. In these articles, we’re focusing on how to combine Salesforce with Heroku to build an “eCars” app—a sales and service application for a fictitious electric car company (“Pulsar”) that allows users to customize and buy cars, service techs to view live diagnostic info from the car, and more. In case you missed my previous article, you can find it here.
Just as a quick reminder: I’ve been following this Trailhead Live video series to brush up and stay current on the latest app development trends on these platforms key to my career and business. I’ll be sharing each step for building the app, what I’ve learned, and my thoughts from each session. These series reviews are both for my own edification as well as for others who might benefit from this content.
The Trailhead Live sessions and schedule can be found here:
The Trailhead Live sessions I’m writing about can also be found at the links below:
In the last session, we went into detail on Lightning Web Components (LWC) and built out a custom front-end experience by creating a custom inventory gallery for our eCars application. We also went through all the design tools and resources available to LWC developers such as the Salesforce Lightning Design System and Lightning Web Components reference library.
This time, we are shifting gears and reviewing ways to automate business processes. As developers, we know how to handle complex use cases with code, but Salesforce also offers a powerful, declarative way for us to do this: enter Flows.
Introduction to Salesforce Flows
Flows in an automation tool that allows you to automate processes in Salesforce without having to write code. Although flows are considered a “declarative” or non-code method of automating processes, it’s important that developers learn how to use Flows even as some of these processes may be managed by a Salesforce Admin moving forward. It’s also important for developers to learn since Flows can integrate with APEX via invocable actions and Lightning Components.
Flows offer a powerhouse of tools with easy to use drag-and-drop elements. Salesforce even offers a UI element known as Screen Flows which allows you to build a multi-page process or wizard. There are also pre-built solutions on the AppExchange that allow you to install packages with flows and combine them with your org’s pre-existing flows.
Flows are somewhere near the middle of this spectrum
Automating the eCars App Using Flows
In our first activity with Flows and our eCars app, we will populate a Range, using automation, based on a car’s price.
This can also be done using APEX triggers, Process Builder or Workflow rules, but today we are going to automate this using Flows. When creating a new flow in Setup, you’ll see that Flows can be triggered in multiple ways.
Screen Flows give you a way to build screens for lightning pages, communities or quick actions so that users can initiate the actions and go through a series of screens with ease. This type also supports integrating lightning web components into the flows.
Scheduled-Trigger Flows allow you to specify a frequency (“this should run at 3am every day”) for when a flow should run.
Platform Event-Triggered Flows offer a way to run an automation based on platform events. If you are new to Platform Events, check out this Trailhead Module that will help get you up to speed.
Autolaunched Flows can be invoked by APEX, process builders, other flows, or even called via the REST API and used with Einstein bots.
Record-Triggered Flows are flows triggered by changes to records, such as when records are created, updated, or deleted. These are very similar to process builders, workflow rules, and APEX triggers.
Today we are using the Record-Triggered Flows which allow you to run automation logic when a record is created, modified, or deleted. In the flow builder, we select when we want the flow to run. It’s important to keep a best practice in mind though: When updating the same record that you are evaluating, select “before the record is saved,” since selecting “after record is saved” can result in recursions or infinite loops. This occurs because the “after record is saved” run mode will update the record again and cause the flow to re-run.
Another thing to be aware of is the order of execution when mixing different methods of automation such as APEX triggers, flows, and process builders (here it is for quick reference). Oftentimes when mixing these different methods, it’s best to use an APEX trigger, since they provide the most granular control over what executes and when.
There are also some limitations to be aware of for the record-trigger flow. Specifically, these Flows don’t let you use the ISCHANGED() or PRIORVALUE() functions (but this will be changing in the Spring ‘21 release). Some helpful architect documentation is available on the Architect Website here. There, you’ll see what is currently available, as well as the roadmap for upcoming changes/releases to flows. If you have a truly complex use case, resort to APEX code. Alternatively, mix and match flows and APEX in a sensible way. For example, launch a flow and add an APEX element to it. (You can call APEX methods or Lightning Components from flows!) Because you don’t want your flow to become so complex that it is hard to maintain or debug, it’s key you check out the Architecture Guide to understand when you should use what.
Back in our flow, we select our object and pose the question, “When do we want this to run?” Or, phrased from a developer’s perspective: This is your “if/else statement.”
For now, we set this to “None” which will cause it to run under all conditions:
We bring in the “Decision” element and review our requirements once more so we can build out this logic into our flow:
Now we can build in these conditions where we will be checking the price of the vehicle and enter the outcomes we wish to occur depending on the price.
Next, we drag the “Assignment” element into our flow and go through the steps to map the range field’s corresponding value:
There are different options for assigning a value, and in this case, we will use “Constant:”
We can repeat the same steps for a second “Assignment” element for medium range as well, and then finally connect our elements together:
Adding lots of elements can quickly create a big of a mess on the layout, but there is a new feature called “auto-layout” which automatically cleans things up and organizes them in a neat and tidy way:
Even though flows are extremely powerful, there are just three logic elements in the toolbox: Assignment, Decision and Loops.
Assignments are where you can create variables and assign values to them.
Decisions are like “if” statements for evaluating conditions.
Loops are like “for loops” to control logic that needs to repeat until an entire list of variables has been processed (or some condition is met).
Over in the “Manager” tab, we can see all the elements created so far. These are the variables that have been created in the course of the previous steps.
The funny thing is that pretty much every programming language I’ve come across has these same core elements just expressed with slightly different syntax. So if you’re an admin who’s already a pro at building flows and can think through the necessary logic and architecture to build them in an elegant fashion, taking the next step and developing in APEX code should be a simple transition. Essentially, you are already doing low-code programming with flows.
Testing and Debugging Our Flow
For debugging record-trigger flows, we can only test this from the record. Test the flow we just built, save and activate it, navigate to a car record, and change the price of a car, then confirm that the range field auto-updates to the expected range value. Success!
More Flow Features and Other Flow Execution Types
Back in Flow Builder, if you select a new record-triggered flow but then choose “After the record is saved,” you can see more elements in the toolkit. This execution mode has more features; now we have an “Action” as an option as well as additional data elements.
Note from earlier that “before save flows” are only meant to modify the same record, whereas “after save flows” allows you to handle other data operations.
For the Auto-Launched Flow option, there is a “Subflow” action in our toolbox. This allows you to call a Flow from another Flow. Similar to object-oriented programming, this allows flows to be re-used in a modular fashion. An expert programmer, whether using flows or APEX, is always thinking about being parsimonious and efficient. They’d rather avoid repeating the same code or set of flow logic over and over again!
Another option worth mentioning is that you can choose the security mode your flow runs. This includes a feature that lets you run the Flow with the same data security and access rules that admins have configured for the current user, or allow the flow to bypass these rules or run in “system context.”
With Flow Actions and Flow Screens, you can build a step-by-step wizard or custom process within Salesforce. Flow Actions allow you to create a piece of logic in APEX and bundle it so that an admin can simply drag and drop it within a Flow. With Screen Components, you can do the same using Lightning web components, further empowering admins.
These flow bundles are available for those building AppExchange applications. They are also fully compatible with Continuous Integration/Continuous Deployment (CI/CD).
Flows are stored as metadata behind the scenes that you can view them as XML. As a result, it’s versionable and can be in a Git repository (just like all of your other code) and moved/deployed between different Salesforce instances.
Introduction to Salesforce APEX
Even though there is so much that can be done with Flows, there are still cases where it’s best to use custom code and APEX. APEX is a strict-typed, object-oriented language similar to Java. In a few bullets, APEX is:
Salesforce native programming language
Object oriented (classes, interfaces, inheritance)
Strongly typed language
Compiles to Java Byte Code
Includes SOQL and DML statements similar to SQL stored procedures
Now that we know what APEX is, it’s important to know when it’s appropriate to use. It’s somewhat rare to need any APEX, given all the declarative features that Salesforce provides, but certain use cases do call for it. For instance, it can be useful when you need to:
Create custom transactional logic (logic that occurs over the entire transaction, not just with a single record).
Attach custom logic to another operation, such as saving a record so that it occurs whenever the operation is executed, regardless of whether the operation originated in the user interface or via a API transaction.
Create bundled APEX to be invoked from Lightning components, Visualforce pages or Flows.
Perform complex logic or validation over multiple related objects.
Create custom web services.
Create custom email services.
With the first two, it’s not necessary to use APEX, but with the last three items, there really is no alternative to APEX. In fact, one of the main uses of APEX in my current experience on client projects is to create custom REST web services. Doing so allows an external application to make POST, PUT, or GET requests to Salesforce and have the requests processed in a custom fashion.
Automating Tasks for the eCars App with APEX
Our example use case for APEX and our eCars app will be to create a task for our sales reps after a vehicle status is set to “sold.”
When first starting out doing development, I did a lot of copy-pasting and editing existing code. There is no shame in this; it’s all part of the learning process. Luckily, in the APEX Recipes Github repository, we can find some APEX Recipes with bite-sized snippets of code for almost everything that you might need. The code samples found here are also “production quality,” so it would be a useful exercise to review and compare it with any existing code you’ve written to gain some insights into what Salesforce considers best practices.
The recipes include integrations, SOQL, DML, and other use cases. Each of these recipes is paired with documentation. The recipes also encompass best practices around writing secure code. When writing APEX, we sometimes want the permissions that are configured for an object to be enforced. This needs to be handled explicitly in code— a useful recipe to review is the “CanTheUser” recipe.
It’s important to note that even though you can create multiple APEX triggers for an object, you should never do so. If you did, it would be easy to quickly lose control over the execution of the transaction, as the order that the triggers are fired is not guaranteed. Therefore, it is recommended you write only one trigger per object and have a delegator pattern in place—that is where a TriggerHandler comes in. A common pattern that I use for all triggers and handler classes is as follows. You can see that having a dedicated handler method allows for more granular control in each execution context.
Using a combination of what we’ve learned so far and the APEX Recipes library, it should be relatively straightforward to implement the task automation for the eCars app. If anyone is having problems, the Chatter group dedicated to this series would be a good place to ask for help with your code.
With so many ways to implement a particular use case, it’s important that we talk about which tool to use when and to review best practices. Do you use APEX only, Flows only or a hybrid approach? If you’re unsure, it’s useful to refer back to the Architecture Guide Quip document. A summary of the key deciding factors is as follows:
You should typically choose the tool that allows you to build and maintain the solution at a low cost:
If you have APEX developers available and have well-established CI/CD and trigger frameworks in place, adding Flows to the mix can unnecessarily add overhead.
If your application will be maintained by admins or non-developers in the future and there is less access to developers, then Flows may be the best choice.
If you have a combination of devs and admins, you can consider using flow triggers with complex multi-record processing logic in an APEX layer that is exposed as services/actions for flows.
At the time of this writing, APEX developers are in short supply as compared to Salesforce admins, so it’s usually natural to avoid APEX for as long as possible. However, in certain cases, it’s very easy for flows to quickly get too complex, out of control, and unmaintainable. This is especially true if thought isn’t put into how the flows are architected and organized. It’s also important to revisit existing flows periodically to see if they can be refactored to be more modular or maintainable. I’ve seen many orgs overuse flows when a little bit of APEX could have been a more effective solution. When that happens, the organization has to spend a great deal of resources trying to fix/refactor a mess of flows once things start breaking and error messages start popping up. As a result, an ounce of prevention in this case is worth many pounds (and hours) of technical debt!
In the next article, we’re going to look at scaling Salesforce applications with microservices on Heroku and building using an event-based architecture.
If you haven’t already joined the official Chatter group for this series, I certainly recommend you do so. That way, you can get the full value of the experience and also pose questions and start discussions with the group. Oftentimes, there are valuable discussions and additional references available there such as the slides from the presentation and links to other resources and references.
About me: I’m an 11x certified Salesforce professional who’s been running my own Salesforce consultancy for several years. If you’re curious about my backstory on accidentally turning into a developer and even competing on stage on a quiz show at one of the Salesforce conventions, you can read this article I wrote for the Salesforce blog a few years ago.
Thanks to Jason Sun for his kind permission to publish this article.