Skip to content

Recommended Conventions for Salesforce Development

David B edited this page Feb 1, 2025 · 17 revisions

General Principles

  • Regularly refer to the Salesforce Metadata Coverage Report and:
    • Avoid leveraging metadata types which are unsupported by Unlocked Packaging
    • Avoid modifying Standard or Managed Metadata Types

Naming Conventions

Objects & Fields

  • Use PascalCase for custom objects and fields
    • Avoid using underscores
  • Use singular nouns for object names
  • Avoid modifying the following Standard Metadata Types:
    • Standard Page Layouts
    • Standard Flexipages
    • Standard Search Layouts
    • Standard Compact Layouts
    • Standard Value Sets (e.g. Opportunity Stage Picklist)
  • When creating fields, always add them to the relevant Permission Set(s)
  • Avoid changing field Data Types (generally better to introduce a new field and deprecate the old one as opposed to changing its type)
  • Junction object names should reflect their primary relationships (eg a junction object joining Survey__c and Page__c should be called SurveyPage__c)

Tip

Most field types don't need type indicators - the name should describe its purpose clearly. Only use suffixes when they add clarity or help distinguish between similar fields.

Below are specific conventions for various field types:

Field Type Example Field Label Example API Name Notes
Most Fields Annual Revenue AnnualRevenue__c No suffix needed
Lookup/Master-Detail Account Manager AccountManagerId__c Use Id suffix
Date Start Date StartDate__c Use Date when needed to distinguish from DateTime
DateTime Start Time StartDateTime__c Use DateTime when needed to distinguish from Date
Percent Discount DiscountPct__c Use Pct only when "Percent" isn't clear in name
Number Sequence SequenceNum__c Use Num only when disambiguation needed
Legacy System IDs Legacy LCS ID LegacyLcsId__c Use Id suffix

Apex

Class Naming

General Class Rules

  • Use PascalCase for all class names
  • Classes should be nouns (e.g., UserService)
  • Avoid abbreviations unless universally understood (e.g., Id, Http)

Specific Class Types

  • Test Classes: Suffix with Test
  • Trigger Handlers: Suffix with TriggerHandler
  • Triggers: Suffix with Before or After to indicate execution order
    • Example: AccountTriggerBefore
  • Utility Classes: Suffix with Util
  • Scheduled Jobs: Suffix with Schedule
  • Invocable Classes: Suffix with Action
    • Example: AccountMergeAction
    • Always include human-friendly Labels and Descriptions
      • Label example: Merge Accounts
      • Description example: This action attempts to automatically merge two account records
  • Exception Classes: Suffix with Exception
    • Example: InvalidAccountException

Interface Naming

  • Avoid "I" prefix for interfaces
    • ✅ Use: PayableInterface
    • ❌ Avoid: IPayable

Composable Architecture Pattern

classes/
├── account/
│   ├── AccountApi.cls         
│   ├── AccountController.cls  
│   ├── AccountService.cls     
│   ├── AccountRepository.cls  
│   └── client/               
│       ├── AccountRequest.cls          # Apex-Defined Type for incoming account creation requests
│       ├── AccountResponse.cls         # Apex-Defined Type for API responses
│       └── AccountSearchCriteria.cls   # Apex-Defined Type for complex search parameters

Method Naming

General Method Rules

  • Use camelCase
  • Methods should be verbs
  • Example: getUserById

Common Method Prefixes

  • Accessors: Use get/set
  • Complex Operations: Use compute/calculate
  • General Actions: Start with verbs
    • Examples: getData, processRecord, validateInput

Test Methods

  • Prefix with test
  • Use descriptive names explaining the scenario
  • ✅ Good Examples:
    • testUpdateAccountWithValidData
    • testThrowsExceptionWhenEmailInvalid
  • ❌ Avoid arbitrary suffixes

Variable Naming

General Variable Rules

  • Use camelCase
  • Use meaningful plural/singular forms

Collection Naming

✅ Correct Examples:

  • List<Account> accounts
  • Account primaryAccount
  • List<Contact> activeContacts

❌ Incorrect Examples:

  • List<Account> account
  • Account accounts
  • List<Contact> contact

Boolean Naming

Use these prefixes:

  • is: For state
    • Examples: isValid, isActive
  • has: For possession
    • Examples: hasPermission, hasChildren
  • should: For conditions
    • Examples: shouldProcess, shouldUpdate

Constants

  • Use UPPER_SNAKE_CASE
  • Example: MAX_ATTEMPTS

Flows

  • Use PascalCase for flow names
  • Avoid including redundant information in the Flow Name and Label. All of the following details are natively tracked by Salesforce and are therefore considered redundant:
    • Active
    • Api Version
    • Environments
    • Flow Namespace
    • Created By
    • Package Name
    • Package State
    • Process Type
    • Source Template
    • Template
    • Trigger
  • A single flow should be roughly analogous - in terms of its "Cognitive Complexity" - to a single Apex Method:
    • Name follows typical verb-noun conventions: (e.g., CreateNewAccount, UpdateOpportunityStage, GetOpportunityProducts)
    • Single-Responsibility
    • Reusable
    • Self-contained
  • Avoid using the default screen header in Screen Flows
    • Instead, disable the header and insert a "display text" element with a user-friendly title
    • Tip: For screen flows with many screens, consider creating a Text Template variable to avoid creating the title in every screen
  • Variable naming conventions:
    • Input variables: prefix with in_
    • Output variables: prefix with out_
    • Collection variables: suffix with _Collection
    • Loop variables: suffix with _Current

Validation Rules

  • Use all-caps snake-case for Validation Rule names (e.g., REQUIRE_CONTACT_METHOD)
  • Start with a verb describing the restriction:
    • PREVENT_DUPLICATE_NAME
    • PREVENT_NULL_LASTNAME
    • REQUIRE_ROLE_ADMIN
  • Error messages should:
    • Use clear, user-friendly language
    • Include specific resolution steps
    • Example: "Please provide at least one contact method (Email or Phone)"

Reports & Dashboards

  • Use underscore (_) instead of spaces in report and dashboard names
  • Start with the primary object name (e.g., "Opportunity_Pipeline_Summary")
  • Use consistent folder structure:
    • Format: Department/Team/Category/Report_Name
    • Example: Sales/Pipeline/Opportunity/Opportunity_Pipeline_Summary
  • For time-based reports, include date:
    • Format: Report_Name_YYYY_MM

User Interface

  • Use verb phrases for button and link names
  • For custom labels, use all-caps snake-case OBJECT_ACTION_PURPOSE (e.g., ACCOUNT_CREATE_ERROR, ACCOUNT_CREATE_SUCCESS, USER_SIGNIN_WELCOME)

Lightning Web Components (LWC)

  • Use kebab-case for component names (e.g., "my-component")
  • Use camelCase for properties and methods
  • Suffix service components with "Service" (e.g., "dataService")
  • Follow DRY & SOLID principles
  • File naming conventions:
    • HTML template: myComponent.html
    • JavaScript: myComponent.js
    • CSS: myComponent.css
    • Test: myComponent.test.js
  • Private methods/properties should start with underscore
  • Event handler methods should end with Handler (e.g., clickHandler)

Page Layouts

  • Use PascalCase for page layout names
  • Avoid modifying Standard Page Layouts
  • Include the object name and any specific use case (e.g., AccountSalesLayout, ContactSupportLayout)

Flexipages

  • Use PascalCase for Flexipage names
  • Avoid modifying Standard Flexipages
  • Include the purpose or app name (e.g., AccountDetailPage, SalesConsoleHomePage)

Custom Settings

  • Avoid using these altogether. They are not CICD-friendly.
  • Instead, rely on Custom Metadata Types and/or Custom Permissions where applicable

Custom Metadata Types

  • Use PascalCase for custom metadata type names
  • Suffix with Setting or Config (e.g., EmailServiceSetting, IntegrationConfig)

Custom Permissions

  • Use PascalCase for custom permission names
  • Create one Custom Permission per Persona-based custom permissions (e.g. isCallCenterUser, isFieldServiceManager)
    • Add these^ custom permissions to a permissionSet & permissionSetGroup of the same name (e.g. CallCenterUser, FieldServiceManager)
    • In addition to sanitizing your permission schema, this also gives you some pretty incredible super powers...

Checking perms in Apex

public void updateServiceCase(Case record) {
    // Check if user has field service permissions
    if (!FeatureManagement.checkPermission('isFieldServiceManager')) {
        throw new CustomException('You do not have permission to update service cases');
    }
    
    // Proceed with update
    update record;
}

Checking perms in Formulas/Validation Rules

AND(
    ISCHANGED(Status),
    NOT($Permission.isCallCenterUser)
)

Clone this wiki locally