by Adam Purkiss

Force.com developers familiar with making callouts from Apex Code to external systems understand that there are a few unique challenges involved. Most of these relate to governor limits but there is another key consideration that we must account for: Callouts are not permitted following the execution of Data Manipulation Language (DML) in a given context. In other words, you can’t save anything to the database and then make a callout in the same thread. But you can execute DML after all callouts have completed. This is also true for sending emails, meaning that any emails will need to be sent after all callouts have completed. These are some of the challenges that the Flow Factory design pattern addresses.

The Problem

Consider the following flow that contains eight discrete steps with four yes/no branches:

Branches.jpg

In this flow, Steps A, B, and D involve callouts to other systems. Therefore, DML is off limits until we reach the C, H or G process steps. This complicates things since flow steps can’t manage their own data persistence or otherwise record their results – including the logging of errors – to standard or custom sObjects. One way to solve this problem is to combine these steps into one contiguous block of Apex.

But this can result in deeply nested if/else blocks which increase the risk of errors and can also cause migraines:

Migraine.jpg

Although this approach will “work,” the resulting code is brittle, hard to maintain, and error prone. Let’s look at another way of handling things.

The Flow Factory Defined

The Flow Factory is a stateful design pattern that organizes the business logic of a conceptual flowchart into Apex flow steps. It has roots in both the State pattern and the Factory Method, and provides a lightweight framework for service orchestration in Apex. Flow Factory is particularly useful when executing more than one callout in a single execution context as part of an aggregate transaction. This pattern always begins with a single flow step and continues processing until it reaches one or more defined final steps where DML and email notifications are allowed.

Flow.jpg

The Flow Factory delegates the creation of flow steps to the flow steps themselves, as opposed to having one central “brain” dictate everything from a single script. Since the flow steps are responsible for creating and handing back the most appropriate sibling to execute next, changes to the flow do not disrupt the greater design at all.

The main design follows the open closed principle, meaning that it’s open for extension yet closed for modification. In fact, recompilation of the main processing loop isn’t required to change the type of flow being processed or the executable code within each step. The flow steps, on the other hand, are encapsulated and designed for ongoing modification as business processes change down the road.

In order to understand how it all works, we’ll look at the following elements of the pattern with code samples for each:

  • Primary interfaces:
    • FlowState
    • FlowParent
    • Step
  • Sample flow class

In addition, I’ve created a sample Flow Factory application that uses a data-driven approach to execute flows, along with a flow tree to help visualize the flow paths:

Demo.jpg

Being able to select, view, and execute flows from Visualforce is mostly for demo purposes and to help visualize the flow of the design pattern itself. In practice, these flows are meant to be “headless” and called from any number of starting points, including: Visualforce controllers, triggers, scheduled and batch Apex, Future calls, and Apex web services.

The source is available on GitHub and can also be installed from AppExchange here.

Primary Interfaces

The three primary interfaces are virtual classes and live in the Flow Factory container class: FlowParent, FlowState, and Step. Both abstract classes and interfaces also work for this purpose, but with virtual classes we can include code alongside the logical interfaces, which is useful in this pattern.

FlowParent

FlowParent provides the process steps mechanism for all children to inherit and is the main processing loop of the Flow Factory. Each flow will inherit from FlowParent and seed processSteps with an initial Step and FlowState instance:

public virtual class FlowParent
{
   protected void processSteps(Step step, FlowState state)
   {
      Boolean keepGoing = true;
      while(keepGoing)
      {
         step = step.processStep(state);
         if(step == null) 
            keepGoing = false;
      }
   }
}

Then processSteps will execute each step by calling its processStep method until a null is returned from one of the final steps. Since Step siblings are handing back new instances of Step to the caller, all the caller knows is that the next step in the chain will have a processStep() method, or it will be null, signifying the end of the flow. This code is closed for modification since it won’t need to be recompiled when steps are modified or new steps are added to the flow.

FlowState

The FlowState virtual class is the base class for storing and persisting state over the course of a flow. FlowState contains a list of Step instances that accumulate as flow processing continues:

// State Parent
public virtual class FlowState
{
   public List<Step> steps {get; set;}
   public FlowState()
   {
      this.steps = new List<Step>();
   }
}

FlowState children add specific state variables to persist data throughout the flow. This includes initial data inputs and recording step data as the flow executes:

public class FlowStateChild extends FlowFactory.FlowState
{
   public String name {get; private set;}
   public String email {get; private set;}
		
   public FlowStateChild(String name, String email)
   {
      this.name = name;
      this.email = email;
   }
}

The first thing a step does when its primary method is invoked, called processStep(), is add a reference of itself to the passed-in FlowState object:

flowStateChild.steps.add(this);

As processing continues, FlowState accumulates pointers to each step. Upon completion of the flow, FlowState will contain a collection of step-specific data to iterate and process appropriately. Also, since FlowState retains pointers to each step, additional step methods can still be invoked if desired.

Step

The Step class is the parent for all process steps. It acts as the main logical interface by providing the processStep method, which all children override:

// Step Parent
public virtual class Step
{
   protected Step nextStep {get; set;}
   public String stepName {get; set;}

   // Create next step 
   protected Step createInstance(String className)
   {
      Type t = Type.forName(className);
      this.nextStep = (Step) t.newInstance();
      this.nextStep.stepName = className;
      return this.nextStep;
   }
		
   // Create next step from SObject
   protected Step createDynamicInstance(String className, String branchName)
   {
      Step retVal;
      List<String> classNames = className.split('\\.');

      List<Flow_Step_Branch__c> fsb = [
         SELECT Next_Step__r.Name 
         FROM Flow_Step_Branch__c 
         WHERE Flow_Step__r.Flow__r.Name = :classNames[0] 
         AND Flow_Step__r.Name = :classNames[1] 
         AND Name = :branchName 
         LIMIT 1];
			
      if(fsb.size() == 1 && fsb[0].Next_Step__r.Name != null)
      {
         retVal = createInstance(classNames[0] + '.' + 
            fsb[0].Next_Step__r.Name);
      }

      return retVal;
   }

   // Step children override with unique processing
   public virtual Step processStep(FlowState fs){return null;}
}

In createInstance(), a class name is passed in and the corresponding class is invoked for the next step in the chain. This instance is assigned to the nextStep member variable and its stepName holds on to the name of the next Step. This makes it easy to iterate and identify steps after the flow is complete.

In createDynamicInstance(), the name of the next step is retrieved from an sObject to demonstrate organizing and restructuring a flow dynamically, mostly for demo purposes. But the key method of this class is createInstance(), which provides a reusable way to instantiate flow steps by passing in the class name.

Sample Flow Class

A class that implements the Flow Factory provides concrete classes for FlowParent, FlowState, and as many Step instances as required by the flow at hand.

Sample FlowParent

The main class begins by extending FlowParent and then the processWork() override method is implemented:

public with sharing class Flow1 extends FlowFactory.FlowParent
{
   public override FlowFactory.FlowState processWork(Integer p)
   {
      Flow1State state = new Flow1State(p);
      FlowFactory.Step step = new FirstStep();
      step.stepName = FirstStep.class.toString();
      processSteps(step, state);

      return state;
   }

This is the main entry point responsible for:

  • Creating a unique FlowState instance
  • Seeding the Flow Factory with the first step
  • Recording the class name and
  • Calling the processSteps() parent method

It’s in processSteps() where we loop through all steps until flow processing is complete. The exact steps that will be processed won’t be known until runtime, but when the flow is finished, the last step must be set to null in order to exit the processSteps() loop.

Sample FlowState

For FlowState, you could actually just use the parent class, which holds on to a list of step instances:

public virtual class FlowState
{
   public List<Step> steps {get; set;}
   public FlowState()
   {
      this.steps = new List<Step>();
   }
}

This list is our “activity record” that accumulates response data as flows execute. But if a flow requires unique data as inputs, just extend FlowState and add an appropriate constructor to the subclass. This way you won’t disrupt the signature of the parent class and include flow-specific details where they don’t belong.

The demo contains two flows: Flow1 and Flow2. In Flow1, I’ve only added an integer to simulate path branching:

public class Flow1State extends FlowFactory.FlowState
{
   public Integer path {get; private set;}
   public Flow1State(Integer p)
   {
      this.path = p; 
   }
}

But in Flow2 there’s an extra parameter that accepts a contact object:

public class Flow2State extends FlowFactory.FlowState
{
   public Integer path {get; private set;}
   public Contact contact {get; private set;}
   public Flow2State(Integer p, Contact c)
   {
      this.path = p;
      this.contact = c; 
   }
}

In actual implementations, this is where you would include objects such as contacts, leads, and opportunities to be passed through the entire flow, either as lists or even as single objects.

But why would you design an Apex entry point to accept only a single object? Aren’t we supposed to bulkify everything? It’s true that in Apex it’s a good practice to code most everything in bulk. In fact, you’ll raise some eyebrows during the AppExchange security review process if you have methods that accept a single sObject anywhere in your code. But perhaps equally important is that your code is self-describing. The intentions of code should be apparent by reading the code itself rather than relying on comments or assumptions.

So then, if we have a flow that intends to perform a handful of callouts per Contact, and we plan to execute these in the same context, bulk processing is out. And if we accept a list of contacts in a method with the intention of only processing the first element in the list (which I’m sure you would never do just to pass a security review!) then the code is misleading and therefore hard to maintain.

Anyway, back to the flow…

Sample FlowStep

public class ProcessApples extends FlowFactory.Step 
{
   public override FlowFactory.Step processStep(FlowFactory.FlowState fs)
   {
      Flow1State state = (Flow1State) fs;
      state.steps.add(this);
      processThoseApples();
      this.nextStep = 
         createDynamicInstance(ProcessApples.class.toString(), 
         state.path);

      return this.nextStep;
   }
   private void processThoseApples(){} // Step-specific logic
}

Again, the steps in a Flow Factory implementation extend the step virtual class and, when executed in the main processing loop, the calling code won’t know the concrete class of the step being executed. What’s important is the contract that each step adheres to. Each step must:

  • Implement the processStep() method
  • Register itself in FlowState.steps
  • Create and return the next step (or null to terminate)

Flow Factory Demo

As I’ve mentioned, in the demo app (GitHub / install) I’ve added a path variable to simulate branching logic at runtime. This path is selected in the interface, along with the flow to execute:

Flowscreen.jpg

Depending on the path number chosen, certain flow steps will branch differently. For example, in the ProcessApples step of Flow1, the path number will determine which of the following three paths will be executed:

Paths.jpg

Other steps have only two branches, while the rest simply default to the first path. Additionally, these steps, their branches and next steps at each branch, can be modified directly in their respective custom objects:

Stepbranches.jpg

Below is a snapshot of the custom object hierarchy. A Flow object represents an Apex class that implements the Flow Factory. These have Flow Step children that map to FlowStep classes contained in the Flow class. And finally, each Flow Step will reference 0-n Flow Step Branch children that correlate back up to the next step(s), or FlowStep instance(s), in the current flow:

Currentflow.jpg

Let’s look at a few scenarios where this design pattern might be considered.

Flow Factory Scenarios

  • A fitness training company has various certification programs both for individuals looking for personal development, and for trainers who need to maintain their certifications. This data is uploaded to Salesforce on a nightly basis and also needs to be communicated to various other systems via APIs. Depending on whether an individual is a student or a trainer, upon completing a given course, a number of different steps will get processed that involve updating external systems. Additionally, depending on the response from individual callouts, the subsequent callouts will vary.
  • An online food delivery service provides payment processing and delivery from a variety of different restaurants. This service is part of a franchise that has locations in numerous cities around the world. Depending on the city, the restaurant being ordered from, the time of day, the day of week, and whether it’s a holiday or not, the flow of processing orders will need to change. The franchise has standardized on Force.com and wants to provide a uniform order process for all locations, yet must account for regional differences.
  • In an attempt to attract and retain contributors, the creators of an online tech forum hosted in a Force.com Site decide they want to build out a configurable reputation system that incorporates gamification techniques. A handful of other forums are going to be updated with the awards individuals achieve. But depending on the individual contributor, and assorted other factors, the specific forums to update will vary.

Conclusions

The Flow Factory design pattern isn’t simply an exercise in solving the same problems that Visual Workflow solves. It’s true that headless execution is not currently supported, but it’s probably just a matter of time before this option becomes available.

Similar to Visual Workflows, this pattern helps organize process steps that can be rearranged at runtime. It also provides structure for managing state throughout the entire process. This begins with flow-specific inputs and results in a chronological record of executed steps to iterate for final processing.

Since APIs change frequently and vary greatly in terms of inputs and response data, instrumentation is essential. The Flow Factory provides a framework for diagnostic support, and with the ability to postpone DML and email operations until callouts have completed, this pattern is well suited for service orchestration in Apex.

The Flow Factory design pattern is detailed in the Pluralsight course: Force.com Design Patterns – Part 2.