Building for an unknown set of subscribing orgs imposes design constraints beyond a single-org build.
Key considerations:
- Namespace awareness — all custom objects/fields/classes carry your namespace. Cross-namespace references require dynamic SOQL.
- Bulkified by default — subscribers can have wildly different data volumes.
- Sharing model neutral — default to
with sharing; opt out only for legitimate system tasks. - Governor limits leave room for subscriber — aim to use ~30% or less of limits; the customer's own automation also consumes them.
- No dependencies on subscriber-specific metadata — use
Schema.describeSObjectsfor dynamic field access. - Test data factory inside package — subscribers may have validation rules that break naive test setup.
- Forward compatibility — subscribers will be on different versions. Avoid breaking changes; deprecate, don't remove.
- `global` is permanent — once exposed, you can't change the signature. Be deliberate.
- Trigger handler discipline — one trigger per object.
- Error handling — throw custom exceptions; subscribers need to debug your package.
- Configurable behaviour — Custom Metadata Types let subscribers tune without forking.
- Performance budgets — each method completes well under CPU limit.
- Test in subscriber-like orgs — partner orgs that mimic real customer configurations.
- Logging — log to a custom object so subscribers can troubleshoot.
- Deprecation strategy — announce, deprecate, remove across multiple versions.
Multi-tenant constraints feel restrictive but make Salesforce ISV apps reliable across thousands of customer orgs.
