Application Architect Interview Questions
25 expert-curated Application Architect interview questions covering sharing architecture, large data volumes, governor limits, packaging strategies, and platform design decisions.
Application Architect Interview Questions Content
Lookup Relationship: Loosely coupled. The lookup field is optional; deleting the parent does not cascade-delete children (options: clear field, restrict delete, or cascade delete — configurable). Children have their own OWD and sharing settings. Does not support Roll-Up Summary (RUS) fields. A record can have up to 25 lookup relationships.
Master-Detail Relationship: Tightly coupled. The parent controls sharing and security of the detail. Deleting the master cascades deletes all detail records. Supports Roll-Up Summary fields (COUNT, SUM, MIN, MAX) on the master. The master field is required. Up to 2 master-detail relationships per object.
Many-to-Many (Junction Object): Implemented via a custom junction object with two master-detail relationships to each of the related objects. Enables querying records on either side of the relationship.
Self-Relationship: A lookup on an object to itself (e.g., Account.ParentId). Used for hierarchies.
Hierarchical Field: A special lookup available only on the User object, allowing users to reference other users above them in a hierarchy (e.g., Manager field).
Master-Detail Relationship: Tightly coupled. The parent controls sharing and security of the detail. Deleting the master cascades deletes all detail records. Supports Roll-Up Summary fields (COUNT, SUM, MIN, MAX) on the master. The master field is required. Up to 2 master-detail relationships per object.
Many-to-Many (Junction Object): Implemented via a custom junction object with two master-detail relationships to each of the related objects. Enables querying records on either side of the relationship.
Self-Relationship: A lookup on an object to itself (e.g., Account.ParentId). Used for hierarchies.
Hierarchical Field: A special lookup available only on the User object, allowing users to reference other users above them in a hierarchy (e.g., Manager field).
OWD (Organisation-Wide Defaults): Set the baseline access for all records of an object. Options: Private (only owner and those above in hierarchy), Public Read Only, Public Read/Write, Controlled by Parent. Stricter OWD = more sharing rules required but better security. OWD setting on high-volume objects (like Activities) has significant performance implications.
Role Hierarchy: Users higher in the hierarchy implicitly gain access to records owned by users below them (if "Grant Access Using Hierarchies" is enabled for the object). Does not apply to custom objects where the checkbox is disabled.
Sharing Rules (limit: 300 per object): Open up access beyond OWD for specific groups or criteria. Types: ownership-based (share records owned by Group A with Group B) and criteria-based (share records matching field criteria).
Apex Managed Sharing: Programmatic sharing using the Share object (e.g.,
Role Hierarchy: Users higher in the hierarchy implicitly gain access to records owned by users below them (if "Grant Access Using Hierarchies" is enabled for the object). Does not apply to custom objects where the checkbox is disabled.
Sharing Rules (limit: 300 per object): Open up access beyond OWD for specific groups or criteria. Types: ownership-based (share records owned by Group A with Group B) and criteria-based (share records matching field criteria).
Apex Managed Sharing: Programmatic sharing using the Share object (e.g.,
AccountShare). Key fields: UserOrGroupId, AccessLevel (Read/Edit), RowCause (must be a custom Share Reason or the Manual value). All Apex Managed Sharing uses a custom RowCause to distinguish it from manual sharing. When the Share Reason is deleted, all associated sharing records are removed automatically.
When Salesforce evaluates whether a user can access a record, it follows this sequence:
1. System Access: System administrators and users with "View All Data" / "Modify All Data" permissions bypass all record-level access controls.
2. OWD: If Public Read/Write, all users have access. If Private, only the owner and higher role users can access by default.
3. Role Hierarchy: Users above the record owner in the hierarchy gain the access level defined by OWD (if "Grant Access Using Hierarchies" is enabled).
4. Sharing Rules: Criteria-based or ownership-based rules extend access to additional users/groups beyond what OWD and hierarchy provide.
5. Manual Sharing: Record owners or admins can share individual records with specific users or groups.
6. Apex Managed Sharing: Programmatic sharing logic via Share objects.
Important: Sharing can only expand access beyond OWD — it cannot restrict it below OWD. Object-level permissions (Profile/Permission Set) are evaluated first; even with record access, a user without the object's Read permission cannot see any records.
1. System Access: System administrators and users with "View All Data" / "Modify All Data" permissions bypass all record-level access controls.
2. OWD: If Public Read/Write, all users have access. If Private, only the owner and higher role users can access by default.
3. Role Hierarchy: Users above the record owner in the hierarchy gain the access level defined by OWD (if "Grant Access Using Hierarchies" is enabled).
4. Sharing Rules: Criteria-based or ownership-based rules extend access to additional users/groups beyond what OWD and hierarchy provide.
5. Manual Sharing: Record owners or admins can share individual records with specific users or groups.
6. Apex Managed Sharing: Programmatic sharing logic via Share objects.
Important: Sharing can only expand access beyond OWD — it cannot restrict it below OWD. Object-level permissions (Profile/Permission Set) are evaluated first; even with record access, a user without the object's Read permission cannot see any records.
Data skew occurs when a single record is the parent of an unusually large number of child records, causing performance and locking issues.
Account Ownership Skew (>10K records owned by one user): Occurs when a single user owns tens of thousands of Account records. When sharing recalculation runs for that user (e.g., role change), the system must process all their records — causing timeouts. Fix: Distribute ownership using a queue or multiple users as owners. Use Groups/Queues as owners for high-volume accounts.
Account Data Skew: A single Account has an extremely large number of related records (e.g., 50,000 Contacts). DML on the Account can cause record lock contention as child records lock the parent. Fix: Archive old records, use external objects for historical data, or restructure the data model.
Chatter Skew: A Chatter group or user has extremely high follow counts or feed items, degrading Chatter feed performance. Fix: Clean up old follows, archive inactive groups, limit automated Chatter posts.
Account Ownership Skew (>10K records owned by one user): Occurs when a single user owns tens of thousands of Account records. When sharing recalculation runs for that user (e.g., role change), the system must process all their records — causing timeouts. Fix: Distribute ownership using a queue or multiple users as owners. Use Groups/Queues as owners for high-volume accounts.
Account Data Skew: A single Account has an extremely large number of related records (e.g., 50,000 Contacts). DML on the Account can cause record lock contention as child records lock the parent. Fix: Archive old records, use external objects for historical data, or restructure the data model.
Chatter Skew: A Chatter group or user has extremely high follow counts or feed items, degrading Chatter feed performance. Fix: Clean up old follows, archive inactive groups, limit automated Chatter posts.
Selective Queries: A SOQL query is selective when it filters on an indexed field and the estimated result set is below a threshold (approximately 10% of total records or 333K records). Non-selective queries trigger a full table scan and can time out on large objects. Always filter on CreatedDate, Id, or other indexed fields first.
Indexes:
- Standard indexes: Automatically created on Id, Name, OwnerId, CreatedDate, SystemModstamp, RecordTypeId, and Master-Detail/Lookup fields.
- Custom indexes: Requested via Salesforce Support on specific fields. Do not index fields with low cardinality (checkbox, picklist with 2 values) — selectivity is key.
- Unique indexes: Enforce uniqueness at the database level and are indexed.
Skinny Tables: A Salesforce-managed internal table containing a subset of frequently queried fields from a large object. Queries against skinny table fields are faster because fewer columns are scanned. Available for custom and some standard objects. Must be requested via Salesforce Support. Skinny tables are synchronised automatically; no additional code is needed once created.
Query Plan Tool: Available in the Developer Console. Reveals whether a query will use an index or full table scan, and estimates query cost.
Indexes:
- Standard indexes: Automatically created on Id, Name, OwnerId, CreatedDate, SystemModstamp, RecordTypeId, and Master-Detail/Lookup fields.
- Custom indexes: Requested via Salesforce Support on specific fields. Do not index fields with low cardinality (checkbox, picklist with 2 values) — selectivity is key.
- Unique indexes: Enforce uniqueness at the database level and are indexed.
Skinny Tables: A Salesforce-managed internal table containing a subset of frequently queried fields from a large object. Queries against skinny table fields are faster because fewer columns are scanned. Available for custom and some standard objects. Must be requested via Salesforce Support. Skinny tables are synchronised automatically; no additional code is needed once created.
Query Plan Tool: Available in the Developer Console. Reveals whether a query will use an index or full table scan, and estimates query cost.
Formula fields are calculated at query time. Key best practices:
Cross-object formulas: Can traverse up to 5 levels of relationships (e.g.,
Null handling: Use
Recursive formula danger: Formula fields cannot directly reference themselves, but complex circular references between related objects can occur with workflow/trigger loops. For example, Object A's formula depends on Object B's formula, which triggers a workflow on A. Always map dependencies before adding cross-object references.
Performance: Formula fields are not stored on the record — recalculated on every read. For very large datasets, replace complex formulas with stored fields updated by triggers or flows to improve query performance.
Cross-object formulas: Can traverse up to 5 levels of relationships (e.g.,
Account.Owner.Manager.Name). Limit: 10 unique relationships per formula field, 5 across all formula fields per object for certain traversals. Avoid on high-volume objects where the traversal causes performance overhead.Null handling: Use
BLANKVALUE() instead of ISNULL() for text fields (ISNULL treats empty string as non-null). Use NULLVALUE() for numbers. Always account for null parent records in cross-object formulas to prevent formula returning null.Recursive formula danger: Formula fields cannot directly reference themselves, but complex circular references between related objects can occur with workflow/trigger loops. For example, Object A's formula depends on Object B's formula, which triggers a workflow on A. Always map dependencies before adding cross-object references.
Performance: Formula fields are not stored on the record — recalculated on every read. For very large datasets, replace complex formulas with stored fields updated by triggers or flows to improve query performance.
Non-selective queries scan the full table. Triggers include: filtering on non-indexed fields, using
Optimisation strategies:
1. Filter on indexed fields first: Id, CreatedDate, OwnerId, Master-Detail fields, custom indexed fields.
2. Avoid leading wildcards:
3. Use LIMIT: Always add a LIMIT clause to test queries and production queries that don't need all records.
4. Avoid SELECT *: Query only the fields needed. Reduces data transfer and heap usage.
5. Query Plan Tool: Check "Cost" in Developer Console — cost > 1 indicates a potentially non-selective query.
6. Avoid cross-object SOQL in loops: Use relationship queries (SOQL with nested sub-queries) to retrieve parent/child data in one query.
7. Semi-joins and anti-joins: Use
LIKE '%value%' (leading wildcard prevents index use), using OR across non-indexed fields, or the estimated result set exceeds selectivity thresholds.Optimisation strategies:
1. Filter on indexed fields first: Id, CreatedDate, OwnerId, Master-Detail fields, custom indexed fields.
2. Avoid leading wildcards:
Name LIKE '%Corp' forces a full scan. Use Name LIKE 'Corp%' instead.3. Use LIMIT: Always add a LIMIT clause to test queries and production queries that don't need all records.
4. Avoid SELECT *: Query only the fields needed. Reduces data transfer and heap usage.
5. Query Plan Tool: Check "Cost" in Developer Console — cost > 1 indicates a potentially non-selective query.
6. Avoid cross-object SOQL in loops: Use relationship queries (SOQL with nested sub-queries) to retrieve parent/child data in one query.
7. Semi-joins and anti-joins: Use
WHERE Id IN (SELECT ...) to reduce round trips.
When a record is saved, Salesforce executes declarative and programmatic automation in this order:
1. System validation (required fields, field formats, max lengths)
2. Before Triggers (Apex)
3. Custom validation rules
4. Duplicate rules
5. Record written to database (not yet committed)
6. After Triggers (Apex)
7. Assignment rules (Leads/Cases)
8. Auto-response rules
9. Workflow rules (field updates re-fire triggers; email alerts, tasks, outbound messages do not re-fire triggers)
10. Processes (Process Builder — being retired)
11. Escalation rules
12. Roll-Up Summary fields recalculated on parent
13. Criteria-based sharing rules evaluated
14. Record-Triggered Flows (Before-Save executes before step 2; After-Save executes after step 6)
15. Commit to database
16. Post-commit: email sends, async jobs, Platform Events delivery
Note: Before-Save Flows execute between system validation and before triggers in recent releases — verify the exact position for the current API version.
1. System validation (required fields, field formats, max lengths)
2. Before Triggers (Apex)
3. Custom validation rules
4. Duplicate rules
5. Record written to database (not yet committed)
6. After Triggers (Apex)
7. Assignment rules (Leads/Cases)
8. Auto-response rules
9. Workflow rules (field updates re-fire triggers; email alerts, tasks, outbound messages do not re-fire triggers)
10. Processes (Process Builder — being retired)
11. Escalation rules
12. Roll-Up Summary fields recalculated on parent
13. Criteria-based sharing rules evaluated
14. Record-Triggered Flows (Before-Save executes before step 2; After-Save executes after step 6)
15. Commit to database
16. Post-commit: email sends, async jobs, Platform Events delivery
Note: Before-Save Flows execute between system validation and before triggers in recent releases — verify the exact position for the current API version.
Record-Triggered Flows: Fire when a record is created, updated, or deleted. Use for automation that must happen on record save without user interaction (field updates, related record creation, notifications). Before-save flows are most efficient for field updates as no additional DML is needed. After-save flows support more actions including subflows and Apex actions. Ensure flows are bulkified — avoid SOQL/DML inside loops using the Get/Update elements outside the loop.
Screen Flows: Require user interaction (data collection, guided processes, wizard-style UIs). Launch from Quick Actions, Lightning Pages, or Experience Cloud. Best for replacing custom VF pages with no-code solutions.
Schedule-Triggered Flows: Run on a scheduled basis across a batch of records. Replace Scheduled Apex for simple batch updates.
Platform Event-Triggered Flows: Subscribe to Platform Events and execute automation when events are published. Ideal for event-driven integrations and decoupled processing. Runs asynchronously. Support Resume elements for waiting on conditions.
Bulkification in Flows: Record-triggered flows process records in bulk. Use collection variables and loop-safe patterns. Avoid
Screen Flows: Require user interaction (data collection, guided processes, wizard-style UIs). Launch from Quick Actions, Lightning Pages, or Experience Cloud. Best for replacing custom VF pages with no-code solutions.
Schedule-Triggered Flows: Run on a scheduled basis across a batch of records. Replace Scheduled Apex for simple batch updates.
Platform Event-Triggered Flows: Subscribe to Platform Events and execute automation when events are published. Ideal for event-driven integrations and decoupled processing. Runs asynchronously. Support Resume elements for waiting on conditions.
Bulkification in Flows: Record-triggered flows process records in bulk. Use collection variables and loop-safe patterns. Avoid
Get Records inside loops by collecting IDs first.
Approval Processes route records through sequential or parallel approval steps.
Jump to Step: An approver with the "Modify All" permission or a specific role can skip earlier steps and send the record directly to a specific step in the process. Use sparingly — bypasses normal controls.
Recall: The submitter can recall (withdraw) a submitted record back to its pre-submitted state, as long as the record is still pending. Recall Actions (field updates, emails) fire when recalled. A recalled record must be re-submitted to enter the approval process again.
Delegation: An approver can delegate their approval authority to another user (Delegated Approver field on User). The delegate can approve on behalf of the original approver. Set a delegation period to handle leave/vacation scenarios.
Parallel Approvals: Multiple approvers in a single step can be required to approve simultaneously. Configure as "All approvers must approve" (consensus) or "First approver wins" (first response counts). Parallel approvals are useful for cross-functional reviews (Finance, Legal, Management) that happen concurrently.
Jump to Step: An approver with the "Modify All" permission or a specific role can skip earlier steps and send the record directly to a specific step in the process. Use sparingly — bypasses normal controls.
Recall: The submitter can recall (withdraw) a submitted record back to its pre-submitted state, as long as the record is still pending. Recall Actions (field updates, emails) fire when recalled. A recalled record must be re-submitted to enter the approval process again.
Delegation: An approver can delegate their approval authority to another user (Delegated Approver field on User). The delegate can approve on behalf of the original approver. Set a delegation period to handle leave/vacation scenarios.
Parallel Approvals: Multiple approvers in a single step can be required to approve simultaneously. Configure as "All approvers must approve" (consensus) or "First approver wins" (first response counts). Parallel approvals are useful for cross-functional reviews (Finance, Legal, Management) that happen concurrently.
Custom Metadata Types (CMT): Store configuration data as metadata — deployable via Metadata API, change sets, and packages. Records appear in package deployments like code. Accessible via SOQL in Apex. Cacheable — Salesforce caches CMT records in the application tier, reducing query overhead. Best for: integration endpoints, feature flags, validation rule configurations, threshold values that vary by environment.
Custom Settings: Store configuration data as custom objects — two types: List (multiple rows, queryable) and Hierarchy (per-org, per-profile, or per-user values). Accessible via
Key difference: CMT records deploy with the metadata; Custom Settings data does not. For configuration that varies between sandboxes and production (URLs, credentials, feature flags), CMT is strongly preferred.
Custom Settings: Store configuration data as custom objects — two types: List (multiple rows, queryable) and Hierarchy (per-org, per-profile, or per-user values). Accessible via
MySettings__c.getInstance() without SOQL in List type settings. Limitation: Custom Settings are not deployable as data via Metadata API (only the schema deploys; data must be manually re-entered or scripted). Note: Salesforce is encouraging migration from Hierarchy Custom Settings to Custom Metadata Types.Key difference: CMT records deploy with the metadata; Custom Settings data does not. For configuration that varies between sandboxes and production (URLs, credentials, feature flags), CMT is strongly preferred.
Key schema limits that impact application design:
- 800 custom objects per org (Enterprise/Unlimited). Managed package objects count against this limit. Plan object hierarchy carefully to avoid hitting this in large implementations.
- 800 custom fields per object (standard objects have varying limits). This includes formula fields, encrypted fields, and fields added by managed packages. Reaching this limit requires object redesign (related objects for additional fields) or data normalization.
- 25 relationship fields per object: Maximum number of lookup or master-detail fields. Includes relationships to the same or different objects.
- 2 master-detail relationships per object. A third can sometimes be achieved with a lookup that behaves like M-D, but RUS won't be supported.
- 10 Roll-Up Summary fields per object.
- Roll-Up Summary on Master-Detail only — not on Lookup relationships (third-party tools like Rollup Helper work around this).
- Formula field limits: 3,900 characters compiled, 1,300 characters (simple), max 5 unique cross-object relationships per formula, 10 unique relationships across all formula fields on an object.
Always review limits proactively at the design phase. Architectural debt from schema sprawl is hard to reverse.
- 800 custom objects per org (Enterprise/Unlimited). Managed package objects count against this limit. Plan object hierarchy carefully to avoid hitting this in large implementations.
- 800 custom fields per object (standard objects have varying limits). This includes formula fields, encrypted fields, and fields added by managed packages. Reaching this limit requires object redesign (related objects for additional fields) or data normalization.
- 25 relationship fields per object: Maximum number of lookup or master-detail fields. Includes relationships to the same or different objects.
- 2 master-detail relationships per object. A third can sometimes be achieved with a lookup that behaves like M-D, but RUS won't be supported.
- 10 Roll-Up Summary fields per object.
- Roll-Up Summary on Master-Detail only — not on Lookup relationships (third-party tools like Rollup Helper work around this).
- Formula field limits: 3,900 characters compiled, 1,300 characters (simple), max 5 unique cross-object relationships per formula, 10 unique relationships across all formula fields on an object.
Always review limits proactively at the design phase. Architectural debt from schema sprawl is hard to reverse.
A well-structured sandbox pipeline mirrors code promotion through environments before production deployment:
Developer Sandbox: Individual developer sandbox. Metadata-only copy, refreshed quickly (1–2 hours). Used for building and unit testing. One per developer on large teams.
Developer Pro Sandbox: Larger storage (1 GB vs 200 MB). Used for integration testing between developer sandboxes and for teams that need shared feature branches.
Partial Data Sandbox: Metadata + sample data (up to 5 GB from a defined data set). Used for QA and UAT where realistic data is needed. Refresh takes hours to 1 day.
Full Sandbox: Full copy of production (metadata + all data). Used for performance testing, final UAT, and staging. Refresh takes days. Most expensive — typically 1–2 per org.
Pipeline: Developer → Developer Pro → Partial Data (QA/UAT) → Full (Staging) → Production. Promote via change sets, Salesforce CLI (sf project deploy), or CI/CD tools (Gearset, Copado). Automate deployment with scratch orgs for feature-branch isolation in DX-based projects.
Developer Sandbox: Individual developer sandbox. Metadata-only copy, refreshed quickly (1–2 hours). Used for building and unit testing. One per developer on large teams.
Developer Pro Sandbox: Larger storage (1 GB vs 200 MB). Used for integration testing between developer sandboxes and for teams that need shared feature branches.
Partial Data Sandbox: Metadata + sample data (up to 5 GB from a defined data set). Used for QA and UAT where realistic data is needed. Refresh takes hours to 1 day.
Full Sandbox: Full copy of production (metadata + all data). Used for performance testing, final UAT, and staging. Refresh takes days. Most expensive — typically 1–2 per org.
Pipeline: Developer → Developer Pro → Partial Data (QA/UAT) → Full (Staging) → Production. Promote via change sets, Salesforce CLI (sf project deploy), or CI/CD tools (Gearset, Copado). Automate deployment with scratch orgs for feature-branch isolation in DX-based projects.
Change Sets: Simple UI-based deployment between connected orgs. No version control integration. Cannot delete metadata. Limited metadata type support. Best for small teams with simple deployment needs. Not suitable for CI/CD.
Unlocked Packages (Salesforce DX): Modular, versioned metadata containers. Deployed via Salesforce CLI. No namespace required (or can use one). Owned and modified by the subscriber org — source can be modified after installation. Version control integrated via SFDX project. Supports scratch orgs for isolated development. Best for enterprise teams needing modular, CI/CD-driven deployments.
Managed Packages: ISV/AppExchange packages with a namespace. Source code is locked — subscribers cannot modify the package's Apex code. Supports LMA (License Management App) for ISV licensing. Upgradeable via version releases. Deprecation of fields/objects is complex. Best for commercial products sold on AppExchange.
Architectural decision: For enterprise internal development: use Unlocked Packages for modular DX-based CI/CD. For AppExchange products: use Managed Packages. Change sets are acceptable only for small teams without CI/CD requirements.
Unlocked Packages (Salesforce DX): Modular, versioned metadata containers. Deployed via Salesforce CLI. No namespace required (or can use one). Owned and modified by the subscriber org — source can be modified after installation. Version control integrated via SFDX project. Supports scratch orgs for isolated development. Best for enterprise teams needing modular, CI/CD-driven deployments.
Managed Packages: ISV/AppExchange packages with a namespace. Source code is locked — subscribers cannot modify the package's Apex code. Supports LMA (License Management App) for ISV licensing. Upgradeable via version releases. Deprecation of fields/objects is complex. Best for commercial products sold on AppExchange.
Architectural decision: For enterprise internal development: use Unlocked Packages for modular DX-based CI/CD. For AppExchange products: use Managed Packages. Change sets are acceptable only for small teams without CI/CD requirements.
Trigger chain scenario: A trigger on Object A performs DML on Object B, which fires a trigger on Object B, which DMLs Object C, etc. All of these execute within the same transaction and share the same governor limits (100 SOQL queries, 150 DML statements, 12 MB heap). Deep trigger chains can rapidly exhaust limits.
Mixed-save context: When different object types are DML'd in the same transaction, limits are shared. This is common in triggers that update related objects.
Mitigation strategies:
1. Recursion prevention: Use a static Boolean or a static Set to prevent the same trigger from firing multiple times for the same records in one transaction.
2. Bulkify all DML and SOQL: Collect records into Lists/Maps; perform a single SOQL/DML outside loops.
3. Async offloading: Move non-critical operations to Queueable Apex or Platform Events to avoid hitting limits in the primary transaction.
4. Limit trigger chain depth: Design the data model to minimise cascading DML across many objects.
5. Monitor with Apex logs and Limit debug level: Use
Mixed-save context: When different object types are DML'd in the same transaction, limits are shared. This is common in triggers that update related objects.
Mitigation strategies:
1. Recursion prevention: Use a static Boolean or a static Set to prevent the same trigger from firing multiple times for the same records in one transaction.
2. Bulkify all DML and SOQL: Collect records into Lists/Maps; perform a single SOQL/DML outside loops.
3. Async offloading: Move non-critical operations to Queueable Apex or Platform Events to avoid hitting limits in the primary transaction.
4. Limit trigger chain depth: Design the data model to minimise cascading DML across many objects.
5. Monitor with Apex logs and Limit debug level: Use
Limits.getQueries() / Limits.getDMLStatements() in debug statements to catch near-limit scenarios in testing.
Salesforce conducts a Security Review for all AppExchange listings. Key areas:
Apex security: All SOQL must be secure against SOQL injection (use bind variables, not string concatenation). FLS enforcement — check field visibility before reading/writing. Use
XSS prevention: Visualforce pages must use
CSRF protection: Visualforce pages include CSRF tokens automatically. Custom REST APIs must validate session tokens.
Remote Site Settings / Named Credentials: All external callouts must be documented. Hardcoded credentials are an automatic failure.
Permission sets vs profiles: Package should install with minimal permissions; provide Permission Sets for least-privilege access.
Open redirect vulnerabilities: Do not redirect to user-supplied URLs without validation.
Tools: Salesforce Code Analyzer (PMD rules for Apex security), Checkmarx for SAST scanning. Perform security review early — not at the end of development.
Apex security: All SOQL must be secure against SOQL injection (use bind variables, not string concatenation). FLS enforcement — check field visibility before reading/writing. Use
WITH SECURITY_ENFORCED or Security.stripInaccessible(). Use with sharing by default.XSS prevention: Visualforce pages must use
{!HTMLENCODE()} for user-controlled data. LWC templates auto-escape but lwc:dom="manual" bypasses this — audit carefully.CSRF protection: Visualforce pages include CSRF tokens automatically. Custom REST APIs must validate session tokens.
Remote Site Settings / Named Credentials: All external callouts must be documented. Hardcoded credentials are an automatic failure.
Permission sets vs profiles: Package should install with minimal permissions; provide Permission Sets for least-privilege access.
Open redirect vulnerabilities: Do not redirect to user-supplied URLs without validation.
Tools: Salesforce Code Analyzer (PMD rules for Apex security), Checkmarx for SAST scanning. Perform security review early — not at the end of development.
Use Einstein features when:
- The use case aligns with pre-built Einstein capabilities (Lead Scoring, Opportunity Scoring, Activity Capture, Einstein Bots, Recommendation).
- The business wants minimal implementation time and maintenance overhead.
- Data volume meets Einstein's training requirements (typically 1,000+ labelled records).
- Transparency of model decisions is acceptable (Einstein provides limited explainability).
- The org has the required license (Sales Cloud Einstein, Service Cloud Einstein, etc.).
Use custom ML when:
- The use case is highly specific to the business (custom churn prediction, proprietary pricing model).
- Full control over features, model architecture, and explainability is needed.
- Data resides in external systems where Salesforce cannot train effectively.
- The organisation has data science expertise.
Hybrid approach: Build models externally (AWS SageMaker, Vertex AI) and expose them via a REST API called from Salesforce. Einstein Model Builder (part of Data Cloud) allows BYOM (Bring Your Own Model) and exposes external models as first-class Einstein features.
- The use case aligns with pre-built Einstein capabilities (Lead Scoring, Opportunity Scoring, Activity Capture, Einstein Bots, Recommendation).
- The business wants minimal implementation time and maintenance overhead.
- Data volume meets Einstein's training requirements (typically 1,000+ labelled records).
- Transparency of model decisions is acceptable (Einstein provides limited explainability).
- The org has the required license (Sales Cloud Einstein, Service Cloud Einstein, etc.).
Use custom ML when:
- The use case is highly specific to the business (custom churn prediction, proprietary pricing model).
- Full control over features, model architecture, and explainability is needed.
- Data resides in external systems where Salesforce cannot train effectively.
- The organisation has data science expertise.
Hybrid approach: Build models externally (AWS SageMaker, Vertex AI) and expose them via a REST API called from Salesforce. Einstein Model Builder (part of Data Cloud) allows BYOM (Bring Your Own Model) and exposes external models as first-class Einstein features.
Single-org advantages: Unified data model, no cross-org integration overhead, single source of truth, simpler reporting and analytics, shared configuration (profiles, workflows, flows). Best for organisations with relatively uniform processes.
Multi-org drivers:
- Data residency / compliance: Different regions (EU, US, APAC) may require data to reside in specific geographic locations (GDPR, data sovereignty).
- Business unit isolation: Separate acquisitions or subsidiaries with distinct processes, data models, and security requirements that would conflict in a shared org.
- Org size limits: Very large orgs approaching platform limits (800 objects, storage, API call volumes) may benefit from segmentation.
- Release management: Separate orgs allow independent release cycles.
Multi-org costs: Integration complexity, duplicate master data management, higher licensing overhead, separate user management, reporting across orgs requires external data warehouse.
Recommendation: Start with single-org. Introduce multi-org only when driven by genuine compliance, security, or scalability requirements — not organisational politics.
Multi-org drivers:
- Data residency / compliance: Different regions (EU, US, APAC) may require data to reside in specific geographic locations (GDPR, data sovereignty).
- Business unit isolation: Separate acquisitions or subsidiaries with distinct processes, data models, and security requirements that would conflict in a shared org.
- Org size limits: Very large orgs approaching platform limits (800 objects, storage, API call volumes) may benefit from segmentation.
- Release management: Separate orgs allow independent release cycles.
Multi-org costs: Integration complexity, duplicate master data management, higher licensing overhead, separate user management, reporting across orgs requires external data warehouse.
Recommendation: Start with single-org. Introduce multi-org only when driven by genuine compliance, security, or scalability requirements — not organisational politics.
Salesforce (Full CRM): The full Sales or Service Cloud license. Includes access to standard CRM objects (Leads, Opportunities, Cases, Campaigns, Forecasting), all standard reports and dashboards, and full automation capabilities.
Salesforce Platform: A user license for custom app development without the core CRM objects (no Leads, Opportunities, Forecasting, Campaigns). Includes Accounts, Contacts, Tasks, Events, and up to 10 custom objects. Suitable for internal workflow applications, HR portals, or operational tools that don't need CRM functionality. Lower cost than full Salesforce.
Lightning Platform (formerly Force.com): The most restricted license — access to custom objects only (no standard CRM objects at all, except read-only on some). Used for simple custom applications with minimal Salesforce standard object usage.
Architect consideration: Licence cost is a significant factor in solution design. For users who only need custom app functionality, Salesforce Platform or Lightning Platform licences reduce cost significantly. Always map user personas to the minimum required licence type during the design phase.
Salesforce Platform: A user license for custom app development without the core CRM objects (no Leads, Opportunities, Forecasting, Campaigns). Includes Accounts, Contacts, Tasks, Events, and up to 10 custom objects. Suitable for internal workflow applications, HR portals, or operational tools that don't need CRM functionality. Lower cost than full Salesforce.
Lightning Platform (formerly Force.com): The most restricted license — access to custom objects only (no standard CRM objects at all, except read-only on some). Used for simple custom applications with minimal Salesforce standard object usage.
Architect consideration: Licence cost is a significant factor in solution design. For users who only need custom app functionality, Salesforce Platform or Lightning Platform licences reduce cost significantly. Always map user personas to the minimum required licence type during the design phase.
ISVs selling managed packages on AppExchange use the License Management App (LMA) to manage subscriber licences:
How it works: The ISV installs the LMA in their Partner Business Org. When a subscriber installs the managed package, Salesforce creates a
- Licence status: Active, Trial, Expired, Free.
- Licence seats: Number of users allowed.
- Expiry date: For time-limited trials or subscriptions.
Licence enforcement in Apex: The package can call
Site licences: Some packages use site licences (all users in the org are licensed). The LMA manages this at the org level rather than per user.
ISV Harmony: Salesforce's programme linking LMA, Channel Order App, and Analytics for ISVs to manage the complete subscriber lifecycle.
How it works: The ISV installs the LMA in their Partner Business Org. When a subscriber installs the managed package, Salesforce creates a
Lead and License record in the ISV's LMA org. The licence record controls:- Licence status: Active, Trial, Expired, Free.
- Licence seats: Number of users allowed.
- Expiry date: For time-limited trials or subscriptions.
Licence enforcement in Apex: The package can call
PackageLicense.isEnabled() or check the UserPackageLicense object to verify a user has an active licence seat. Unlicensed users can be blocked from specific features.Site licences: Some packages use site licences (all users in the org are licensed). The LMA manages this at the org level rather than per user.
ISV Harmony: Salesforce's programme linking LMA, Channel Order App, and Analytics for ISVs to manage the complete subscriber lifecycle.
Health Check: A Salesforce Setup tool that evaluates your org's security configuration against the Salesforce Baseline Standard (or a custom security standard). It produces a score (0–100) across categories: Remote Site Settings, Session Settings, Password Policies, Network Access, and Certificate/Key settings. Each finding is rated as High Risk, Medium Risk, Low Risk, or Informational.
Security Center: Available for multi-org environments (Enterprise/Unlimited with add-on). Aggregates Health Check scores across multiple orgs into a central Security Center org. Allows org comparison, trend tracking, and bulk remediation guidance.
Architectural use:
- Run Health Check during every architecture review and before go-live.
- Set a minimum acceptable score (e.g., 90+) as a deployment gate in CI/CD pipelines.
- Use Security Center to enforce security baseline consistency across multi-org landscapes.
- Address high-risk findings first: overly permissive session settings (long timeout, no re-authentication), weak password policies, and broad Remote Site Settings.
- Custom security standards allow organisations to add their own internal security controls to the check.
Security Center: Available for multi-org environments (Enterprise/Unlimited with add-on). Aggregates Health Check scores across multiple orgs into a central Security Center org. Allows org comparison, trend tracking, and bulk remediation guidance.
Architectural use:
- Run Health Check during every architecture review and before go-live.
- Set a minimum acceptable score (e.g., 90+) as a deployment gate in CI/CD pipelines.
- Use Security Center to enforce security baseline consistency across multi-org landscapes.
- Address high-risk findings first: overly permissive session settings (long timeout, no re-authentication), weak password policies, and broad Remote Site Settings.
- Custom security standards allow organisations to add their own internal security controls to the check.
A systematic performance investigation covers multiple layers:
1. Page load performance: Use Salesforce Lightning Inspector (Chrome extension) to identify slow LWC/Aura components. Check for excessive wire calls, large data payloads, and missing caching.
2. SOQL and DML: Enable Apex debug logs at the PROFILING level. Identify SOQL queries with high execution time. Run slow queries in the Developer Console Query Plan tool to check for non-selective queries. Add custom indexes if needed.
3. Automation profiling: Check for excessive trigger chains, Process Builder processes, or Flows firing on the same record save. Consolidate automation into single triggers/flows.
4. Page layout complexity: Too many related lists, inline edit, real-time formula recalculations, and complex layouts degrade UI performance. Simplify layouts and use lazy-loading patterns.
5. Data volume: Related lists loading thousands of records cause UI timeouts. Use List Views with filters, restrict related list record counts, or replace inline lists with custom LWC with pagination.
6. Network: Use browser DevTools Network tab to identify large payload sizes and slow API responses. Enable HTTP/2 and CDN-hosted static resources.
1. Page load performance: Use Salesforce Lightning Inspector (Chrome extension) to identify slow LWC/Aura components. Check for excessive wire calls, large data payloads, and missing caching.
2. SOQL and DML: Enable Apex debug logs at the PROFILING level. Identify SOQL queries with high execution time. Run slow queries in the Developer Console Query Plan tool to check for non-selective queries. Add custom indexes if needed.
3. Automation profiling: Check for excessive trigger chains, Process Builder processes, or Flows firing on the same record save. Consolidate automation into single triggers/flows.
4. Page layout complexity: Too many related lists, inline edit, real-time formula recalculations, and complex layouts degrade UI performance. Simplify layouts and use lazy-loading patterns.
5. Data volume: Related lists loading thousands of records cause UI timeouts. Use List Views with filters, restrict related list record counts, or replace inline lists with custom LWC with pagination.
6. Network: Use browser DevTools Network tab to identify large payload sizes and slow API responses. Enable HTTP/2 and CDN-hosted static resources.
Permission Set Groups (PSG) allow you to combine multiple Permission Sets into a single assignable group. Instead of assigning 5–10 individual permission sets to each user of a given persona, you assign one PSG that bundles them all.
Benefits:
- Simplified assignment: Assign one PSG instead of multiple individual permission sets per user.
- Muting Permission Sets: A PSG can include a Muting Permission Set — a special PS that removes permissions from the group without modifying the underlying permission sets. Useful for edge cases (e.g., a Power User PSG that grants broad access, with specific permissions muted for certain regulated roles).
- Scalable persona management: As permissions change, update the PSG; all assigned users are automatically affected.
Architectural best practice: Define PSGs per user persona (Sales Rep, Sales Manager, Service Agent, System Admin). Use muting permission sets for compliance edge cases. Avoid modifying profiles — the "Permission-Set-Everywhere" Salesforce strategy will eventually deprecate most Profile settings in favour of PSGs.
Benefits:
- Simplified assignment: Assign one PSG instead of multiple individual permission sets per user.
- Muting Permission Sets: A PSG can include a Muting Permission Set — a special PS that removes permissions from the group without modifying the underlying permission sets. Useful for edge cases (e.g., a Power User PSG that grants broad access, with specific permissions muted for certain regulated roles).
- Scalable persona management: As permissions change, update the PSG; all assigned users are automatically affected.
Architectural best practice: Define PSGs per user persona (Sales Rep, Sales Manager, Service Agent, System Admin). Use muting permission sets for compliance edge cases. Avoid modifying profiles — the "Permission-Set-Everywhere" Salesforce strategy will eventually deprecate most Profile settings in favour of PSGs.
User licensing: Choose the right licence type for your portal users (Customer Community, Customer Community Plus, Partner Community, External Apps). Customer Community is the cheapest but most restricted (no sharing rules, role hierarchy limited). Partner Community supports full sharing model. External Apps Plus is the most flexible.
Sharing and security: Set strict OWDs for objects exposed in the community. Use sharing sets (for Customer Community) or sharing rules (for Customer Community Plus/Partner) to control record access. Never rely on page layout to hide sensitive data — enforce FLS and OWD.
Performance: Enable CDN for community assets. Use Guest User caching where appropriate for public pages. Limit the number of components on high-traffic pages. Use lazy loading for data-heavy sections.
Scale: For high-traffic communities (100K+ users), enable community caching, use Lightning Web Runtime (LWR) for performance (faster than Aura communities), and ensure Apex code invoked from community actions is optimised for concurrent users.
Security: Audit guest user permissions carefully — they are unauthenticated. Disable "Public can read" OWD settings for all sensitive objects. Regularly review community sharing and CRUD permissions.
Sharing and security: Set strict OWDs for objects exposed in the community. Use sharing sets (for Customer Community) or sharing rules (for Customer Community Plus/Partner) to control record access. Never rely on page layout to hide sensitive data — enforce FLS and OWD.
Performance: Enable CDN for community assets. Use Guest User caching where appropriate for public pages. Limit the number of components on high-traffic pages. Use lazy loading for data-heavy sections.
Scale: For high-traffic communities (100K+ users), enable community caching, use Lightning Web Runtime (LWR) for performance (faster than Aura communities), and ensure Apex code invoked from community actions is optimised for concurrent users.
Security: Audit guest user permissions carefully — they are unauthenticated. Disable "Public can read" OWD settings for all sensitive objects. Regularly review community sharing and CRUD permissions.
An enterprise Apex trigger architecture must be maintainable, testable, and governor-limit safe:
One Trigger per Object: Have exactly one trigger per object that handles all contexts (before insert, before update, after insert, after update, etc.). Avoids unpredictable execution order between multiple triggers on the same object.
Trigger Handler Pattern: The trigger itself contains no business logic — it delegates to a handler class:
Handler Class: A switch statement routes to context-specific methods (handleBeforeInsert, handleAfterUpdate, etc.). Each method implements bulkified logic.
Service Layer: Complex business logic (reusable across triggers, Apex REST, and Batch jobs) lives in a dedicated Service class, not the handler.
Recursion prevention: Use a static Boolean or static Set of processed IDs to prevent infinite loops.
Unit testing: Test handler methods in isolation. Use test data factories for consistent, reusable test data. Aim for 85%+ code coverage with meaningful assertions.
One Trigger per Object: Have exactly one trigger per object that handles all contexts (before insert, before update, after insert, after update, etc.). Avoids unpredictable execution order between multiple triggers on the same object.
Trigger Handler Pattern: The trigger itself contains no business logic — it delegates to a handler class:
trigger AccountTrigger on Account (before insert, after insert, before update, after update) { AccountTriggerHandler.handle(Trigger.operationType, Trigger.new, Trigger.oldMap); }Handler Class: A switch statement routes to context-specific methods (handleBeforeInsert, handleAfterUpdate, etc.). Each method implements bulkified logic.
Service Layer: Complex business logic (reusable across triggers, Apex REST, and Batch jobs) lives in a dedicated Service class, not the handler.
Recursion prevention: Use a static Boolean or static Set of processed IDs to prevent infinite loops.
Unit testing: Test handler methods in isolation. Use test data factories for consistent, reusable test data. Aim for 85%+ code coverage with meaningful assertions.