Apex runs in a multi-tenant world where the platform actively defends shared resources with governor limits. Code that works on one record and explodes on two hundred is the most common — and most avoidable — failure mode in a Salesforce org. After years of architecting enterprise-grade applications, these are the patterns I insist on.
Bulkify everything, always
Assume every trigger and method will receive a collection, because eventually it will — a data load, an integration, a mass update. The cardinal sins are SOQL or DML inside a loop:
// WRONG — a query per record; dies at scale.
for (Case c : cases) {
Account a = [SELECT Risk_Score__c FROM Account WHERE Id = :c.AccountId];
c.Priority = a.Risk_Score__c > 80 ? 'High' : 'Medium';
}
// RIGHT — one query, one map, set-based work.
Set<Id> ids = new Set<Id>();
for (Case c : cases) ids.add(c.AccountId);
Map<Id, Account> accts = new Map<Id, Account>([
SELECT Id, Risk_Score__c FROM Account WHERE Id IN :ids WITH SECURITY_ENFORCED
]);
for (Case c : cases) {
Account a = accts.get(c.AccountId);
c.Priority = (a != null && a.Risk_Score__c > 80) ? 'High' : 'Medium';
}
Design for the bulk case and the single-record case comes free. Design for one record and the bulk case becomes a production incident.
Respect the user's permissions
Apex runs in system context by default, which means it will happily read and write fields the running user should never see. In an enterprise org that's a security finding waiting to happen. Enforce sharing and field-level security deliberately:
with sharingon classes that act on behalf of a user, so record visibility is respected.WITH SECURITY_ENFORCEDin SOQL to enforce object and field-level read access.Security.stripInaccessible()before DML, so you never write fields the user can't edit.
Architect for maintainability, not just limits
Staying under governor limits is table stakes. The harder goal is code your team can still reason about in two years. A few habits that compound:
- One trigger per object, delegating to a handler class — predictable order of execution.
- Service-layer separation — business logic in testable classes, not buried in triggers or controllers.
- Query selectively — only the fields and rows you need, with sensible
LIMITs. - Async where it belongs — Queueable/Batch Apex for large volumes, keeping synchronous paths snappy.
Prove it under load
Every test class should include a bulk scenario — 200 records minimum — plus negative and permission cases. If a test only ever inserts one record, it isn't testing the thing most likely to break.
Takeaway
Scalable Apex isn't about clever tricks; it's discipline applied consistently: bulkify, query once, enforce security, and separate concerns. Do that and governor limits stop being a threat and become a guardrail.
Reviewing an Apex codebase or setting standards for a team? I'm happy to help.