Summary: This article discusses a pattern or template for enabling and customizing features in an application developed upon the Force.com platform.
Force.com and “configurability”: new expecations for developers
A great thing about developing on the Force.com platform is how configurable the product is out of the box. Need a new field on a screen? Easy, find the right page layout and modify it. Want a field to be required? Go find the field and make it required. It’s crazy easy. So easy in fact, that more and more folks can contribute to the solution of a system. Even folks without an IT background that 5-10 years ago would never make these types of configuration changes are doing it. Can you imagine Joe the BA adding an Oracle constraint to make a field required? Of course not.
The downside to this amazing “configurability” of the Force.com platform however, is it creates a disconnect between developers who are not used to including this level of configurability, and salesforce users who have grown to love this type of configuration and now expect it in anything associated with salesforce. Below I discuss a “global configuration variable” pattern that makes adding configurability to your solution simple, clean and reliable.
What’s a global configuration variable?
A global variable (as opposed to a global configuration variable) is a variable which is accessible from any scope. It’s widely accepted that using global variables is a bad practice because those variables can easily be modified from anywhere within your codebase and as a result, using them becomes chaotic and difficult to debug. While similar in that its accessible from any scope, a global configuration variable should also be:
- read only (because it would be a bad practice if it weren’t)
- type cast (client code shouldn’t be burdened with type-casting a string to an integer)
- cached (each variable shouldn’t be loaded each time it’s accessed)
- sanity checked upon load (for example, a timeout shouldn’t be negative so default to 0)
- easily changeable in production (Joe the BA should be able to do it)
Usage
Best explained in a diagram:
What components are included?
- GlobalConfigurationVariable__c.object: Defines the data store for the global configuration variables (I think I just sounded like George W Bush saying “the google”). If you’re unfamiliar with custom settings, essentially they are specialized custom objects whose records are cached in the Force.com application tier and accessing those records doesn’t burn any governor limits.
- GlobalConfigurationVariables.cls: The main class which you’ll need to modify with your configuration variables. The example template is show below.
- GlobalConfigurationVariablesTest.cls: Test class which you’ll need to modify as well.
- GlobalConfigurationVariableTestUtils.cls: No need to modify. Unit test helper that makes achieving 100% code coverage much easier.
- GlobalConfigurationVariableTestUtilsTest.cls: No need to modify. Unit test helper’s test class (yeah, I know the name is confusing but you shouldn’t need to touch this class or the unit test helper class).
GlobalConfigurationVariables.cls
/**
* Please consider this class a template. You will need to customize
* this class according to the global variables you might require in
* your application. Also, you might consider creating multiple
* classes similar to this broken down by global configuration variables that make
* sense to be packaged together.
*
* First (1), define your global configuration variables as member variables of this class.
* For example, if you're defining a twitter username as a global variable, then
* the variable might be:
*
* public String twitterUsername {get; private set;}
*
* Next (2), define the key for your global variable. This is the value which
* must be entered as the name of the "Global Variable" custom settings record
* defined at:
*
* Setup | App Setup | Develop | Custom Settings | Global Variable | Manage
* (NOTE: if you haven't deployed that Custom Settings object yet, then obviously
* the above won't be available.)
*
* The key can be the same value as member variable but that isn't required.
* Using same example as above, the variable key might be:
*
* public static final String KEY_TWITTER_USERNAME = 'twitter.username';
*
* Third (3), define how the variable will be loaded. Included are two
* methods which read Strings and Integers. If you have a different data type,
* definie a different "retrieve" method.
*
* And last (4), consider putting in some sanity checking. For example, if
* you have a timeout variable defined as integer, perhaps it's a good idea
* to make sure it's > 0 but less than 60000 milliseconds.
*
* Once your configuration variables are defined, you should access the configuration variables in your
* code via the following:
*
* GlobalConfigurationVariables.getInstance().twitterUsername
*
* And I suggest you always call getInstance and you never store a reference of
* the GlobalConfigurationVariables object. That way, you can be assured that all transactions
* will get the latest copy of the configuration variables AND only do it once.
*
* @author Richard Vanhook
*/
global class GlobalConfigurationVariables {
//==================================================
// (1) Define your configuration variables
//==================================================
global String exampleString {get; private set;}
global Integer exampleInteger {get; private set;}
//==================================================
// (2) Define variable keys
//==================================================
global static final String KEY_STRING_EXAMPLE = 'ExampleString';
global static final String KEY_INTEGER_EXAMPLE = 'ExampleInteger';
private GlobalConfigurationVariables(){
final Map<String,GlobalConfigurationVariable__c> all = GlobalConfigurationVariable__c.getAll();
//==================================================
// (3) Load configuration variables
//==================================================
exampleString = retrieveString(KEY_STRING_EXAMPLE, all);
exampleInteger = retrieveInteger(KEY_INTEGER_EXAMPLE, all);
//==================================================
// (4) Do some sanity checking
//==================================================
if(exampleInteger == null || exampleInteger < 0 || exampleInteger > 60000){
exampleInteger = 1000;
}
}
//==================================================
// HELPER METHODS
//==================================================
global static GlobalConfigurationVariables instance;
global static GlobalConfigurationVariables getInstance(){
if(instance == null){
instance = new GlobalConfigurationVariables();
}
return instance;
}
private static Integer retrieveInteger(String key, Map<String,GlobalConfigurationVariable__c> all){
Integer returnValue = null;
if(all != null && !isBlank(key) && all.get(key) != null){
try{
if(all.get(key).value__c != null){
returnValue = Integer.valueOf(all.get(key).value__c);
}
}catch(System.TypeException e){}
}
return returnValue;
}
private static String retrieveString(String key, Map<String,GlobalConfigurationVariable__c> all){
String returnValue = null;
if(all != null && !isBlank(key) && all.get(key) != null){
returnValue = all.get(key).value__c;
}
return returnValue;
}
private static boolean isBlank(String str) {
return str == null || str.trim() == null || str.trim().length() == 0;
}
}
Component install instructions:
- Unzip GlobalConfigurationVariables.zip to a local folder
- Open Eclipse and set up a Force.com project (steps for doing this are outside the scope of this article)
- Include object metadata components in your project (via right-click project -> Force.com -> Add/Remove Metadata Components)

- Drag and drop file GlobalConfigurationVariable__c.object into your objects folder

- Drag and drop class files into your classes folder
