Step-by-Step Salesforce Apex Developer Tutorial for beginners

Step-by-Step Salesforce Apex Developer Tutorial for beginners

On September 24, 2021, Posted by , In Salesforce Apex Tutorial, With Comments Off on Step-by-Step Salesforce Apex Developer Tutorial for beginners
Step-by-Step Salesforce Apex Developer Tutorial for beginners
Step-by-Step Salesforce Apex Developer Tutorial for beginners

Table of contents

What is Salesforce Apex?

Salesforce Apex is a powerful programming language developed specifically for the Salesforce.com platform. It is a strongly typed, object-oriented language designed to enable developers to execute flow and transaction control statements on the Force.com platform server, seamlessly integrating with the platform’s API. Apex’s syntax bears a resemblance to Java, making it accessible for those familiar with Java development. This language is pivotal in customizing Salesforce applications, as it can be triggered by various user actions such as clicking a button, accessing weblinks, activating triggers, or interacting with Visualforce pages.

Check out these top Salesforce interview questions and answers for extensive knowledge and informative details about Salesforce Admin, Developer, Integration, and LWC modules.

The versatility of Apex extends to its availability across multiple Salesforce editions, including Enterprise, Performance, Unlimited, Developer, and Database.com. This wide availability underscores Apex’s integral role in the Salesforce ecosystem, providing developers with a robust tool for crafting custom functionalities and workflows. For those looking to master this language, numerous Apex development tutorials are available, offering step-by-step guidance to unlock the full potential of Salesforce customization and enhance the overall user experience within the platform.

We are offering a real-time project based Salesforce course career building program for beginners!

Salesforce Apex Tutorial - Chapter 1: what is Apex

You can find the Salesforce Apex Environment as next chapter, sequel to this one.

Features of Apex – Salesforce programming for beginners :

Salesforce Apex is loaded with several awesome features. Here’s a list of some important features:

  • The Apex programming language is strongly typed.
  • Apex is a case-insensitive programming language.
  • Apex supports DML operations like Insert,Update,Delete etc.
  • Apex can execute multiple queries and DML statements concurrently.
  • Apex runs in a multitenant environment, and salesforce has set up governor limits for each user, so a user can not control shared resources.

Collection is one of the important concept, checkout: Collections in Salesforce Apex

When Should Developer Choose Apex programming as beginner?:

Apex Code should only be written if a business scenario is too complex and can’t be implemented using the pre-built functionality provided by salesforce. Following are a few use cases where apex can be used over salesforce configuration:

  • To create web services that integrate salesforce with other applications.
  • To implement custom and complex validations on Sobjects.
  • To implement complex business processes that can’t be achieved using the out of the box salesforce functionality( Workflow, process builder, and flows)
  • To perform apex logic when a DML operation happens in Salesforce Database.
  • To set up email services which include processing the contents, headers and attachments of the email using the apex code.

Read more: Arrays in Salesforce Apex

Structure of Apex Programming:

Following are the actions that happen when a developer saves the code and an end-user performs some action that invokes Apex code.

Developer Action: Whenever a developer builds and saves the apex code, it compiles the code into a set of instructions that the Apex runtime interpreter can read and save that information as metadata.

End-User Action: As soon as a user event executes apex code, the server receives the compiled instructions from the metadata and sends them through the apex runtime interpreter to the platform server before returning the result.

Below is the architecture of Apex programming and how it runs on the Force.com platform.

Salesforce Apex Tutorial - Chapter 1: Apex Overview Structure of Apex
Salesforce Apex Tutorial – Chapter 1: Apex Overview Structure of Apex

What is the Syntax of Apex – Salesforce programming tutorial syntax: 

Apex Code contains many elements which are similar to other programming languages. Following are a few elements of the apex language.

Variable Declaration: Since Apex is a strongly typed language, every variable must have its own data type. Read more about variables in Salesforce Apex used in Apex programming.

In Apex programming, the syntax for variable declaration is similar to that of Java. Here’s an example of how you can declare variables in Apex:

// Declaring an integer variable
Integer myInteger = 10;

// Declaring a string variable
String myString = 'Hello, Apex!';

// Declaring a list of integers
List<Integer> myList = new List<Integer>{1, 2, 3};

// Declaring a map with String keys and Integer values
Map<String, Integer> myMap = new Map<String, Integer>{'a' => 1, 'b' => 2};

In these examples, you can see that the syntax for variable declaration in Apex involves specifying the data type of the variable, followed by the variable name, and then optionally initializing the variable with a value using the = operator. Apex supports various data types, including primitive types like Integer , String , and Boolean , as well as collection types like List , Set , and Map .

SOQL Query: SOQL(salesforce object query language) directly interacts with the salesforce database and is used to fetch data from the salesforce database.

The below query is used to fetch Contact object records from the Salesforce database.

Contact[] con = [Select Id, FirstName, LastName from Contact];

Loop Statements:

For iterating over a list of records, or a piece of code for a given number of times, Loop statements are used, read more here about loops.

Below is the sample code used to iterate over the list of the Contact object. 

List<Contact> listOfContact = new List<Contact>();// iteration over the contact list
For(Contact con:listOfContact ) {
//logic
};

Flow Control Statement: 

Flow control statements are used when a user wants to execute or stop the execution of a piece of code on specific conditions.

Below code execute the logic if the size of the contact list is greater than zero

List<Contact> conList = [Select Id,FirstName, LastName from Contact Limit 10];
If(conList .size()> 0) {
// execute the logic if the size of the contact list is greater than zero
};

DML Statements:

Data manipulation language(DML) is used to perform  Insert, update, upsert, and delete operations over records in the Salesforce database.

The below code is used to delete the account record of having the name ‘Test’.

List<Contact> conList = [Select Id,FirstName, LastName from Contact Where LastName =Test ’];
Delete conList ;

Sample code snippet

public class ApexDemoController{ 
    Public static void updateContact(){ 
        // variable declaration
        List<Contact> conList = new List<Contact>();
        // SOQL query 
        conList = [Select Id,FirstName,LastName from Contact Where LastName = 'Test'];
        List<contact> listToUpdate = new List<Contact>();
        // iteration over contact list
        for(contact con:conList){
            con.Title = 'Manager';
            listToUpdate.add(con);
        }
        // flow control statement
        if(listToUpdate != null || listToUpdate.size()> 0 ){
            // DML statement
            update listToUpdate;
        }    
        
    }
}

The ApexDemoController class contains a method named updateContact that’s designed to update specific records in the Salesforce database. This method specifically targets Contact records where the last name is ‘Test’.

Checkout: SOSL Query in Salesforce Apex

FAQs

1. How do you handle Apex transaction control and governor limits?

Handling Apex transaction control and governor limits is crucial for ensuring that your code executes efficiently and within Salesforce’s constraints. Here are some strategies and best practices for managing transactions and governor limits:

Read more: Database methods – Salesforce Apex

a. Bulkify Your Code

Bulkification is the process of designing code to handle multiple records at once, rather than one record at a time. This is essential for staying within governor limits.

Example:

List<Account> accountsToUpdate = [SELECT Id, Name FROM Account WHERE Name LIKE 'Test%'];
for (Account acc : accountsToUpdate) {
    acc.Name = 'Updated ' + acc.Name;
}
update accountsToUpdate;

In this example, all updates are performed in a single DML operation rather than individual DML operations within a loop.

Read more: DML in Salesforce Apex

b. Avoid SOQL and DML in Loops

Placing SOQL queries or DML operations inside loops can quickly exceed governor limits.

Bad Practice:

for (Account acc : accounts) {
    Account acc = [SELECT Id FROM Account WHERE Id = :acc.Id];
    update acc;
}

Good Practice:

List<Id> accountIds = new List<Id>();
for (Account acc : accounts) {
    accountIds.add(acc.Id);
}
List<Account> accountsToUpdate = [SELECT Id FROM Account WHERE Id IN :accountIds];
update accountsToUpdate;

Read more: Strings in Salesforce Apex

c. Use Collections

Use collections like List , Set , and Map to store records and perform operations in bulk.

Example:

Map<Id, Account> accountMap = new Map<Id, Account>([SELECT Id, Name FROM Account WHERE Name LIKE 'Test%']);
for (Account acc : accountMap.values()) {
    acc.Name = 'Updated ' + acc.Name;
}
update accountMap.values();

d. Use @future Methods for Asynchronous Processing

@future methods can be used to handle operations asynchronously, allowing the current transaction to complete without waiting for the future method to finish.

Example:

@future
public static void updateAccountNames(Set<Id> accountIds) {
    List<Account> accountsToUpdate = [SELECT Id, Name FROM Account WHERE Id IN :accountIds];
    for (Account acc : accountsToUpdate) {
        acc.Name = 'Updated ' + acc.Name;
    }
    update accountsToUpdate;
}

Collection is one of the important concept, checkout: Collections in Salesforce Apex

e. Use Limits Apex Methods

Salesforce provides Limits class methods to check the current governor limit usage and the remaining limit.

Example:

if (Limits.getQueries() < Limits.getLimitQueries()) {
    List<Account> accounts = [SELECT Id FROM Account WHERE Name LIKE 'Test%'];
}

f. Proper Exception Handling

Implement proper exception handling to ensure that your code can gracefully handle any exceptions and perform necessary rollback operations if needed.

Example:

try {
    List<Account> accountsToUpdate = [SELECT Id, Name FROM Account WHERE Name LIKE 'Test%'];
    for (Account acc : accountsToUpdate) {
        acc.Name = 'Updated ' + acc.Name;
    }
    update accountsToUpdate;
} catch (DmlException e) {
    System.debug('An error occurred: ' + e.getMessage());
}

Read more: Interfaces in Salesforce Apex

2. How do you use trigger context variables in Apex?

Trigger context variables in Apex provide runtime information about the execution of triggers, allowing you to handle different scenarios such as insert, update, and delete operations both before and after the record is saved. These variables include Trigger.isInsert , Trigger.isUpdate , Trigger.isDelete , Trigger.isBefore , Trigger.isAfter , Trigger.new , Trigger.old , Trigger.newMap , Trigger.oldMap , and Trigger.size , enabling you to access and manipulate the records involved in the trigger.

Code Example

trigger AccountTrigger on Account (before insert, before update, after insert, after update, before delete, after delete) {

    if (Trigger.isInsert && Trigger.isBefore) {
        for (Account acc : Trigger.new) {
            System.debug('Before Insert: ' + acc.Name);
        }
    }

    if (Trigger.isInsert && Trigger.isAfter) {
        for (Account acc : Trigger.new) {
            System.debug('After Insert: ' + acc.Name);
        }
    }

    if (Trigger.isUpdate && Trigger.isBefore) {
        for (Account acc : Trigger.new) {
            Account oldAcc = Trigger.oldMap.get(acc.Id);
            System.debug('Before Update - Old Name: ' + oldAcc.Name + ', New Name: ' + acc.Name);
        }
    }

    if (Trigger.isUpdate && Trigger.isAfter) {
        for (Account acc : Trigger.new) {
            Account oldAcc = Trigger.oldMap.get(acc.Id);
            System.debug('After Update - Old Name: ' + oldAcc.Name + ', New Name: ' + acc.Name);
        }
    }

    if (Trigger.isDelete && Trigger.isBefore) {
        for (Account acc : Trigger.old) {
            System.debug('Before Delete: ' + acc.Name);
        }
    }

    if (Trigger.isDelete && Trigger.isAfter) {
        for (Account acc : Trigger.old) {
            System.debug('After Delete: ' + acc.Name);
        }
    }

    System.debug('Total Records in Trigger: ' + Trigger.size);
}

The provided Apex trigger AccountTrigger is designed to handle various operations (insert, update, delete) on the Account object both before and after the records are saved. It uses trigger context variables to differentiate between these operations and contexts. For instance, Trigger.isInsert && Trigger.isBefore checks if the trigger is fired before an insert operation, logging the account name. Similarly, Trigger.isUpdate && Trigger.isBefore compares old and new values before an update, and Trigger.isDelete && Trigger.isAfter logs account names after deletion. The trigger also logs the total number of records involved in each transaction using Trigger.size .

Read more: Database methods in Salesforce Apex

3. Can you explain the exception handling mechanism in Apex?

Exception handling in Apex is a structured mechanism to handle runtime errors, allowing developers to manage and respond to exceptions gracefully rather than allowing the program to crash. Apex provides several constructs for handling exceptions, such as try-catch blocks, custom exceptions, and finally blocks. Here’s a brief overview of these concepts:

Try-Catch Blocks

Try-catch blocks in Apex are used to handle exceptions that may occur during the execution of code within the try block. If an exception occurs, control is passed to the catch block where you can handle the error.

Example:

try {
    // Code that may throw an exception
    Account acc = [SELECT Id FROM Account WHERE Name = 'NonExistentAccount'];
} catch (QueryException e) {
    // Handle the exception
    System.debug('QueryException: ' + e.getMessage());
} catch (Exception e) {
    // Handle any other exceptions
    System.debug('Exception: ' + e.getMessage());
}

Custom Exceptions

You can define custom exception classes by extending the built-in Exception class. Custom exceptions are useful when you need to handle specific error conditions uniquely.

Example:

public class CustomException extends Exception {}

try {
    // Some code that throws a custom exception
    throw new CustomException('This is a custom exception');
} catch (CustomException e) {
    System.debug('Caught CustomException: ' + e.getMessage());
}

Finally Block

A finally block contains code that is always executed after the try and catch blocks, regardless of whether an exception was thrown. This is useful for cleanup activities.

Example:

try {
    // Code that may throw an exception
    Integer result = 10 / 0; // This will throw a DivideByZeroException
} catch (ArithmeticException e) {
    // Handle the exception
    System.debug('ArithmeticException: ' + e.getMessage());
} finally {
    // Code that will always execute
    System.debug('This is the finally block');
}

Read more: Arrays in Salesforce Apex

Throwing Exceptions

You can throw exceptions manually using the throw statement. This is useful when you want to enforce certain conditions or validate data.

Example:

public void validateAccount(Account acc) {
    if (acc.Name == null) {
        throw new CustomException('Account name cannot be null');
    }
}

try {
    Account acc = new Account();
    validateAccount(acc);
} catch (CustomException e) {
    System.debug('Validation failed: ' + e.getMessage());
}

4. What are the best practices for writing test classes in Apex to ensure high code coverage?

Writing effective test classes in Apex is crucial for ensuring high code coverage and robust code quality. Here are some best practices for writing test classes in Apex to achieve high code coverage:

a. Use Test Data Factories

Creating reusable test data factory classes helps to generate consistent test data, making your tests cleaner and more maintainable.

Example:

public class TestDataFactory {
    public static Account createAccount() {
        Account acc = new Account(Name = 'Test Account');
        insert acc;
        return acc;
    }
}

Checkout: Data types in Salesforce Apex

b. Test Different Scenarios

Ensure that you test all possible scenarios, including positive, negative, and edge cases.

Example:

@isTest
public class AccountTriggerTest {
    @isTest
    static void testAccountInsert() {
        // Positive case
        Account acc = TestDataFactory.createAccount();
        System.assertEquals('Test Account', acc.Name);
    }

    @isTest
    static void testAccountInsertWithoutName() {
        // Negative case
        Account acc = new Account();
        try {
            insert acc;
            System.assert(false, 'Expected exception not thrown');
        } catch (DmlException e) {
            System.assert(e.getMessage().contains('REQUIRED_FIELD_MISSING'));
        }
    }
}

c. Use Test.startTest() and Test.stopTest()

Encapsulate your test logic between Test.startTest() and Test.stopTest() to reset governor limits and ensure that your tests run within limits.

Example:

@isTest
public class AccountTriggerTest {
    @isTest
    static void testAccountInsertWithLimits() {
        Test.startTest();
        Account acc = TestDataFactory.createAccount();
        Test.stopTest();
        
        System.assertEquals('Test Account', acc.Name);
    }
}

Read more: Salesforce apex programming examples

d. Verify Results Using Assertions

Use System.assert() methods to validate the expected outcomes of your tests.

Example:

@isTest
public class AccountTriggerTest {
    @isTest
    static void testAccountInsert() {
        Account acc = TestDataFactory.createAccount();
        System.assertEquals('Test Account', acc.Name);
        System.assertNotEquals(null, acc.Id);
    }
}

e. Cover All Branches of Code

Ensure that your tests cover all possible branches of your code, including if statements, loops, and exception handling.

Example:

public class AccountService {
    public void updateAccount(Account acc) {
        if (acc.Name == null) {
            throw new CustomException('Account name cannot be null');
        }
        update acc;
    }
}

@isTest
public class AccountServiceTest {
    @isTest
    static void testUpdateAccount() {
        Account acc = TestDataFactory.createAccount();
        acc.Name = 'Updated Account';
        
        AccountService service = new AccountService();
        service.updateAccount(acc);
        
        System.assertEquals('Updated Account', [SELECT Name FROM Account WHERE Id = :acc.Id].Name);
    }

    @isTest
    static void testUpdateAccountWithException() {
        Account acc = TestDataFactory.createAccount();
        acc.Name = null;
        
        AccountService service = new AccountService();
        try {
            service.updateAccount(acc);
            System.assert(false, 'Expected exception not thrown');
        } catch (CustomException e) {
            System.assert(e.getMessage().contains('Account name cannot be null'));
        }
    }
}

5. How do the ‘with sharing’ and ‘without sharing’ keywords affect data visibility in Apex?

In Apex, the with sharing and without sharing keywords determine the data visibility and sharing rules applied when an Apex class executes. These keywords control whether the class respects the user’s organization-wide sharing settings, role hierarchies, and sharing rules. Understanding their effects is crucial for maintaining data security and integrity in your Salesforce application.

Read more: Loops in Salesforce Apex

with sharing

When a class is defined with the with sharing keyword, it enforces the sharing rules of the current user. This means that the class respects the sharing settings and only allows access to records that the user is authorized to view or manipulate according to their permissions and sharing rules.

Example:

public with sharing class AccountService {
    public List<Account> getAccounts() {
        return [SELECT Id, Name FROM Account];
    }
}

Explanation: In this example, AccountService is defined with with sharing . When getAccounts is called, it will only return Account records that the current user has access to based on their sharing settings.

without sharing

When a class is defined with the without sharing keyword, it ignores the sharing rules of the current user. This means that the class has access to all records, regardless of the user’s sharing settings. However, it still respects field-level security and object permissions.

Example:

public without sharing class AccountService {
    public List<Account> getAllAccounts() {
        return [SELECT Id, Name FROM Account];
    }
}

Watch our FREE Salesforce online course video, it’s a full length free tutorial for beginners.

Explanation: In this example, AccountService is defined with without sharing . When getAllAccounts is called, it will return all Account records in the database, ignoring the user’s sharing settings. The user will be able to see all accounts, even those they wouldn’t normally have access to.

CRS Info Solutions offers real-time  Salesforce course for beginners designed to equip learners with practical knowledge and industry skills in Salesforce. Enroll for demo today.

If you are looking for hands-on experience, enroll for our Salesforce training in Hyderabad to gain practical, hands-on experience, real-time projects included.

Next chapter is Apex environment, Apex examples and data types in apex.

Comments are closed.