Land the job you want — prepare
with Real interviews Q&A
Curated interview questions, company-wise guides and coding rounds. Practice mock interviews, improve with feedback, and track your progress.
Apex is object-oriented, strongly typed, multitenant aware, integrated directly with the database, and provides built-in support for transactional triggers as well as complex asynchronous processing loops.
Account acc = new Account(Name = 'Acme Corp');
insert acc;
Governor limits are runtime limits enforced by the Salesforce multitenant engine to prevent shared execution threads from monopolizing system resources.
// Bulkified query and list insert
List<Contact> contactsToInsert = new List<Contact>();
for (Account acc : [SELECT Id FROM Account LIMIT 100]) {
contactsToInsert.add(
new Contact(
LastName = 'Doe',
AccountId = acc.Id
)
);
}
insert contactsToInsert;
SOQL (Salesforce Object Query Language) is used to read data structures and records from individual object structures.
List<Opportunity> opps = [
SELECT Id, Name, Amount, StageName
FROM Opportunity
WHERE CloseDate = TODAY
];
SOSL (Salesforce Object Search Language) is used to scan text patterns across multiple index tables at once.
List<List<SObject>> searchList = [
FIND 'Acme*'
IN ALL FIELDS
RETURNING
Account(Name),
Contact(FirstName, LastName)
];
SOQL retrieves exact records from a single object index, whereas SOSL performs multi-object keyword searches efficiently across text columns.
// SOQL (Exact retrieval)
Account acc = [
SELECT Id
FROM Account
WHERE Name = 'Acme'
LIMIT 1
];
// SOSL (Fuzzy search)
List<List<SObject>> results = [
FIND 'Acme'
IN NAME FIELDS
RETURNING Account(Id, Name)
];
A trigger is Apex code that runs dynamically before or after specific DML operations, such as record insertions, edits, or removals.
trigger AccountTrigger on Account (before insert, before update) {
for (Account acc : Trigger.new) {
if (acc.Industry == null) {
acc.Industry.addError('Industry is required.');
}
}
}
Data Manipulation Language statements modify records in the Salesforce database (e.g., insert, update, delete, undelete, upsert).
List<Account> newAccs = new List<Account>{
new Account(Name = 'Tech Corp'),
new Account(Name = 'Media Group')
};
insert newAccs;
A class is a structural template or object-oriented blueprint containing processing methods and properties.
public class Vehicle {
private String model;
public Vehicle(String modelName) {
this.model = modelName;
}
}
Apex provides four levels of visibility control: public, private, protected, and global.
global class GlobalService {
public static void performTask() {
// Shared across namespaces and API integrations
}
}
A static variable is scoped to the class itself rather than individual instances, and persists across execution contexts.
public class Counter {
public static Integer staticCount = 0; // Class-level shared state
public Integer instanceCount = 0; // Object-level individual state
}
A constructor is a special class method called automatically during object instantiation to initialize state.
public class Employee {
public String name;
public Employee(String empName) {
this.name = empName;
}
}
Batch Apex processes massive datasets asynchronously by splitting operations into smaller, manageable transaction blocks called chunks.
public class AccountUpdateBatch implements Database.Batchable<SObject> {
public Database.QueryLocator start(Database.BatchableContext bc) {
return Database.getQueryLocator(
'SELECT Id FROM Account'
);
}
public void execute(
Database.BatchableContext bc,
List<Account> scope
) {
// Process each chunk safely
}
public void finish(Database.BatchableContext bc) {
// Post-processing logic
}
}
A future method (annotated with @future) executes asynchronously in its own thread block when resources become available.
public class AsyncHelper {
@future
public static void callExternalWebService(String payload) {
// Async processing
}
}
A test class contains verification logic to test Apex code functionality, and is required to hit a minimum 75% code coverage threshold for production deployments.
@isTest
private class AccountServiceTest {
@isTest
static void testAccountCreation() {
Account acc = new Account(Name = 'Test Acc');
insert acc;
System.assertNotEquals(
null,
acc.Id,
'Account ID should be generated'
);
}
}
Bulkification is the practice of designing code to handle sets of records efficiently in a single operation, rather than processing individual records one-by-one inside loop blocks.
// BAD (Trigger with nested query)
// for (Account a : Trigger.new) {
// List<Contact> c = [
// SELECT Id
// FROM Contact
// WHERE AccountId = :a.Id
// ];
// }
// GOOD (Bulkified query mapping)
Set<Id> accIds = new Set<Id>();
for (Account a : Trigger.new) {
accIds.add(a.Id);
}
List<Contact> contacts = [
SELECT Id, LastName
FROM Contact
WHERE AccountId IN :accIds
];
A wrapper class is a custom container object used to bind multiple distinct data types or sObjects together into a single logical structure.
public class TableWrapper {
public Account accRecord { get; set; }
public Boolean isSelected { get; set; }
public TableWrapper(Account a) {
this.accRecord = a;
this.isSelected = false;
}
}
A map is an un-ordered collection that stores data in key-value pairs, where each key uniquely maps to a single corresponding value.
Map<Id, Account> accountMap =
new Map<Id, Account>([
SELECT Id, Name
FROM Account
LIMIT 10
]);
Account target =
accountMap.get('0018000000GvNX0AAN');
A set is an unordered collection of elements that enforces uniqueness, preventing duplicate entries from being added to the collection.
Set<String> uniqueCodes =
new Set<String>{
'US',
'UK',
'CA',
'US'
};
System.debug(uniqueCodes.size()); // Outputs 3
A list is an ordered collection of elements indexed by position. It can contain duplicate values and functions like a standard dynamic array.
List<String> names = new List<String>();
names.add('Akash');
names.add('Rahul');
String first = names.get(0);
Queueable Apex is an asynchronous design pattern that builds upon future methods, allowing you to monitor job status and chain sequential asynchronous execution flows.
public class AsyncProcessor implements Queueable {
public void execute(QueueableContext context) {
// Chainable async operation
System.enqueueJob(new SecondaryProcessor());
}
}
An sObject is a generic data type that can represent any standard or custom Salesforce object record in memory.
sObject genericRecord =
new Account(Name = 'Generic Corp');
String objName =
genericRecord
.getSObjectType()
.getDescribe()
.getName();
Schema Builder is a visual design utility inside Salesforce used to manage data models, define objects, and establish relationship connections. At the code level, you describe these schemas programmatically.
Map<String, Schema.SObjectType> gd =
Schema.getGlobalDescribe();
Schema.DescribeSObjectResult descResult =
gd.get('Account').getDescribe();
The with sharing keyword enforces the organization-wide defaults and sharing rules of the running user for all database queries and transactions in that class.
public with sharing class SecureRecordController {
// Respects sharing rules
// of current logged-in user
}
The without sharing keyword executes class logic in system mode, ignoring the current user's sharing rules and record permissions.
public without sharing class AdminDataOverrider {
// Skips sharing rules
// and operates with system-level access
}
The upsert command checks if a record exists based on an ID or unique external ID field; it updates the record if found, or inserts a new record if it is not.
Account acc = new Account(
Name = 'Upsert Corp',
External_ID__c = 'EXT-101'
);
upsert acc External_ID__c;
The Database class provides system methods for database manipulation, supporting partial successes via the allOrNone parameter option.
Database.SaveResult[] srList =
Database.insert(accountList, false);
// false allows partial success
Trigger context variables (e.g., Trigger.new, Trigger.oldMap, Trigger.isInsert) provide operational state and data from the triggering transaction.
trigger ContactTrigger on Contact (before update) {
for (Contact newCon : Trigger.new) {
Contact oldCon =
Trigger.oldMap.get(newCon.Id);
if (newCon.Email != oldCon.Email) {
System.debug(
'Email changed from '
+ oldCon.Email
);
}
}
}
A callout executes HTTP requests from Apex to integrate and exchange payload data with external web services.
Http http = new Http();
HttpRequest request = new HttpRequest();
request.setEndpoint(
'https://api.example.com/data'
);
request.setMethod('GET');
HttpResponse response =
http.send(request);
Exception handling uses try-catch-finally blocks to intercept runtime errors, handle failures gracefully, and execute mandatory cleanup actions.
try {
insert new Lead(LastName = 'Smith');
}
catch (DmlException e) {
System.debug(
'DML failed: ' + e.getMessage()
);
}
finally {
System.debug(
'Transaction finished processing.'
);
}
Apex methods annotated with @AuraEnabled allow client-side Lightning Web Components (LWC) to call server-side actions, retrieve database records, or trigger business logic.
public class ContactController {
@AuraEnabled(cacheable=true)
public static List<Contact> getContactList() {
return [
SELECT Id, FirstName, LastName
FROM Contact
LIMIT 10
];
}
}
Platform Events support an event-driven architecture, enabling applications to run independently by publishing and subscribing to real-time notification streams.
Order_Event__e eventObj =
new Order_Event__e(
Order_Id__c = 'ORD-009',
Status__c = 'Shipped'
);
Database.SaveResult sr =
EventBus.publish(eventObj);
A Mixed DML error occurs when you try to modify a setup object (like User) and a non-setup object (like Account) in the same transaction context.
User u = [
SELECT Id
FROM User
WHERE Alias = 'admin'
];
System.runAs(u) {
// Update User (Setup Object)
}
// Update Account (Non-Setup Object)
// outside block
The Apex Scheduler executes specific classes at scheduled intervals by implementing the Schedulable interface.
public class CleanupScheduler
implements Schedulable {
public void execute(SchedulableContext sc) {
// Delete orphaned logs dynamically
}
}
Custom Metadata Types are application configurations that can be packaged and deployed between environments. They are read from cache without consuming SOQL query limits.
App_Setting__mdt setting =
App_Setting__mdt.getInstance(
'Global_Config'
);
Boolean featureEnabled =
setting.Is_Active__c;
Field-Level Security (FLS) manages user access to specific fields on objects. It should be validated dynamically in Apex before querying or mutating field data.
if (
Schema.sObjectType.Contact
.fields.Email.isAccessible()
) {
// Query/Read field safely
}
Dynamic SOQL allows you to construct and execute SOQL query strings at runtime using the Database.query() method.
String dynamicField = 'Phone, Email';
String queryStr =
'SELECT Id, '
+ dynamicField
+ ' FROM Lead LIMIT 5';
List<Lead> leads =
Database.query(queryStr);
A Savepoint defines a specific state in a transaction that you can roll back to in case of errors, without reverting the entire transaction.
Savepoint sp =
Database.setSavepoint();
try {
insert new Account(
Name = 'Success'
);
insert new Contact();
// Fails due to missing LastName
}
catch (Exception e) {
Database.rollback(sp);
// Reverts transaction
}
Custom Settings are application configurations cached in memory. They provide fast read access without using SOQL query limits.
Discount_Setting__c discount =
Discount_Setting__c.getInstance();
Decimal rate =
discount.Global_Rate__c;
CRUD permissions control user access to entire objects, while FLS permissions control user access to specific fields on those objects.
if (
Schema.sObjectType.Account.isCreateable()
&&
Schema.sObjectType.Account
.fields.Rating.isCreateable()
) {
insert new Account(
Name = 'Protected Inc',
Rating = 'Hot'
);
}
List<Account> accs = [
SELECT Id, Name
FROM Account
];
Account acc =
new Account(Name='Test');
insert acc;
acc.Name = 'Updated';
update acc;
delete acc;
@future
public static void asyncMethod() {
// Long running asynchronous process
}
global class MyBatch
implements Database.Batchable<SObject> {
global Database.QueryLocator start(
Database.BatchableContext BC
) {
return Database.getQueryLocator(
'SELECT Id FROM Account'
);
}
global void execute(
Database.BatchableContext BC,
List<Account> scope
) {
// Batch chunks executed here
}
global void finish(
Database.BatchableContext BC
) {
// Cleanup actions
}
}
trigger AccountTrigger on Account (
before insert
) {
for (Account acc : Trigger.new) {
// Before insert logic
}
}
public class MyQueue
implements Queueable {
public void execute(
QueueableContext context
) {
// Async processing
}
}
String q =
'SELECT Id FROM Account';
List<Account> accs =
Database.query(q);
try {
// Execution with risk
}
catch (DmlException e) {
System.debug(
'Exception: ' + e.getMessage()
);
}