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:
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 ofSet<String> citySet
List<Employee__c> employees
instead ofList<Employee> employeeList
- (Infrequently Used)
Map<Id, Contact> contacts
instead ofMap<Id, Contact> contactMap
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 ofList<Account> accounts
Contact[] contacts = new Contact[]{}
instead ofList<Contact> contacts = new List<Contact>();
Integer[] sizes = new Integer[]{2, 3, 4, 5};
instead ofList<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);
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 calledname
and return it at the end. Don't call the variablen
or something other than what the getter is explicitly called. public Data getExtraData(){ ... Data extraData = new Data(); ... return extraData; }
- If you have a getter
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();
}