What is a good set of naming conventions to use when developing on the Force.com platform?

Follow the CamelCase Java conventions, except for VF pages and components start with a lower case letter.

Triggers:

  • <ObjectName>Trigger - The trigger itself. One per object.
  • <ObjectName>TriggerHandler - Class that handles all functionality of the trigger
  • <ObjectName>TriggerTest

Controllers:

  • <ClassName>Controller
  • <ClassName>ControllerExt
  • <ClassName>ControllerTest
  • <ClassName>ControllerExtTest

Classes:

  • <ClassName>
  • <ClassName>Test (These might be Util classes or Service classes or something else).

Visualforce pages and components:

  • <ControllerClassName>[optionalDescription] (without the suffix Controller). There might be multiple views so could also have an extra description suffix.

Object Names and custom Fields

  • Upper_Case_With_Underscores

Variables/properties/methods in Apex

  • camelCaseLikeJava - more easily differentiated from fields

Test methods in test classes

  • test<methodOrFunctionalityUnderTest><ShortTestCaseDesc> - For example, testSaveOpportunityRequiredFieldsMissing, testSaveOpportunityRequiredFieldsPresent, etc.

Working on something that would be used as an app or in some cases just a project? If yes, then do the following:

Prefix all custom objects, apex classes, Visualforce pages and components with an abbreviation so that they are easier to identify (e.g., easier for changesets). For example the WidgetFactory app would have the prefix wf on those. Additionally, when adding custom fields to a standard object they would also be prefixed to identify them as part of the app/package.

The main reason for the Object and Fields Names using Upper_Case_With_Underscores is that when you type in the name field or object with spaces it automatically adds the underscores. Although Apex is case insensitive, always refer to the Objects and Custom Fields in the code as Upper_Case_With_Underscores as well for consistency all around and consistency with what is generated by the SOQL schema browser and other tools. Object and Field Labels (which are generally ignored by code but visible to users) should keep spaces, not underscores.


I generally subscribe to the following rules:

Apex Classes

  • For a generic class, I just prefix with a capital C, e.g. CSomeClass
  • For those which are test classes I use CTest as the prefix
  • For a Visualforce controller I use the prefix CVFC which means they're all grouped together

Visualforce Pages

  • I tend to use VFP as a prefix, maybe redundant but it helps keep them together when there are pages from other sources involved

Triggers

  • Here, I use the object type followed by an underscore and the trigger type, e.g. Contact_AfterUpdate, Lead_BeforeInsertUpdateDelete

If I'm working with code that all logically sits together in psuedo-package (or a real package) then I tend to also prefix everything with a suitable abbreviation.


Update on 2016-02-17

I've evolved the below in a few cases:

  1. For collections, I always make the Collection variable plural, and I don't append the Collection Type as a suffix. Examples:

    • Set<String> cities instead of Set<String> citySet
    • List<Employee__c> employees instead of List<Employee> employeeList
    • (Infrequently Used) Map<Id, Contact> contacts instead of Map<Id, Contact> contactMap
  2. I use the Array notation for all Lists unless contructing a new List from an existing List or Set. This makes it easier to use the Auto-Complete in MavensMate which uses Sublime Text. (Plus it's less characters to type.) Examples:

    • Account[] accounts instead of List<Account> accounts
    • Contact[] contacts = new Contact[]{} instead of List<Contact> contacts = new List<Contact>();
    • Integer[] sizes = new Integer[]{2, 3, 4, 5}; instead of List<Integer> sizes = new List<Integer>{2, 3, 4, 5};
    • But you have to use the prior convention if you want to initialize a List with an existing List or Set. Set<String> lastNames; String[] lastNameList = new List<String>(lastNames);
  3. Abandoned the whole Return Variable mumbo jumbo. I always try to be as explicit as possible when using variable names. Example:

    • If you have a getter String getName(), somewhere in the Method, you should set a String called name and return it at the end. Don't call the variable n or something other than what the getter is explicitly called.
    • public Data getExtraData(){ ... Data extraData = new Data(); ... return extraData; }

Original

To add to the mix:

Variable Names

For variables names, I like to have them be as explicit as possible usually adding the variable Type as a suffix unless the term is "understood". I especially favor long, descriptive names over short, sometimes-ambiguous names.

For instance variables & all methods, I start the name with a lower-case letter. For static variables I like to start the name with a Capital letter.

Additionally, whenever referencing static variables or methods, I ALWAYS add the class prefix. Furthermore, whenever referencing instance variables or methods, I try to use the this prefix. Therefore it is much clearer where variables/methods come from/reside -- which is especially useful when copying code to and from other classes or re-writing code.

Examples:

  • Set<Id> contactIdSet
  • List<String> nameList
  • List<String> otherNameList
  • Decimal paymentAmount
  • Account parentAccount

When creating a Map, I like to add a comment that states the key/values for reference.

Map<String, Account> accountMap = new Map<String, Account>(); // accountMap: clientCode ---> Account
for(Account clientAccount :
    [SELECT Id, Client_Code__c
     FROM Account
     WHERE RecordType.Name = 'Client']
){
    accountMap.put(clientAccount.Client_Code__c, clientAccount);
}

For for loops, I favor using temp as a prefix for already used variable names:

List<Tax_Payment__c> taxPaymentList = [SELECT Id, Amount__c, Payment_Date__c
                                       FROM Tax_Payment__c
                                       WHERE Payment_Date__c = THIS_FISCAL_QUARTER];
Map<Date, List<Tax_Payment__c>> taxPaymentMap = new Map<Date, List<Tax_Payment__c>>();
    // taxPaymentMap: paymentDate ---> List<TaxPayment>
for(Tax_Payment__c taxPayment :taxPaymentList){
    List<Tax_Payment__c> tempTaxPaymentList = taxPaymentMap.get(taxPayment.Payment_Date__c);
    if(tempTaxPaymentList == null)
        tempTaxPaymentList = new List<Tax_Payment__c>();
    tempTaxPaymentList.add(taxPayment);
    taxPaymentMap.put(taxPayment.Payment_Date__c, tempTaxPaymentList);
}

Rewriting the last example using static and instance methods:

public class TaxPaymentExtension{
    public static String DefaultTaxType = 'Federal 941';

    String taxType;
    public List<Tax_Payment__c> taxPaymentList {get;set;}
    public Map<Date, Tax_Payment__c> taxPaymentMap {get;set;}

    public TaxPaymentExtension(){
        this.taxType = ApexPages.currentPage().getParameters().get('taxtype');
        if(String.isBlank(this.taxType))
            this.taxType = TaxPaymentExtension.DefaultTaxType;
        this.taxPaymentList = [SELECT Id, Amount__c, Payment_Date__c
                               FROM Tax_Payment__c
                               WHERE Payment_Date__c = THIS_FISCAL_QUARTER
                               AND Tax_Type__c = :taxtype];
        this.taxPaymentMap = TaxPaymentExtension.getPaymentMap(taxPaymentList);
    }

    public static Map<Date, Tax_Payment__c> getPaymentMap(List<Tax_Payment__c> tpList){
        Map<Date, Tax_Payment__c> returnMap = new Map<Date, List<Tax_Payment__c>>();
            // taxPaymentMap: paymentDate ---> List<TaxPayment>
        for(Tax_Payment__c taxPayment :taxPaymentList){
            List<Tax_Payment__c> tempTaxPaymentList = taxPaymentMap.get(taxPayment.Payment_Date__c);
            if(tempTaxPaymentList == null)
                tempTaxPaymentList = new List<Tax_Payment__c>();
            tempTaxPaymentList.add(taxPayment);
            taxPaymentMap.put(taxPayment.Payment_Date__c, tempTaxPaymentList);
    }
}

For methods returning a value I like to (1) always create the return variable at the start of the method and (2) have the return variable name of the form return + Type:

!!!! This is all mumbo jumbo.  See Update on 2016-02-17 above. !!! 

public List<Case> getCaseList(){
    List<Case> returnList = new List<Case>();
    // ...
    return returnList;
}

public String getActivityFile(Date startDate, Date endDate){
    String returnString = '';
    // ...
    return returnString;
}

public class Data {
    public List<String> nameList {get;set;}
    public Map<String, Decimal> amountMap {get;set;}  // amountMap: name ---> amount
}

public Data getData(){
    Data returnData = new Data();
    // ...
    return returnData;
}

Test Classes

For Test Classes I like to always construct all necessary Test Data in a subClass. This way it is easy to create the Test Data in the Test Class itself as well as any other Test Class that might need to use it now or later on.

I also like to test Instance and Static methods separately:

@isTest
public class SpecialCaseExtensionTest{

    public class TestData{
        Account testAccount {get;set;}
        List<Case> caseList {get;set;}

        TestData(){
            // ...
        }

        // Have multiple constructors for multiple scenarios
        TestData(Integer caseCount){
            // ...
        }
    }

    @isTest
    public static void testInstanceMethods(){
        TestData tData = new TestData();

        Test.startTest();

        // ...

        Test.stopTest();
    }

    @isTest
    public static void testStaticMethods(){
        TestData tData = new TestData();

        Test.startTest();

        // ...

        Test.stopTest();
    }
}

....

@isTest
public class AnotherCaseExtension{

    public TestData{
        SpecialCaseExtensionTest.TestData specialTestData {get;set;}
        List<Account> extraAccountList {get;set;}
        // ...
    }

    @isTest
    public static void testInstanceMethods(){
        TestData tData = new TestData();

        Test.startTest();

        // ...

        Test.stopTest();
    }

    @isTest
    public static void testStaticMethods(){
        SpecialCaseExtensionTest.TestData tData = new SpecialCaseExtensionTest.TestData();
        // All I need is the Special Case Extension Test Data!
        Test.startTest();

        // ...

        Test.stopTest();
    }