Navigation: Developer Force | Salesforce Mobile Services | Refactoring Force.com for Mobile

Banner.png

Refactoring Force.com for Mobile

by Don Robins

“Mobile-first” is a mantra we hear often these days. The mobile-first development approach, which seems to imply new app development, centers around deliberately focusing your initial design and development efforts on the form, function and user experience of the mobile devices you are targeting. It is only after this that you place additional design effort on the browser- or desktop-based user experience.

The question is, how do you adapt the mobile-first strategy to a legacy Force.com application? This article proposes designing a modular and layered architecture for Apex Code, and performing some fairly simple modifications to your existing application. Specifically, we'll explore how you can refactor code so that it can be accessed from multiple entry points in your system, especially for an evolving suite of mobile applications.

The Mobile Reuse Challenge

In his comprehensive article on Enterprise Mobile Patterns, Quinton Wall presented the Mobile Platform Pattern and a cloud-first approach to promote leveraging pre-existing back-end functionality across an entire company, and in particular with new mobile apps. Adopting these approaches when adding new mobile apps as extensions to existing Force.com applications is indeed effective. However, you are likely to face some challenges when building out your new mobile apps and find that you need to leverage existing back-end Apex business logic from your org, especially when originally built to support a custom Visualforce web-based user interface.

The desired objective is to reuse and leverage such existing functionality for new mobile apps without dramatically changing the Force.com custom user interface and logic already in place. While you don't want to duplicate existing functionality, you do want to minimize modifications to existing code to reduce the risk of breaking anything already in production.

Refactoring for Separation of Concerns (SOC)

One common use case I see is 'trapped' business logic in Apex. For example, code supporting business rules or data processing is often written directly into the main body of a method on a controller class, rather than being deliberately isolated and implemented in a modular fashion as part of a layered architecture. Such code in a controller or extension class might be bound to a Visualforce page called from a custom button or link embedded in a standard page layout of an sObject.

In order to leverage the contained business logic, we have to find a way to separate these two different concerns. The proper approach is to refactor the code, extracting the business logic from the controller method and placing it inside its own static method in a public service class. This allows it to be easily invoked from any particular entry point, including the Apex controller class where it originally resided.

If you have not already been down this road, it's time to come up to speed on the concept of Separation of Concerns (SOC), and other related software design patterns, that you can apply to your Apex code base to provide flexibility, scalability, consistency and maintainability. This set of articles, Apex Enterprise Patterns - Separation of Concerns by Andrew Fawcett of FinancialForce.com, provides an excellent and comprehensive overview and primer to the concepts. I highly recommend that you read them in depth, as they present these time tested patterns in an Apex context, and they speak to our immediate purpose around refactoring for mobile. In particular you will want to read the post on the Service Layer.

These patterns promote a modular approach when designing Apex classes that manage business application logic, and describe the deliberate organization of such code into a predefined collection of layers that follow established best practices, providing multiple benefits as a result.

In the following diagram, you can see that logic in a service class can be accessible from multiple entry points. Service methods can be invoked from a controller, a REST resource, or a SOAP web method.

MobileCustomLayers.png

As an aside, you could also access such logic from a trigger, however trigger handler logic is often considered a different layer, and is typically isolated into domain specific classes rather than services. For more information read the SOC article on the Domain Layer.

But don't get hung up on the potential complexities. While our legacy code may not have originally been architected in such a manner, our immediate task is simply to migrate our custom business logic from the Apex controller extension class into it's own service class and method, so that it may be invoked from multiple entry points.

Returning to our example of code in a controller that is bound to a Visualforce page, let's explore for a minute the logic flow and user experience of this common pattern. When the custom button is pressed, the user is redirected to the Visualforce page which shares the current record's context and StandardController, but is extended with a custom Apex controller extension class. When the Visualforce page is invoked, it delegates on load to an action on the controller extension class by way of the <apex:Page> 'action' attribute. The action method on the class is immediately invoked, and the contained logic is processed.

Upon successful processing, the action method redirects the user back to a refreshed instance of the original detail page from which the custom action was originally executed, and the Visualforce page is never visibly rendered. In the event of an exception case, when an error occurs during the processing, the action method will handle the exception, add a message to the page's <apex:PageMessages> collection, and subsequently return a null value to redirect the user back to the custom page to see the message. The following UML sequence diagram shows the interaction; note the shaded process logic area under the life line of the controller extension class:

MobileCustomProcess1.png

The challenge arises when designing a mobile application serving up this same record in a mobile view, with a design that calls for a similar action to invoke the exact same logic built into the pre-existing Apex controller extension. The problem is that the controller extension class and its action method cannot be directly accessed by the mobile app.

To refactor this, we will access it from both the original controller extension, and from a new Apex REST resource class.

Here is a modified UML diagram to illustrate the change from the perspective of the interaction with the custom Visualforce page. You can see where we have added one more swim lane to represent the service class and its method for a call from the controller class:

MobileCustomProcess2.png

SOC is for Testing Too

An added benefit of this approach is that a new test class can be constructed whose sole responsibility is for testing the custom processes in the service class. Any unit tests previously testing the method in the controller extension class can be migrated to the new test class.

Adding additional processes to the new service class requires only isolated changes to that class and its related test class. You will no longer need to touch the controller class and its tests, thus reducing risk and the potential for inadvertently breaking them.

Unit tests for the controller extension will now only be required to test the immediate controller functionality, and such tests no longer have to include logical assertions against the service logic.

You can see that the Separation of Concerns pattern trickles down into the testing layer, and promotes a cleaner, more focused, decoupled, simplified and structured testing approach. So, let's look at how we will refactor our code to apply this modular approach.

Building a Service Class

Many of the examples you'll see in the MobilePak reference apps will show you how to fetch one or more records and perform CRUD operations on them, but there's not too much on how to launch actions from any particular record's context. A specific REST request is typically needed from any mobile client to invoke such a process in Salesforce. Actions can be easily invoked from mobile applications, but require a custom Apex action API built into your salesforce org. There are two general approaches to access your custom API.

If you're using a REST approach from either a native mobile app or a mobile web app using Ajax for its REST service calls, you will need to create a custom Apex REST resource to invoke your action on an HTTP POST request from the client. The Apex REST pattern allows you to build such resources very easily, and invoke them through the Apex REST Service API. However, if you're leveraging JavaScript Remoting from a mobile web app hosted in a Visualforce page, then you'll require a client side Ajax method to call a global @RemoteAction method on an Apex class.

Regardless of the approach you decide on to make the action request from your mobile app, the primary task at hand will be to refactor the existing Apex business logic needing to be invoked, so that it may be accessed from alternate entry points. First we'll build a new class and a public static service method. You should make the names of both the class and method self-documenting of course, but in this case we'll use generic names.

public class MyCustomService{

     public static string MyCustomProcess(ID recordId){
     
          //Custom process logic gets moved to here from controller...
          ... 

          //Set up the message and return it.
          return message;

     }

}

Our service method will expect only the ID of the record as a parameter, and the method will be responsible for fetching the object as needed from the data layer for processing. It is a best coding practice to simplify the signatures and parameter collections of the service methods as much as practical, however it's your design decision how to best define the inputs to your methods.

Keep in mind that there are some data type limitations when working with web services, and you will benefit from any effort to decouple the logic of your classes. In this example, the calling routines need not concern themselves with anything other than providing the identity of the record to act upon; they need to know absolutely nothing about the state of the object, or how it will be processed by the service.

Once the record has been fetched, the method will process the data based on the logic extracted from the original method in the controller class, and then, based on success or failure, will pass back an appropriate message.

Refactoring the Controller Action Method

Next we'll change the action method in the controller class, removing the original business logic and calling the new service method. We must refactor to evaluate the returned message which will be used to determine subsequent feedback and navigation for the user.

public class MyControllerExtension{

     private ApexPages.StandardController controller;

     //Constructor for the extension.
     public MyControllerExtension(ApexPages.StandardController pController{

          controller = pController;

     }

     //Action method called from the 'action' attribute on the apex:page tag.
     public PageReference MyCustomAutoRunAction(){
     
          //Call the new service static method and return the message.
          string resultMessage = MyCustomService.MyCustomProcess(controller.getId()); 

          //Determine appropriate user feedback and navigation based on the message returned.
          ... 

     }

}

Note that we're simply passing to the service method the record's ID as derived from the StandardController. This controller action method will still require logic to determine how to respond with the appropriate user feedback and navigation based on the message returned from the service.

Build an Apex REST Resource API

Now that we have the service method in place, we can build a simple Apex REST resource that will provide an external API to the service from an HTTP request from our mobile app or any other REST based application that needs to call it.

Our Apex resource class method simply wraps a call to the service class method, and passes back the resulting message. Depending on the signature of the service class method, the Apex REST resource will need to support whatever parameters are required to invoke it. In our sample case, it simply needs to pass along the record ID.

Keep in mind that it's best to follow standard REST API design patterns. For example, you'll want to name your resources as nouns, and design parameters to qualify acceptable actions and accept required data arguments. You will also associate your REST request with a standard HTTP verb, such as GET or POST. For example, an Apex resource named 'MobileActions' can be used to invoke a collection of arbitrary actions on a POST, each identified by an 'action' parameter.

REST API design is well beyond the scope of this post, but you can read more about it in this article on Creating REST APIs using Apex REST and by watching this excellent presentation on REST API design.

@RestResource(urlMapping='/MobileActions/*')
global with sharing class MobileActions {

     @HttpPost
     global static String doMobileAction(String recordId, String action) {

          if(action == 'MyCustomAction') {	

               //Invoke the new service static method and return the message.
               ID tempId = (ID)recordId;
               return MyCustomService.MyCustomProcess(tempId); 

          } else {

               return 'Unknown action: ' + action;

          }           
    
     }
}

In the revised diagram below, you can see the interaction from a mobile app via the Apex REST resource class, which can now invoke our custom business logic from its new home in our service class.

MobileCustomProcess3.png

Also Works With JavaScript Remoting

The REST API works great if we're connected to the org using OAuth, making calls through the REST API. However, if we're using a mobile web approach with our mobile client hosted inside a Visualforce page, we will have an Apex controller class that handles the action with an @RemoteAction method called from Ajax. That Apex controller method would look something like this, simply passing back the resulting message to the calling routine:

global class MyController{

     //Action method called from the Ajax 'action'.
     @RemoteAction
     global static String MyCustomRemotingAction(string recordId){

          //Call the new service static method and return the message.
          ID tempId = (ID)recordId;
          return MyCustomService.MyCustomProcess(tempId); 

     }

}

Our final diagram below shows the interaction from the mobile web app now hosted in a Visualforce page, invoking the service logic via a call from client side Ajax to an @RemoteAction method on an Apex class.

MobileCustomProcess4.png

Closure

As you can see, you gain tremendous flexibility when refactoring Apex into a more modular architecture. This approach allows previously 'trapped' custom business logic to be called as a service from any entry point, both internal or external to the org.

The same pattern can be applied to similar scenarios, perhaps where a custom button calls a JavaScript stub, using the Ajax Toolkit to invoke a SOAP Apex web method. Once again, the key is to extract and isolate the business logic contained in the SOAP web method into a separate service class, so that it can be called via the SOAP API as well as from a REST service or any Apex code elsewhere in your org.

Adopting a SOC approach provides maximum flexibility with just a bit of effort to build out a more structured architecture. You can incrementally refactor your existing code base in bite size chunks as needed, delivering constant and incremental improvement to your application while exposing valuable functionality to your shiny new mobile apps.

So...what are you waiting for? Go do it.

About the Author

Don Robins has been building custom business applications with framework-based architectures for over two decades. He found his way into Force.com as a consultant and architect in 2009, and has recently been immersing himself in Force.com mobile development, integration and training. A Force.com MVP, Salesforce.com Certified Advanced Developer and award winning Salesforce.com Certified Instructor, he delivers all of the Salesforce.com Developer Classes (DEV401, 501, 502, 531), both domestically and internationally, in both public and private workshops when not consulting or mentoring privately. His background and experience in the trenches as Developer, Architect, Team Lead, Tech Mentor, Certified Agile Scrum Master, and Developer Community Leader shapes his training and mentoring approach with developers of all skill levels, from novice to architect. Don is a principal of Outformations, Inc. and runs a team of Certified Salesforce.com Instructors under the banner of ForceMentor.com.