Salesforce-Coding-Standards

Appsavio Coding Standards




Naming Conventions


IDENTIFIER CASE EXAMPLE
Class Pascal Account
Enum type Pascal Severity
Enum values Pascal Severity.Error
Field camel listItem
Final/Const field Pascal MaximumCount
Static field Pascal RedValue
Interface Pascal Idisposable
Method in Apex, Java camel toString
Method in C# Pascal ToString
Parameter camel typeName
Property Pascal BackColor
Trigger Pascal SendEmailOnNewAccount


In Apex, primitive types such as String, Decimal are all classes. So they should be Pascal casing.


Comments

The description should include useful information about what it is, why you created it, and any known issues or dependencies:

/**
* @description : Description of the class
* @author : Author Name
* @created Date : CreatedDate
* @last modified on : LastModifiedDate
* @Test class: Name of Test class for this class
**/

You can download the VScode extension named Salesforce Documenter


Coding style

This is not about right or wrong, but we make an agreement to put it to the next line, like:

public class Whatever
{ 
	//recommended  
} 

This rule applies to all kinds of code blocks, including class, method, property, if-else, while, etc.

Use blank spaces properly as betrayed in the following table:

EXPRESSION BLACK SPACE EXAMPLE
Arithmetical operator 1 b + c
Assignment 1 a = b + c
Comparison 1 a >= b + c
Semi-colon 0 a = b + c;
if/while 1 if (a == b + c)
for loop 1 for (i = 0; i < 100; i++)
Unary operator 0 <p>!bool </p><p>-i</p>
Increment/Decrement 0 <p>i++ </p><p>–i</p>
Ternary operator 1 (a == null) ? 0 : a
Function call 0 sendEmail(email);
Subscript 0 array[0]
Automatic property 1 <p>String Name { get; </p><p>set; }</p>

Example:

a = b + c; // right  

a=b+c; // wrong  

a = b + c ; // wrong  

a = (a == null) ? 0 : a; // right  

a = (a == null)?0:a; // wrong  

for (i = 0; i < 10; i++) // right  

for(i=0;i<10;i++) // wrong  

for (i = 0; i < 10; i ++) // wrong 

a = -- b; // wrong  

a = --c; // right  

a = - b; // wrong  

a = -b; // right  

public String Name{get;set;} // wrong  
public String Name { get; set; } // right 

Example:

If () {}


SOQL Rules

[SELECT Id, Name FROM Account WHERE Website = 'Test'] //Recommended

[select Id, Name From Account where Website = 'Test'] 
//Not Recommended
//Not Recommend
List<Account> acctList = [SELECT Id FROM Account]; 
for( Account acct : acctList ){
	//Process here
}


//Recommend
for( Account acct : [SELECT Id FROM Account] ){
	//Process here
}
//Not Recommend
List<Account> acctList = [ SELECT Id, Name FROM Account ];
List<Opportunity> oppList = [ SELECT Id, Name 
			      FROM Opportunity 
			      WHERE Account Id IN: acctList];		

//Recommend
List<Account> acctList = [ SELECT Id, Name
			 ( SELECT Id FROM Opportunities )
			   FROM Account ];

//Recommend
[ SELECT Id, Name FROM Account Where Id IN: keySet() ];

//Not Recommend
[SELECT Id,Name FROM Account Where Id IN:keyset()];

Enterprise Structure

To keep the code sophisticated and easy to maintained developers should write their code in a well-mannered structure that will keep the different parts of the at their appropriate places.

The General structure for coding is below:

enter image description here

Trigger

The Apex Trigger should contain only the Trigger session logics ( After, Before, Insert Update ). It should not contain any business-related logic. Based on different sessions the trigger should call the methods or the TriggerHandler class.

trigger TriggerAccount on Account{

	if( Trigger.isBefore ){
		if( Trigger.isInsert ){
			AccountTriggerHandler.setAccountAge( Trigger.Name );
		}
	}
	if( Trigger.isAfter ){
		if( Trigger.isInsert ){
			AccountTriggerHandler.createAccountContacts( Trigger.Name );
		}
	}
		

}

TriggerHandler

To handle the Data to be inserted or modified developers should create a TriggerHandler class. TriggerHandler should have separate methods for each functionality and should be called from Trigger inappropriate conditions. TriggerHandlers should call the methods from the Object Specific Service Class method that contains all the business logic. It is not recommended to have any DML in TriggerHandler class. An example of TriggerHandler is as follows:

public class AccountTriggerHandler{
	
	public static void setAccountAge( List<Account> newAccounts ){
		List<Account> acctList = new List<Account>();
		for( Account acct : newAccounts ){
			if( acct.Email != null ){
				acctList.add( acct );
			}
		}
		AccountService.setAccountAge( acctList );
	}
	
	public static void createAccountContacts( List<Account> newAccounts ){
		AccountService.createAccountContacts( newAccounts );
	}
}

ObjectService class

The Object Service class contains all the business logic for the object. This class is named after the sObject name. For example, AccountService will contain all the logic for happening on the Account object same for other standard and custom objects. This makes it easy to find and resolve the issues and also keeps the code clean and structured. An example of a Service class is given below:

public class AccountService{
	
	public static void setAccountAge( List<Account> newAccounts ){
		//Business logics here
	}
	
	public static void createAccountContacts( List<Account> newAccounts ){
		//Business logics here
	}
}

ObjectSelector class

The selector classes contain all the queries for the specific objects. For example, the AccountSelector class will contain all the SOQL happening on the Account object in this org. Then this method should be called from different classes. This class layer helps to detect the Governer limits spend and resolve them. It helps developers to monitor easily which queries they are using and also helps in Code reusability. An example for Selector class is as follows.

public class AccountSelector{

	//Following method can be called from Service or Controller class.
	public static List<Account> getAccountsById( Set<Id> accIds ){
		return [ SELECT Id, Name, Website FROM Account WHERE Id IN: accIds ];
	}	

}

Controller class

Controller classes are created specifically for Lightning Components and Vifsualforce pages. These classes contain the component-specific logic but as far as business-related logic is considered controller classes call the methods from the Service classes to perform DML on records. It is not recommended to have DMLs in Controller classes. Following is an example for the Controller class structure.


public class AccountPageController{
	
	@AuraEnabled
	public static List<Account> getAccountDetails( Set<Id> accIds ){
		return AccountSelector.getAccountsById( accIds );
	}

	@AuraEnabled
	public static void updateAccounts( List<Account> acctList ){
		AccountService.updateAccounts( acctList );
	} 

}

Trigger Standards

‘Trigger’+ObjectName
For Example TriggerOpportunity or TriggerAccount


if( Trigger.isBefore ){

	if( Trigger.isInsert ){
		//Call all Before Insert Methods here
	}

	if( Trigger.isUpdate ){
		//Call all Before Insert Methods here
	}

	if( Trigger.isDelete ){
		//Call all Before Insert Methods here
	}

}

if( Trigger.isAfter ){

	if( Trigger.isInsert ){
		//Call all After Insert Methods here
	}

	if( Trigger.isUpdate ){
		//Call all After Insert Methods here
	}

	if( Trigger.isDelete ){
		//Call all After Insert Methods here
	}

}

Apex Batch Standards

Apex Test Class Standards

@isTest
private class AccountServiceTest{

}
@isTest
private class AccountServiceTest{
	
	@TestSetup
	static void createData(){

		Account acct = new Account( Name = 'Test Account' );
		insert acct;
		//Further records insertion below
	}

}
	@isTest
	static void accountWebsiteUpdateTest(){
		//Logic to test Website test
	}

	@isTest
	static void accountOpportunityInsertTest(){
		//Logic to test Opportunity Insert
	}
	@isTest
	static void accountWebsiteUpdateTest(){
		Account acct = [SELECT Id FROM Account LIMIT 1];

		Test.startTest();
			AccountService.accountWebsiteUpdate( acct );
		Test.stopTest();
	}
	@isTest
	static void accountWebsiteUpdateTest(){
		Account acct = [ SELECT Id FROM Account LIMIT 1 ];

		Test.startTest();
			AccountService.accountWebsiteUpdate( acct );
		Test.stopTest();

		Account updatedAccount = [ SELECT Id, Website FROM Account WHERE Id =: acct.Id ];

		System.assertEquals( 'myTestWebsite.com', updatedAccount.Website, 'Provide Error message here is assert fails' );
	}

Flow Standards


VS Code Must Have Extensions

APEX PMD

Apex PMD will provide useful tips about how you can optimize the code and make it better.

Salesforce Package XML generator

This extension will help to create Package.xml file with various Salesforce Metadata elements. It provides a rich UI that makes it convenient to create desired package xml files that can be used in Deployments.

Salesforce Query Editor

If you don’t like to Open developer whenever you want to query some records, you may like this extension. It will rich UI for Building your Query and show the returned records in a tabular format.

Beautify

Beautify provides code formatting natively for JS, HTML and CSS. Other than these languages it can be utilized for Apex and Visualforce as well. Apex can be formatted as per javascript standards. This extension doesn’t require any extra installation or configurations.

Snippets Extensions

These extensions will help you by providing auto completion for your code syntax. Following are some recommendations: