Skipping Unit Tests
- Mistake: Not writing proper unit tests is a common issue. Although Salesforce requires a minimum of 75% code coverage for deployment, relying on just meeting the threshold without writing comprehensive tests can lead to undetected bugs.
- How to Avoid: Always write unit tests that cover both positive and negative scenarios. Use
Test.startTest()andTest.stopTest()to monitor asynchronous behavior and ensure your tests run within governor limits. Ensure that your tests include edge cases and all possible error paths.
Ignoring Governor Limits
- Mistake: Salesforce enforces strict governor limits (such as 100 SOQL queries per transaction, 6 MB of heap size, etc.). Ignoring these limits can result in runtime exceptions like
Too many SOQL queriesorHeap size too large. - How to Avoid: Always write code that is “bulk-safe”—this means using bulk operations and avoiding SOQL queries in loops. For example, use
Liststo store records and process them in bulk rather than querying them one at a time. UseDatabase.query()for dynamic queries and minimize the number of records processed in each transaction.
Hardcoding IDs and Values
- Mistake: Hardcoding record IDs (e.g.,
AccountId = '001xxxxxxxxxxxx') and values (like currency or user roles) makes your code brittle and non-portable. It creates problems when migrating from sandbox to production or when the underlying data changes. - How to Avoid: Always use dynamic approaches. For example, if you need an ID for a specific record, query it dynamically based on the record’s properties. Use Custom Labels and Custom Settings for values that may change across environments or over time.
Not Using Declarative Tools Where Possible
- Mistake: Writing custom Apex code when declarative tools (e.g., Flows, Process Builder, Validation Rules) could achieve the same result often leads to overcomplicated and difficult-to-maintain solutions.
- How to Avoid: Before writing custom code, ask yourself whether the solution can be implemented using declarative tools. Flows, in particular, have become quite powerful and can replace many Apex triggers, reducing complexity and improving maintainability.
Lack of Bulk Processing
- Mistake: Writing Apex code that processes records one by one instead of in bulk can quickly lead to hitting governor limits when working with large datasets. For example, performing an SOQL query inside a loop can result in excessive queries being executed.
- How to Avoid: Use best practices like bulkifying your code. This means processing records in collections (e.g., Lists, Sets, and Maps) and running SOQL queries outside of loops. The goal is to minimize the number of queries and DML operations while handling large datasets effectively.
Not Following Security Best Practices
- Mistake: Overlooking security considerations in your code, such as not respecting Field-Level Security (FLS) or not using sharing rules correctly, can expose sensitive data and lead to security vulnerabilities.
- How to Avoid: Use
with sharingin your Apex classes to respect sharing rules and limit data visibility according to user permissions. Additionally, always check FLS in your code by using methods likeSchema.sObjectType.Account.fields.Name.isAccessible()to ensure users can access the fields you’re working with.
Mismanagement of Trigger Logic
- Mistake: Not properly structuring trigger logic, especially when dealing with multiple triggers on the same object, can result in unexpected behavior and difficulty troubleshooting issues.
- How to Avoid: Follow the best practice of having one trigger per object, and delegate the logic to Apex handler classes. Implement the “one trigger per object” pattern to avoid conflicts and ensure clear, maintainable code. Consider using trigger frameworks like the
TriggerHandlerpattern to organize your triggers.
Neglecting Governor Limits During API Integration
- Mistake: API integrations can easily exceed Salesforce’s API limits (e.g., number of callouts per day or batch size), causing failures or performance issues if not properly handled.
- How to Avoid: Use asynchronous Apex (like
@futuremethods or Queueable Apex) for external API callouts to avoid blocking the main transaction. Also, implement retry logic to gracefully handle failures and ensure that your integration handles the API rate limits of both Salesforce and the external system.
Poor Use of Exception Handling
- Mistake: Failing to handle exceptions properly or using generic
catchblocks without meaningful error messages can make it difficult to diagnose and fix issues. - How to Avoid: Use specific exception types in your
try-catchblocks and provide meaningful error messages to capture the root cause of the issue. For example, instead of justcatch(Exception e), catch specific exceptions likeDmlExceptionand log meaningful details about the failure, including the context in which the error occurred.
Insufficient Documentation
- Mistake: Not documenting your code or using ambiguous variable names can create confusion for other developers (or your future self) when maintaining or enhancing the code.
- How to Avoid: Use comments to explain non-obvious code logic, especially complex algorithms or business rules. Document any assumptions made and why a particular approach was taken. Use meaningful and descriptive variable names to make your code easier to understand.
Not Following Best Practices for Asynchronous Apex
- Mistake: Misusing asynchronous Apex features like
@future, Batch Apex, or Queueable Apex can lead to issues like poor performance or missed execution due to governor limits or execution order. - How to Avoid: Always choose the right type of asynchronous processing based on the scenario. Use Batch Apex for large data processing, Queueable Apex for small to medium jobs that need chaining, and
@futurefor short, non-blocking tasks. Be mindful of governor limits for asynchronous operations.
Optimizing SOQL Queries
- Mistake: Writing inefficient SOQL queries, such as using
SELECT *or performing queries in a loop, can lead to performance degradation and hitting governor limits. - How to Avoid: Always write selective queries by filtering data based on indexed fields. Avoid
SELECT *—only query the specific fields you need. Minimize the number of SOQL queries by grouping them outside of loops and usingINclauses when querying related records.
Skipping Performance Testing
- Mistake: Failing to test your code for performance, especially when dealing with large data volumes or complex processes, can result in slow page loads or failed processes under production loads.
- How to Avoid: Test your code under realistic conditions by using
Test.startTest()andTest.stopTest()for performance profiling. Monitor heap size, SOQL limits, and execution time in your unit tests. Perform load testing when necessary to ensure your solution can scale properly.
By following these practices, you can significantly reduce the risk of common mistakes and improve the quality, maintainability, and performance of your Salesforce applications.