35 Advanced Salesforce Developer Scenarios
Post 2: Apex Patterns, Trigger Choreography, Integration, Security & Testing
What's Post 2: Deep-dive into production-grade Salesforce architecture. We've covered debugging basics (Post 1). Now let's tackle: How do you design Apex for performance and testability? How do you choreograph multi-trigger interactions without creating chaos? How do you build integrations that don't lose data? How do you lock down security without breaking user workflows? How do you deploy without breaking prod?
35 Questions in 5 Advanced Categories:
• 💎 Advanced Apex & Design Patterns (Q36–Q42)
• 🎭 Multi-Trigger Choreography & Order of Execution (Q43–Q49)
• 🔗 Complex Integrations & Webhook Patterns (Q50–Q56)
• 🔐 Security & Permission Edge Cases (Q57–Q63)
• 🚀 Testing, Code Quality & Deployment (Q64–Q70)
Pair with these free resources: Apex 120+ Q&A • SOQL 81+ Q&A • LWC Zero to Hero • Practice Zone (27 Quizzes)
Advanced Apex & Design Patterns
7 QuestionsStatic Inner Classes vs. Sharing Mode — When Does Sharing Bypass Matter?
Salesforce enforces Org-Wide Defaults and sharing rules at the SOQL level. A with sharing class can only query records the running user owns or has access to. A without sharing class bypasses all sharing logic (admin power). Inner classes inherit the outer class's mode, so if you're not careful, a utility inner class could accidentally bypass sharing and expose data.
This matters in multi-tenant orgs where users shouldn't see each other's records, or in communities where guests have restricted access.
- Inner classes inherit outer class's sharing mode (with/without).
- without sharing bypasses Org-Wide Defaults and sharing rules — use sparingly.
- When calling a without sharing utility, document why and audit access.
- Best practice: keep utility classes small, explicitly declare sharing mode, test with different user profiles.
XYZ Company: Built an OrderUtil inner class to calculate discounts. Outer OrderService class was without sharing (for admin batch processing). OrderUtil inherited without sharing, so it could query all orders. A community user called OrderService, expecting to see only their orders — instead they saw all company orders. Security breach.
Fix: Made OrderService with sharing (default), moved admin utilities to a separate AdminOrderUtil class explicitly marked without sharing with code comments explaining why.
Builder Pattern for Complex Object Creation — When Is It Overkill?
- Use Builder for 3+ optional constructor params (Account, Order, Opportunity).
- Overkill for simple utility classes or DTOs with 1-2 fields.
- Builder adds ~50 lines of boilerplate; worth it for complex objects.
- Fluent API (method chaining) improves readability in test setup.
Static Caching in Apex — Cache Strategy for Frequently Queried Data?
- Static caching = SOQL reduction. Query once, reuse for lifetime of transaction.
- Best for: RecordTypes, Profiles, custom metadata, lookup reference data.
- Cache invalidation: on trigger (RecordType updated), batch job completion, scheduled refresh.
- Monitor: Log cache hits/misses to tune strategy.
Mock vs. Stub in Unit Tests — When Do You Use Each?
- Mock = verify behavior (was method called with right params?).
- Stub = provide fake data (return test values for calculations).
- Use mocks for external callouts (HTTP, APIs). Use stubs for data layer.
Governor Limits in Different Contexts — Trigger vs. Batch vs. Queueable?
- Trigger: Shares DML/SOQL limits with calling code. Update 100 records via UI = 100 SOQL/DML available for trigger. If trigger uses 50 SOQL, only 50 left for batch/process.
- Batch: Each batch execution has independent 10k SOQL, 10k DML, 12MB heap. No sharing with other batches or triggers.
- Queueable: Same as batch, but chainable (up to 5 times). Each chain restarts the 10k/10k/12MB limits.
- Heap Limit: 12MB for triggers, batch, Queueable. Static variables accumulate; memory leaks can cause failure at 11MB.
XYZ Company: Batch job updated 100k orders, calling trigger 100k times (one trigger per order). Trigger tried to query Accounts (10k SOQL) to update parent totals. Batch had used 8k SOQL already, only 2k left. Trigger failed on record 20k: "SOQL limit exceeded."
Fix: Moved Account update logic to a separate Queueable enqueued from trigger finish(). Queueable has independent 10k SOQL limit, no conflict with batch limits.
Dependency Injection in Apex — When and How?
- DI = pass dependencies to constructor, don't hardcode them.
- Makes classes testable (can inject mocks) and reusable.
- Use for callout services, data access layers, integrations.
- Overkill for simple utility classes.
Apex Enum vs. String Constants for Status Values?
- Enums = type-safe, compile-time checked, no typo risk.
- String constants = queryable, matchable with field picklists.
- Use enums for internal state logic, string constants for Salesforce field values.
Multi-Trigger Choreography & Order of Execution
7 QuestionsOrder of Execution Across Before/After Triggers on Multiple Objects
- Before: validate, modify data before save. After: query relationships, update children.
- After-trigger updates don't re-fire the same after-trigger (no recursion on same object).
- Parent before → After → Child before → After (depth-first order).
- Document execution order in code comments; it's fragile.
Platform Events vs. Publish-Subscribe Pattern for Decoupled Triggers
- Platform Events decouple triggers (loose coupling, easy testing).
- ~1-10s latency (not real-time). Use for async workflows.
- New subscribers don't require trigger changes (extensible).
- Direct trigger calls are faster but create tight coupling.
Trigger Updates Parent, Parent Update Fires Trigger Again — No Recursion Guard?
- Salesforce prevents same after-trigger from re-firing (auto recursion prevention).
- But two-way updates (A→B→A) create loops not prevented automatically.
- Use Set<Id> guards on both triggers to track processed records.
Test Apex Order of Execution — Full Cascade of Before/After Fires?
- @isTest executes in same order as production.
- Test.startTest() starts fresh governor limits (for async testing).
- Assert at each stage: after before-trigger (data modified?), after after-trigger (children updated?).
Process Builder / Flow Trigger Timing — Sync or Async?
- Process Builder / Flows fire after all triggers (sync, not async).
- If Flow creates records, those records' triggers run before Flow completes.
- For true async, use Platform Events or Queueable from trigger.
Bulkification — Single Loop vs. Batch Processing Pattern
- Bulkify: query all IDs at once, loop once, update once.
- Reduces SOQL count (1 instead of 100), DML calls, lock contention.
- Use Map<Id, sObject> for O(1) lookups in loop.
Trigger Calls Batch Job — Counts Against Apex Jobs Limit?
- Trigger can enqueue batch. Counts toward 50k batch jobs / 24hr limit.
- Bulk insert 1k → 1k batch enqueues (OK, well under 50k).
- Monitor: track batch enqueues per day; if approaching 50k, defer batch to scheduled job.
Complex Integrations & Webhook Patterns
7 QuestionsWebhook Idempotency — Duplicate Event Processing & De-duplication
- Idempotency key = unique ID per event (from webhook sender).
- Check if key exists before processing (skip duplicates).
- Return 200 for both first and duplicate deliveries (idempotent API).
- Log all events in queue table for audit and debugging.
Dead Letter Queue (DLQ) Pattern for Failed Webhook Events
- DLQ = permanent storage for failed events (audit trail).
- After max retries, move to Failed status (don't infinitely retry).
- Admin manually reviews DLQ, decides to retry or discard.
- Prevents data loss; every event is tracked.
Long-Running Integration — Polling vs. Streaming vs. Webhooks
- Polling: simple, high latency (1-15 min), limits external API calls.
- Streaming: real-time, connection overhead, risk of drops.
- Webhooks: real-time, requires public URL, idempotency needed.
- Hybrid: webhook primary, poll as fallback for missed events.
Transactional Integrity Across Salesforce & External System
- Salesforce DML commits immediately, no true 2-phase commit.
- Pattern: create in Salesforce (Pending), call API async, update status (Synced/Failed).
- If API fails, log error, retry via scheduled job or manual intervention.
- Accept eventual consistency; data may be temporarily out-of-sync.
REST API Versioning — Breaking Changes & Backward Compatibility
- Version in URL (/api/v1). Makes breaking changes safe.
- Add fields, don't remove. Old consumers skip unknown fields.
- Deprecation window: support old version for 6+ months.
Rate Limiting Integration — Backoff Strategy & Throttling
- 429 = rate limited. Extract Retry-After header.
- Exponential backoff (2s, 4s, 8s) prevents overwhelming API.
- Queueable queue = serialized callouts (natural rate limiting).
- Monitor usage, alert before hitting limits.
Webhook Signature Verification — Prevent Unauthorized Calls
- Signature verification = prevent spoofed webhooks.
- External system signs payload with shared secret.
- Salesforce verifies before processing (reject if invalid).
- HMAC-SHA256 is standard; Crypto.generateMac() in Apex.
Security & Permission Edge Cases
7 QuestionsGuest User Sees Records via SOQL — Field-Level Security Bypassed?
- SOQL respects sharing rules AND FLS. Guest can see record but not sensitive fields.
- Hidden fields return NULL, no error thrown (silent failure risk).
- Code must check FLS before using field values (Schema.SObjectField.isAccessible()).
- Test with actual guest user profile to catch FLS issues.
XYZ Company: Guest user queried Orders and salary was returned (should be hidden). Root cause: SOQL didn't check FLS for Salary field. Guest saw NULL silently; developer assumed NULL meant "no value" instead of "no access." Fixed by checking SObjectField.isAccessible() before returning field.
Admin User Runs Code WITH SHARING — Still Bypass Records?
- with sharing enforces OWD and sharing rules for ALL users, including admins.
- Admin override (Setup > Sharing Settings) is different from code-level override.
- Code can't bypass admin override settings.
Org-Wide Defaults Conflict with Sharing Rules — Which Wins?
- OWD = default access level (baseline).
- Sharing rules = exceptions (grant more access, can't deny).
- If OWD = Private, sharing rule can grant Read. If OWD = Read-Write, sharing rule can't restrict.
RLS (Record-Level Security) on Lookup Field — Can User See Related Record?
- Lookup fields inherit parent's sharing. If parent is hidden, lookup value is hidden.
- Relationship queries (SELECT Account.Name FROM Order) respect parent's RLS.
SOQL Executed as User vs. SYSTEM Context — Sharing Difference?
- Execution context = current user's sharing is enforced in SOQL.
- @isTest(SeeAllData=true) bypasses security (testing only).
- Community user REST API = executes as that user, respects their access.
Custom Permission Bypass Sharing Rules?
- Custom permissions = feature flags, not data access control.
- Custom permission + sharing rule = user sees data AND feature available.
- To bypass sharing, use WITHOUT SHARING class (intentional, documented).
Trigger Updates Record as Different User — Sharing Respected?
- Trigger executes as triggering user, can't override.
- WITH SHARING respects that user's sharing rules.
- To query beyond user's access, move to WITHOUT SHARING class (intentional bypass).
Testing, Code Quality & Deployment
7 QuestionsCode Coverage 75% but Production Bug — What Missed?
- Code coverage % = lines executed, not logic quality.
- Test happy paths + error paths (exceptions, governor limits).
- Test boundary conditions (empty lists, null values, gov limit edge cases).
- Coverage != correctness. 75% coverage can still have production bugs.
Test Data Setup — Should Use Actual Records or Minimal Test Data?
- Minimal test data = faster tests, clearer intent.
- @TestSetup for shared data across test methods.
- Mock external dependencies (HTTP, APIs) — don't call real APIs in tests.
- Avoid prod data copy; use @isTest(SeeAllData=false) by default.
Performance Testing in CI/CD — How to Catch Performance Regressions?
- Assert SOQL/DML counts (Limits.getSOQLStatements()) in tests.
- Benchmark critical flows (batch, report, API endpoint).
- Track deployment performance: if code change increases query count, reject deploy.
- Load test with production-scale data in sandbox.
Feature Flags in Apex — Gradual Rollout Without Code Deploy?
- Store feature flags in custom metadata (config) or custom settings (data).
- Check at runtime: if (flag.IsEnabled__c) { ... }.
- Deploy with flag OFF. Enable in prod without redeploy.
- Allows gradual rollout, A/B testing, instant disable on bug.
Deployment Validation Errors — How to Debug Deployment Issues?
- Validate deploy in full sandbox first (catches 90% of issues).
- Code coverage must be 75%+ (org-wide). Single class can be 0% if other classes cover 75%+.
- Check field references, test failures, managed package conflicts.
- Deploy errors are verbose; read message + line number carefully.
Rollback Strategy — What If Production Deploy Breaks Production?
- No native Salesforce rollback. Rollback = redeploy previous code.
- Instant mitigation: disable feature flag (code still deployed, logic off).
- Data restore: Recycle Bin (15 days), backup service (3rd party).
- Log all changes for audit trail (error tracking, data quality).
Deployment Frequency — Weekly vs. Daily Small Releases?
- Daily small deploys < monthly big deploys (lower risk, faster feedback).
- Trunk-based: merge to main when ready, deploy daily.
- Feature flags allow code to be deployed but logic OFF until ready.
- Rollback = disable flag (instant), not redeploy (slow).
📚 Deepen Your Salesforce Mastery
Post 2 covers advanced patterns for 6+ year developers. Continue learning with our free resources:
70 Questions Down. 35 More Coming.
Post 3 (Q71-Q105): DevOps disasters, deployment strategies, architecture trade-offs, high-scale system design, real war stories
All 105 questions free. No paywalls. Production-level interview prep for senior Salesforce developers.
Practice with real people
Join the free Mock Interview Community — practice with peers, get honest feedback, and walk into your real interview confident.
Join the Community ↗