It’s important to steer of hardcoding in Apex to ensure our code stays versatile and easy to maintain while being open to future adjustments. Hardcoding values like record types, record IDs, profile IDs and object field names could lead to various issues. In this article we will discuss the recommended methods for steering of hardcoding in Apex to create more organized Salesforce code.
Table of Contents
TogglePitfalls of Hardcoding in Salesforce Apex
1. Lack of Flexibility
When business needs change over time hardcoded values in the code need to be adjusted. This process involves testing of the code, which could extend the time needed to implement new changes. For instance modifying a hardcoded record ID or picklist value necessitates updates to the code and testing, for both future modifications and existing changes.
2. Environment Dependency
Due to differences in record type IDs or other settings, hardcoded values may work in one Salesforce environment (e.g., sandbox) but not in another (e.g., production). Additionally test classes could encounter errors during deployment as the hardcoded ID may not be present, in the target organization.
3. Duplication of Code
When a value is hardcoded in multiple locations within Salesforce Apex, any updates to that value must be made individually at each instance where it appears. This not only leads to redundant work but also significantly increases the risk of introducing inconsistencies or errors during the update process.
Each instance must be carefully located, reviewed, and updated, which can be time-consuming and prone to oversight, especially in large or complex codebases. Moreover, this redundancy amplifies the testing efforts required, as every modified instance needs to be thoroughly tested to ensure the changes were applied correctly and consistently.
These challenges collectively hinder maintainability and scalability, making it difficult to adapt to new requirements or changes efficiently.
4. Increases the scope of Testing
Hardcoded values restrict the flexibility and reusability of unit tests, making it challenging to adapt them across different environments. Since hardcoded data is often specific to a particular environment, such as a development or sandbox environment, the same tests may fail or behave unpredictably when executed in a different context, such as production or another sandbox.
This limitation forces developers to modify the hardcoded values or the tests themselves for each environment, undermining the principle of reusability.
Moreover, the dependency on fixed values can make it difficult to simulate various scenarios or edge cases required for thorough testing. As a result, additional effort is needed to create and maintain separate tests or modify existing ones for different contexts.
This not only increases the overall testing workload but also introduces a higher likelihood of errors or inconsistencies during test execution, especially when changes are made to the underlying code. Ultimately, hardcoded values hinder the ability to implement efficient, scalable, and environment-agnostic testing practices, leading to longer development cycles and reduced agility in handling new and existing changes.
How to avoid Hardcoding Values in Apex Code?
- Use custom metadata types
- Use custom settings
- Custom Labels for User Facing Text
- Environment-Specific URLs using Named Credentials
1. Use custom metadata types
Custom Metadata Types allow configuration values to be managed declaratively, providing a seamless way to define, store, and deploy settings across different environments, including production.
These values can be easily updated directly in production without requiring code changes or deployments, offering greater flexibility and agility. By centralizing configuration management, Custom Metadata Types streamline the process of adapting to changing requirements while ensuring consistency and reducing the risk of errors during deployments.
The method calculateTax calculates tax using a hardcoded tax rate of 0.05. Later, when the tax rate changes, we must change this code. The method calculateTaxDynamically uses a custom metadata type. We can change the tax rate by changing the value in the FixedTaxRate__c field anytime. This will make our code configurable and maintainable.
public class GenerateTaxService {
//HardCode
public static Decimal calculateTax(Decimal price)
{
//Hardcoded Tax Rate
Decimal taxAmount=(price*0.05);
return taxAmount;
}
//Dynamic
public static Decimal calculateTaxDynamically(Decimal price)
{
//Custom Metadata Types
List<TaxSetting__mdt> settings= TaxSetting__mdt.getall().values();
if(settings.size()>0)
{
Decimal taxAmount=(price*settings[0].FixedTaxRate__c);
return taxAmount;
}
return 0;
}
}
2. Using Custom Setting
Custom Settings provide a way to eliminate hardcoding in the code by storing configurable data that can be easily managed and tailored to meet business needs. By leveraging Custom Settings, developers can centralize and streamline data management, allowing for greater flexibility and reducing the need for repetitive code updates.
public class GenerateTaxService {
//HardCode
public static Decimal calculateTaxHardCode(Decimal price)
{
//Hardcoded Tax Rate
Decimal taxAmount=(price*0.05);
return taxAmount;
}
//Dynamic
public static Decimal calculateTaxDynamically(Decimal price)
{
//Hierarchy Custom Setting
TaxSetting__c setting= TaxSetting__c.getOrgDefaults();
if(settings!=null)
{
Decimal taxAmount=(price*setting.FixedTaxRate__c);
return taxAmount;
}
return 0;
}
}
Using Custom Settings or Custom Metadata Types to store record types, profile IDs, or record IDs enhances the configurability and maintainability of your code. By externalizing these values, you can easily manage and update them without modifying the code, resulting in a more flexible and scalable solution.
3. Use Custom Labels
Hardcoding error messages or alert text directly into the code requires updates to the code whenever the text changes. To avoid this, text strings displayed to users—such as error messages, informational alerts, or prompts—can be stored in Custom Labels.
This approach makes the messages configurable, allowing for easy updates or localization without the need to modify the underlying code, ensuring greater flexibility and efficiency.
// In your Apex class
String errorMessage = Label.CustomLabel_GenerateTaxInfo_Missing_Error;
throw new CustomException(errorMessage);
4. Use Named Credentials to Store Callout Information
Developers often hardcode API endpoint URLs when performing integration tasks, which necessitates code modifications whenever the endpoint changes. Instead of hardcoding, you can use Named Credentials in Salesforce.
Named Credentials allow you to declaratively configure API endpoint URLs and authentication details, making integrations more flexible and eliminating the need for code changes when updates are required.
public class ApiService {
public void generateTaxService() {
HttpRequest req = new HttpRequest();
//TaxNC is Named Credential
req.setEndpoint('callout:TaxRateNC/taxRate');
req.setMethod('GET');
Http http = new Http();
HttpResponse res = http.send(req);
}
}
Conclusion
In summary, by eliminating hardcoding and adopting these best practices, your Salesforce Apex code becomes more flexible, maintainable, and scalable. This approach simplifies ongoing support and ensures the code can evolve efficiently to meet changing requirements in both development and production environments.