10 Essential Principles for Writing Clean, Scalable, and Maintainable Apex Code
Apex is the core language for custom development in Salesforce. While powerful, it comes with strict governor limits and architectural considerations. Writing Apex is not just about making things work, It’s about making them scalable, testable, and ready for change. This decalogue presents 10 original and practical guidelines to help you build reliable solutions using Apex.
ARTICLES
1. Bulkify all your logic
Handle multiple records in a single execution. Never place SOQL or DML inside loops.
2. Implement proper error handling
Wrap critical operations, especially DML and callouts in try/catch and avoid generic exceptions where possible. Log useful context and, if appropriate, relay a user‑friendly error. Avoid catching generic Exception unless necessary. Catch the specific exception class you’re expecting (like CalloutException, DmlException, etc.).
3. Enforce security with CRUD & FLS
Enforce security with CRUD & FLS Always check field-level (FLS) and object-level permissions before accessing or modifying data. Use WITH SECURITY_ENFORCED in SOQL queries or Security.stripInaccessible() for DML operations.
4. Structure your code with layers and trigger frameworks
Avoid embedding logic directly inside triggers. Use a layered architecture: Trigger → Handler → Service → Utility. Employ frameworks like Kevin O’Hara’s to manage context (beforeInsert, afterUpdate, etc.) and keep triggers lightweight and testable.
5. Document every class and method
Use ApexDoc to annotate purpose, parameters, and return values. Include headers with author, version, and change log to support long-term maintenance.
6. Use asynchronous processing when necessary
When your logic performs heavy operations, long loops, or integrations, offload it using Queueable, Batchable, or @future. This keeps your code efficient and reliable.
7. Write robust, isolated tests
Cover positive, negative, edge, and bulk scenarios. Use @testSetup, Test.startTest(), Test.stopTest(), and advanced assertions. Avoid seeAllData=true.
8. Decide declarative vs programmatic wisely
Before writing Apex, consider: can this be done with a validation rule, flow, or formula? Apex is for complex logic, large data volumes, or cases where declarative tools fall short. Choose code only when necessary.
9. Optimize data access and logic reuse
Leverage Maps, Sets, and reusable utility classes (e.g. Utils.getMapById()) instead of re-querying inside loops. Avoid unnecessary heap usage and duplicate logic.
10. Follow consistent naming conventions
Names reflect your system’s clarity. Use PascalCase for classes, camelCase for variables and methods. Avoid abbreviations unless obvious. Write field names that are self-explanatory before the platform adds suffixes like __c.
Examples:
Class: InvoiceProcessor
Method: calculateTaxAmount
Custom field: SyncEnabled
Custom metadata: DeployConfiguration
Content

