Salesforce Apex is two products: the Apex that passes the certification exam, and the Apex that survives 3 years in production. The exam tests syntax and platform concepts. Production tests architecture, discipline, and the patterns that hold up when the org grows from 50K records to 5M and the team changes hands twice.
This guide is the production reference Sapota's Salesforce team uses on every engagement. Each phase below links to a deeper post on the specific topic. Read the pillar to get the shape; read the deep posts to get the patterns.
Phase 1: Trigger architecture
The first piece of every Salesforce implementation is the trigger layer. Get this right and the rest of the architecture follows. Get this wrong and every later piece is fighting the foundation.
The pattern: one trigger per object, calling a handler class, with a static recursion guard, dispatching to event-specific methods. See Apex trigger anti-patterns and the one-trigger-per-object pattern.
Phase 2: Bulkification and governor limits
Every Apex method must work for 1 record and for 200 records. The single most common production incident category is governor limits hit by code that worked in tests but not at scale.
The discipline:
- Bulkify every method that processes record collections. See Apex bulkification: why code works in tests but fails in production.
- Eliminate SOQL inside loops. See SOQL inside loops: the single most common governor limit cause.
- Test with 200 records, not 1.
Phase 3: SOQL selectivity for large objects
As data accumulates, queries that ran fine at 100K records hit full-table-scan limits at 5M records. The query plan changes; the code does not. Production starts timing out without any code change.
The fix is selectivity discipline: filter on indexed fields, use External IDs, configure custom indexes, use date bounds on bulk processing. See SOQL selectivity: avoiding full table scans on million-row objects.
Phase 4: Async patterns
Work that exceeds synchronous limits or that should not block the user transaction belongs in async context. Salesforce offers four patterns: Future, Queueable, Batch, Scheduled. Each has a specific shape.
Selection guide:
- New work: default to Queueable. See Async Apex selection: Queueable vs Batch vs Future vs Scheduled.
- Multi-stage workflows: Queueable chaining. See Apex Queueable chaining: state across async invocations.
- High-volume operations: Batch Apex.
- Time-driven jobs: Scheduled, often kicking off a Batch.
Phase 5: External integration
Salesforce as one node in a real enterprise stack. Apex calls external systems for payments, identity, billing, analytics. The reliability of these calls determines whether the integration survives a bad afternoon at the external system.
The patterns:
- Explicit timeouts on every callout.
- Retry logic on transient failures.
- Idempotency keys on non-idempotent endpoints.
See Apex callouts to external systems: timeouts, retries, idempotency.
Phase 6: Security enforcement
Apex bypasses sharing, CRUD, and FLS by default in many contexts. Three layers need explicit enforcement:
- Sharing modes:
with sharing,without sharing,inherited sharing. See Apex sharing modes: with sharing, without sharing, inherited sharing. - CRUD and FLS: WITH USER_MODE, WITH SECURITY_ENFORCED,
Security.stripInaccessible. See Apex CRUD and FLS: SECURITY_ENFORCED vs stripInaccessible.
For AppExchange-bound code, Salesforce Security Review requires all three layers in place.
Phase 7: DML and error handling
Bulk operations can succeed entirely, fail entirely, or partially succeed. Each is the right answer for some business case. Apex offers three patterns:
- Simple DML keyword: all-or-nothing.
Database.insert(records, false): partial success, inspect SaveResult.- Savepoints and rollback: multi-DML atomic operations.
See DML partial success in Apex: Database.SaveResult and savepoints.
Phase 8: Schema design
Data model choices made in week one affect every later workflow. The most consequential decision: relationship types between custom objects.
The criteria:
- Master-detail when the child cannot exist without the parent, cascade is desired, or rollup summaries are needed.
- Lookup when the child has independent existence.
- Junction objects for many-to-many.
See Master-detail vs lookup: Salesforce relationship decision criteria.
Phase 9: Testing discipline
The 75 percent code coverage threshold is the floor, not the goal. Tests that meet coverage without meaningful assertions provide zero confidence.
The patterns:
- Test data factories that handle schema changes once. See Apex test data factories: patterns that prevent flaky tests.
- 200-record bulk tests for every trigger handler.
- HttpCalloutMock infrastructure that covers success and failure. See HttpCalloutMock: testing Apex callouts without hitting real services.
- Meaningful assertions, not empty ones. See The 75 percent Apex coverage myth: lines covered, logic untested.
Phase 10: Frontend transition
For new component work, LWC is the platform direction. Aura is in Maintain mode, kept running but not improved.
For Apex-heavy developers learning LWC, the curve is shorter than expected. The wire pattern handles most data fetching, Lightning Data Service handles standard CRUD, and the framework is standard-web-components-plus-some-Salesforce-conventions.
See LWC basics for the Apex-heavy developer: leaving Aura behind.
Phase 11: Code review
A 10-minute checklist on every PR catches 80 percent of bugs that would otherwise reach production. The remaining 20 percent need an architect's review.
The checklist covers: governor limits, bulkification, sharing, CRUD/FLS, trigger architecture, error handling, test quality, code quality, integration patterns, and schema changes. See Apex code review checklist: what to flag on every Salesforce PR.
Static analysis (Salesforce Code Analyzer, PMD) catches the mechanical items automatically in CI. Human review focuses on the judgment items.
Practices that span every phase
A few habits that apply across the whole stack:
- Explicit over implicit. Every sharing keyword, every allOrNone choice, every timeout, every retry policy is declared in code. Future maintainers see the intent.
- Test the failure path. Happy path tests are necessary but not sufficient. The bugs are in the failure paths.
- Document the why, not the what. Code shows what. Comments document why a specific choice was made over the alternatives.
- Refactor opportunistically. A clean codebase emerges from many small improvements, not big rewrites. Every PR is an opportunity to leave the touched code slightly better.
- Measure what you ship. Apex log inspection, governor limit dashboards, error rate monitoring. Code that runs in production needs visibility, not just deployment.
Where Sapota fits
Sapota's Salesforce team runs Apex implementations from greenfield design through long-term maintenance. We hold the Platform Developer I credential and have shipped production Apex for mid-market SaaS, enterprise telco, and B2B subscription commerce engagements.
The engagement model is engineering-heavy. We pair with internal teams or run as a delivery team. We write the trigger architecture, refactor governor limit incidents, set up the testing infrastructure, and stay engaged through the first quarter post-launch.
For programs with internal teams that need targeted help, we run scoped engagements: trigger architecture refactors, governor limit audits, security reviews, test infrastructure rebuilds, Aura-to-LWC migrations, and CI/CD setup for Salesforce DX.
Implementing Apex on Salesforce or refactoring an inherited org? Sapota's Salesforce team handles every phase covered in this guide on production engagements. Get in touch ->
See our full platform services for the stack we cover.





