
Salesforce Interview Preparation: Apex, LWC, Triggers & System Design
Master your next Salesforce developer interview with this focused revision guide on Apex, triggers, LWC, and real-world architecture patterns.
Salesforce Interview Preparation: Apex, LWC, Triggers & System Design
If you're preparing for a Salesforce developer interview, you know the drill: platform-specific quirks, governor limits, trigger frameworks, and architecture decisions that don't appear in any standard CS curriculum. I've been through this process multiple times — both as a candidate and as an interviewer. This guide condenses the concepts that actually matter in interviews and real projects.
1. Apex Basics: Object-Oriented Salesforce Style
Apex is strongly typed, case-insensitive, and runs on the Salesforce platform. You need to understand classes, interfaces, inheritance, and especially the without sharing vs with sharing keywords. Interviewers often ask: When would you use
The trick is that without sharing?without sharing runs in system context, bypassing user permissions — useful for administrative operations but dangerous if misused.
Another common topic is the difference between List, Set, and Map. I once spent 20 minutes in an interview explaining why Map<Id, sObject> is faster than nested loops for lookups. It's a simple point, but the interviewer wanted to see if I understood heap limits and query efficiency.
// Example: Using Map to avoid SOQL in loop
Map<Id, Account> accMap = new Map<Id, Account>([SELECT Id, Name FROM Account]);
for (Contact con : contacts) {
if (accMap.containsKey(con.AccountId)) {
con.AccountName__c = accMap.get(con.AccountId).Name;
}
}Key takeaway: Know the sharing model, collection performance, and how Apex handles exceptions (DmlException, QueryException, LimitException).
2. Triggers & Context Variables
Triggers are the backbone of Salesforce automation, but they're also the most common source of recursion bugs and governor limit violations. The key is understanding trigger context variables: isBefore, isAfter, isInsert, isUpdate, isDelete, isUndelete, Trigger.new, Trigger.old.
I always recommend a single trigger per object pattern with a handler class. Interviewers love this because it shows you value maintainability over quick hacks.
// Single trigger pattern
trigger AccountTrigger on Account (before insert, before update) {
AccountTriggerHandler.handle();
}A classic question: How do you prevent recursive triggers?
Use a static Boolean flag in a helper class. Don't put it in the trigger itself — that's a rookie mistake.
3. SOQL & Governor Limits
SOQL is Salesforce's query language, and governor limits are the hard constraints that keep multi-tenant environments stable. Every developer should memorize the key limits: 100 SOQL queries per transaction, 50,000 records retrieved, 10 MB heap size for synchronous Apex.
During an interview, I was asked to optimize a loop containing a SOQL query. The answer is to use SOQL for loop with [SELECT ... FROM ... WHERE ...] and collect records into a list, then query once. Better yet, use batch queries with Database.QueryLocator for large datasets.
Common trap: How do you avoid hitting the 50,000 record limit?
Use LIMIT, filter with indexed fields, or aggregate queries (COUNT(), SUM()).
// Aggregation example
AggregateResult[] groupedResults = [SELECT AccountId, COUNT(Id) contactCount FROM Contact GROUP BY AccountId];4. LWC Essentials
Lightning Web Components are the modern UI framework for Salesforce. You need to understand the component lifecycle (connectedCallback, renderedCallback, disconnectedCallback), data binding with @track and @api, and communication between components via events and pubsub.
I once built a reusable lookup component using LWC. The interviewer asked how I handled stale data. The answer: use refreshApex from the @salesforce/apex module to re-fetch data after a mutation.
// LWC wire service example
import { LightningElement, wire } from 'lwc';
import getAccounts from '@salesforce/apex/AccountController.getAccounts';
export default class AccountList extends LightningElement {
@wire(getAccounts) accounts;
}Key items: Know when to use @wire vs imperative Apex, how to handle errors in promise chains, and the security restrictions on @api properties.
5. Integration & Security
Salesforce integrates with external systems via REST, SOAP, and Streaming APIs. Interviewers look for understanding of OAuth 2.0 flows (especially JWT bearer and refresh token), callout limits (10 synchronous per transaction), and how to handle large payloads with Continuation classes.
A question I encountered: How would you integrate Salesforce with an external payment gateway?
I described a Flow-triggered Apex REST callout, with error handling and retries using Platform Events. That impressed the interviewer because it demonstrated asynchronous reliability.
Security topics: CRUD/FLS enforcement in Apex, sharing rules, and field-level security. Use Schema.sObjectType.Account.fields.Name.isAccessible() to check permissions programmatically.
6. Architecture Patterns
Enterprise Salesforce projects require patterns like Service Layer, Selector Layer, and Domain Layer. This is where you separate concerns: service classes handle business logic, selector classes handle SOQL queries, and domain classes handle record-level logic.
I once demonstrated this pattern during a system design interview for a multi-org integration. The interviewer asked how to handle slow external API responses. I recommended a Platform Event + Streaming API pattern to process updates asynchronously. That's the kind of architecture thinking that wins.
Trade-off: Simpler orgs might not need the full enterprise pattern. Start with a trigger handler + service class, and refactor as complexity grows.
7. Testing Best Practices
Salesforce requires at least 75% code coverage for deployment. But interviews probe deeper: Do you test negative scenarios? Do you use Test.startTest() and Test.stopTest() to isolate governor limits? Do you assert both record state and system behavior?
A common test scenario: Write a test for a trigger that updates an Account's rating based on opportunities.
You need to insert test data, call the trigger, and verify the rating field. Don't forget to use @isTest(SeeAllData=false).
@isTest
static void testRatingUpdate() {
Account acc = new Account(Name='Test');
insert acc;
Opportunity opp = new Opportunity(Name='Test Opp', StageName='Closed Won', Amount=100000, AccountId=acc.Id);
Test.startTest();
insert opp;
Test.stopTest();
Account updatedAcc = [SELECT Rating FROM Account WHERE Id = :acc.Id];
System.assertEquals('Hot', updatedAcc.Rating);
}