Apex Maintenance
Logging and Debugging
System.debug Usage
System.debug should only be used for error logging. All other debug statements must be removed before committing code.
Good Example:
try {
// Process record
} catch (Exception e) {
System.debug('Error processing record: ' + e.getMessage());
// Handle error
}
Bad Example:
System.debug('Processing account: ' + account.Name); // Remove before commit
System.debug('Account ID: ' + account.Id); // Remove before commit
Pre-commit Logging Checklist
- Remove all
System.debugstatements except those used for error logging - Keep error logs concise and actionable for production debugging
- Prefer proper error handling and response wrappers over ad-hoc debug output
Logging Patterns and Best Practices
- Log errors with context (method name, key identifiers, etc.)
- Use consistent log message format
- Include exception stack traces when helpful
- Don't log sensitive information
Example:
try {
processRecord(recordId);
} catch (Exception e) {
System.debug('Error in processRecord for recordId ' + recordId + ': ' + e.getMessage());
System.debug('Stack trace: ' + e.getStackTraceString());
throw e;
}
Code Maintenance
Use this section for long-term maintainability decisions: issue tracking, versioning consistency, and controlled deprecation.
TODO/FIXME Comments
TODO and FIXME comments are acceptable if there is a discussion, issue, or bug created to capture that work.
Format:
// TODO: [Issue #123] Refactor this method to use ACME_AccountSelector
// FIXME: [Bug #456] Handle edge case when recordId is null
Bad Example:
// TODO: Fix this later
// FIXME: This doesn't work
API Version Standardization
Use the latest API version from the project. SFDX handles this automatically when creating new files.
- Don't manually set API version unless necessary
- Keep API versions consistent across the project
- Update API versions as part of regular maintenance
Deprecation Process
Use the following minimum deprecation standard until a fuller lifecycle policy is documented:
- Document replacement - State what to use instead and why
- Set timeline - Define expected removal version/date
- Track consumers - Capture known usages and migration tasks in an issue or work item
Example:
/**
* @description [DEPRECATED] Use ACME_AccountSelector instead
* @deprecated This method will be removed in version 2.0. Use ACME_AccountSelector.selectByName() instead.
* @see ACME_AccountSelector
*/
@Deprecated
public static List<SObject> queryRecords(String objectName) {
// Deprecated implementation
}
Code Analyzer Compliance
Ruleset Reference
All code must comply with the Code Analyzer ruleset your team maintains in the Salesforce source repository (commonly a PMD ruleset file such as rulesets/salesforce.xml referenced from code-analyzer.yml). Full installation, configuration, and command-line usage are covered in Code Analyzer Compliance.
Key Rules to Be Aware Of
Complexity Rules:
CognitiveComplexity- Method: 15, Class: 50NcssCount- Method: 60, Class: 1000AvoidDeeplyNestedIfStmts- Maximum depth: 4ExcessiveParameterList- Maximum: 5 parameters
Security Rules:
ApexSharingViolations- Must declare sharing modelApexCRUDViolation- Validate CRUD before SOQL/DMLApexSOQLInjection- Use bind variables, not string concatenation
Performance Rules:
OperationWithLimitsInLoop- Avoid DML in loops
Code Style Rules:
IfStmtsMustUseBraces- Always use bracesForLoopsMustUseBraces- Always use bracesClassNamingConventions- PascalCase for classesMethodNamingConventions- camelCase for methods
Test Rules:
ApexAssertionsShouldIncludeMessage- Include messages in assertionsApexUnitTestClassShouldHaveAsserts- Tests must have assertionsApexUnitTestShouldNotUseSeeAllDataTrue- Avoid seeAllData=true
Common Violations and Solutions
Violation: Cognitive Complexity Too High
Solution: Refactor into smaller methods, use early returns, reduce nesting
Violation: DML in Loop
Solution: Collect records in a list, perform DML once outside the loop
Violation: Missing Sharing Declaration
Solution: Add with sharing, without sharing, or inherited sharing to class declaration
Violation: SOQL Injection
Solution: Use bind variables instead of string concatenation
@SuppressWarnings Usage Guidelines
Do not use @SuppressWarnings without prior approval from a technical lead. Prefer refactoring or a ruleset adjustment discussed with the team. If a technical lead approves a suppression, use it sparingly, for the smallest scope possible, and document why in ApexDoc (and reference the approval when helpful, e.g. ticket or decision link).
/**
* @description Suppresses PMD warning for this method
* Suppression reason: This method intentionally uses a switch statement
* for type checking which PMD flags, but is the most readable approach here.
* Approved by: Technical Lead <name> on <date> (or link to ticket/ADR).
*/
@SuppressWarnings('PMD.AvoidDeeplyNestedIfStmts')
public static String processType(String type) {
// Implementation
}
Change History
Version 1.0 - 2026-03-26
- Added initial version history tracking for this document.
Last Updated: 2026-03-26 Version: 1.0