Insights
Part 2: Move smoothly with these Subflow tips
Part 1 of our series reviewed Record-Triggered flows, now the conversation moves to Subflows, more formally known as Auto-Launched Flows
January 25, 2024
Part 1 of our series reviewed Record-Triggered flows and offered some tips around structuring your entry conditions, order of execution, and how to leverage Apex actions with Record-Triggered Flows. Now the conversation moves to Subflows, more formally known as Auto-Launched Flows. Subflows are a type of Flow that can be referenced by other Flows, which allows you to compartmentalize functionality and reuse that logic in multiple places. Subflows can be combined with Apex, Login Flows, Custom Buttons, Process Builders, a URL, or another Flow.
Visualizing subflows
Let’s imagine a contact center. Using a case workflow as an example, we’re going to use subflows to help streamline a case escalation process.
The cases we work on are automatically escalated to managers if the case has been open for more than two days. However, cases can also be escalated at any time by the original agent. As part of the case escalation process, a few things need to happen:
An “escalation record” should be created to log the change and take a snapshot of some values on the case record for auditing purposes
A notification should be sent to the user mentioned in the escalation record that the case has been escalated
This is a good candidate for a Subflow because:
It’s self-contained and can be tweaked independently of the rest of the process; for example, we might want to add another notification like a chatter post or slack message
We expect the same behavior regardless of context: auto or manual escalation
Knowing the different contexts helps us decide what functionality should be included in the subflow. Here is the example subflow:
Figure 1 - Case Escalation Subflow
The subflow takes a Case ID value as an input and returns the case escalation record as an output. By design, a subflow should have a simple purpose and a simple set of inputs and outputs. This way, it’s easy for another developer or admin to use the Subflow in other areas. They can understand what it needs and does without knowing the inner workings of the subflow.
Next, we can plug in this subflow to the screen flow for manual escalation and the scheduled flow for auto escalation(see figures 2 and 3). To add a Subflow, an admin simply needs to save and activate the Subflow (Auto Launched Flow) and then add the Subflow element to their parent flow.
To finish integrating the Subflow, just assign the input variable(s) to pass in the necessary inputs, and map the output variables (if you need them) back in your parent flow. It’s that easy!
Figure 2 - Screen Flow Calling Subflow
Figure 3 - Scheduled Flow Calling Subflow
You can see in figures 2 and 3 that we may label the subflow element as whatever we want. Use naming conventions and write descriptions in the flow to help provide context as to why you’re calling the subflow.
Remember, the value of subflows is reusability: you can repeatedly leverage the same functionality without needing to re-build it multiple times or having to maintain those multiple copies when changes inevitably happen.
Subflow best practices
1. Keep Subflows small and do only one thing to reduce complexity.
It might be easy and tempting to expand on what the “thing” that a subflow does over time, but the goal should be to keep it clear, concise, and consistent. In our example, we used a few elements in the subflow, but overall that process was understood as the “case escalation process.” There aren’t other escalation processes in our world, and there’s only two steps to “escalating” a case–so it maintains a clear, concise, and consistent goal.
In the future, if we were to expand our case escalation process to multiple parts of our business or add steps to it, it’s worth revisiting that Subflow to ensure that it’s still clear what it’s supposed to be doing.
For example, perhaps the case escalation process needs to accommodate new regions or introduce different logic based on the “tier” of the related customer to the case (Gold, Silver, Bronze, etc.) and there’s different logic per tier and per region. Don’t be afraid to break up Subflows if they get too big and have too much logic built into their current state. Subflows could be created per region, per tier, or a per tier and region combination if it’s large enough.
Figure 4 - Subflow Expansion for Different Business Regions
In Figure 4, we’ve expanded the Subflow for different business regions and could argue that this is still a good use of the one Subflow. You’re doing different things per one field’s value, and it’s consistent based on what that field’s value is. However, tread carefully. Any further expansion to the scope might raise alarms that it might be time to refactor and think about this logic in a different way.
Figure 5 – Time to refactor our subflow.
Figure 5 shows a Subflow that has gotten out of hand. Many things are happening in the Europe decision tree that are not applicable to the other regions. In this scenario, it might be better to see this Subflow broken up, and perhaps lend the Europe region to its own subflow or otherwise be compartmentalized to represent the region’s unique requirements. This modular programming concept when applied to subflows allows them to more easily be reused in other flows as well, constructed around smaller, singular use cases.
2. Subflow inputs are just as important as the subflow to improve their reusability.
Subflows shine brighter when they’re dropped into flows quickly. Too many input variables can slow the Subflow’s adoption into existing and new processes.
Figure 6 - Adding too many input values add time to setting up subflows and can be passed other ways
A rule of thumb I follow is that it’s best to keep input values to around two or three, with most of them being required. After three input values, adding a Subflow feels like filling out a form and can be an indicator that your Subflow is relying too much on the calling flow or is doing more than one thing.
3. Use ID/Text values instead of a Record or specific Field’s value as input values to reduce dependencies.
Figure 7 - passing a Id as a text variable de-couples subflows from calling flows
When it comes to configuration changes, fields on a record change quite a bit, and hardcoding a specific field or picklist value into your flow could cause issues if that field’s attributes or picklist values change. Worse, if the field is no longer used anymore, it forces you to make changes to not only the Subflow, but also to every flow that calls it.
Generally, it’s better to pass the IDs (or text values) as inputs from the calling flow, and allow the Subflow to query for those records so that it has less dependency on the flow that calls it. However, one caveat to this approach are flows that already have a SOQL intensive structure and this subflow would be called multiple times in that flow. No matter how bulkified a Subflow is constructed, calling one that queries for records multiple times can lead to SOQL query limit concerns.
As an aside, in this section when IDs are mentioned, they should come from the context of the parent flow. We are not advocating hardcoding specific ID values into Subflow input values, but if you need to hardcode, consider using values that remain the same between sandbox/production environments and are less likely to be changed for UI purposes like for example, RecordType.DeveloperName.
4. Use flag input values with caution!
Figure 8 - Flags can lead to subflow overengineering and hidden logic in the subflow based on flag status
This point ties directly to the top concern that subflows should do one thing and do it well. Adding true/false flags to do one thing or another is a clear indicator that this flow does more than one thing and could be refactored into separate subflows.
Conclusion
Subflows promote organization and reusability in your Salesforce flow automations. Following the best practices called out here, your team can use them effectively to make fast and safe updates.
Authored by: Nate Helterbrand