These are the slides from a presentation given to the San Diego Salesforce Developer Group on September 16, 2014.
The presentation highlights why coding standards and design patterns are important parts of creating a scalable, maintainable Salesforce Enterprise Org. A series of specific implementation and architecture recommendations are outlined. Finally, models for process and governance are provided to help the viewer take steps to bring about change in their Org.
3. Overview
• Why standards, design patterns, and best practices matter
• Implementation and Architecture
• Process and Governance
• Three things you can do TODAY
3
4. Why Patterns and Best Practices Matter
• Efficiency
• Security
• Quality
• Minimize Technical Debt
4
5. What is “Technical Debt”?
“Work that needs to be done before a particular job can be
considered complete or proper. If the debt is not repaid, then it
will keep on accumulating interest, making it hard to implement
changes later on”.
In other words…
“All the things, big and small, that left undone will eventually
come around to bite you in the ass”.
5
6. Salesforce Technical Debt Accrues FAST
• Too many “System Administrators”.
• Changing the data model and adding business logic is EASY.
• Less institutional knowledge of Salesforce (typically)
6
7. Salesforce “Gotchas” are Painful
Salesforce development takes a lot of effort to do right.
• Governor limits can cause pain unexpectedly if not considered
early on in the design process.
• Deployment is tricky business
• Team development is either the Wild West…or Soviet Russia.
7
10. Coding Style
Apex code should follow a consistent coding style for the
following areas.
• Whitespace
– Always use spaces for indentation. Do not use tabs.
• Block Indentation / Column Limit
– Indent new blocks with two spaces.
– Code within a 100 character column limit.
• SOQL Queries
– Break SOQL Queries across multiple lines.
• Fields named in the SELECT clause appear alone, one per line.
- List fields in ascending alphabetical order.
• WHERE predicates appear alone, one per line.
*See the Google Java Style guide for additional guidance
10
12. Apex File Headers
• File headers should include…
– Description of purpose.
– Names / emails of the author, and subsequent editors.
– Date of creation, and last modification.
– Related metadata (eg. classes, triggers, objects, VF pages).
• Apex REST classes should…
– Note the HTTP methods they serve.
– Note endpoints when using multiple base URIs per method.
• Triggers and Trigger Handler classes should…
– Note the Actions being caught and processed.
• Use @deprecated when a class is no longer in use.
12
13. Apex Method Headers
• Standard (non-test) method headers should include…
– One or two sentence description of purpose.
– @param description of each parameter
– @return description of the return type, noting likely returned
values / outcomes.
• Test method headers require only…
– Description of the test’s functional logic.
13
14. Visualforce Documentation
Visualforce Pages and Components should be simultaneously
documented in two places.
• File Headers
• Metadata “Description” Fields
14
15. Visualforce File Headers
• Use HTML (<!-- -->) comment blocks.
• File headers should include…
– Description of purpose.
– Names / emails of the author, and subsequent editors.
– Date of creation, and last modification.
– Related metadata (eg. classes, objects, pages, components).
• File headers should respect a 100 column width limit.
15
16. Visualforce Metadata Descriptions
• Edit via Setup or -meta.xml
• Write for a non-technical audience
• Summarize File Header documentation, including…
– Short description of purpose.
– Date of creation
– Full name of original author.
– Administrative notes (if known).
• Update only if core functionality changes
16
17. Non-Code Metadata Documentation
Add descriptions for ALL non-code metadata!
• Description fields typically hold 255 characters
– 1000 for Custom Objects and Fields
• Descriptions should include…
– Short description of purpose
– Date of creation
– Full name of creator
– Administrative references
17
20. Triggers
• One trigger per Object
– Guaranteed order of execution (at least for your code!)
• Implement logic in a separate “trigger handler” class.
• Use static variables to prevent trigger recursion
• All logic MUST be “bulkified”.
20
21. What is “Bulkified” Code?
• Acts on collections, rather than single objects.
• Designed with governor limits in mind
– SOQL Queries
• NEVER perform queries inside of loops!
• Query using sets, rather than single-value predicates
• Use SOQL For loops when expecting more than 300 records.
- Use selective queries!
– DML Operations
- Always perform DML on collections of SObjects.
- Be aware of “hidden” DML, eg. Database.ConvertLead().
- NEVER perform DML inside of loops!
– Future Calls
- Max of 10 @future calls per execution context.
- No callouts from triggers! Business logic often requires use of @future methods.
- @future methods called from Triggers MUST be designed for bulk!
21
22. “Bulk” Design Patterns
• All code should be “bulk” code!
• Public static methods should always be “bulkified”
• Public instance methods can sometimes be “non-bulkified”.
– But they should have a really good reason!
Commit to “bulk-first” design, and it will eventually
become second nature.
22
23. Separation of Concerns
• What is SOC?
– Class architecture?
– Naming conventions?
– Mumbo Jumbo?
23
24. Separation of Concerns (High Level)
Entrypoint Layer
Invocation Layer
Service Layer
Utility Layer
Activities that invoke Apex
– API / UI Based Create/Update/Delete
– Visualforce Page / Component Load
– SFDC Asynchronous Queue, Apex Scheduler
“First Line” of Apex Code
– Visualforce Controllers and Extensions
– Triggers and Trigger Handlers
– Web and Email Services
– Asynchronous and Scheduled Apex
Domain and Function-specific
Business Logic
– LeadServices.cls, AccountServices.cls, etc.
– RegistrationServices.cls, CpqServices.cls, etc.
Supports the Service Layer
– Utility Classes
– Model / Wrapper Classes*
– Selector Classes
24
25. Separation of Concerns (Low Level)
LeadConvController.cls
25
SFDC
API Based
Create/Edit/Delete
UI Based
Create/Edit/Delete
LeadConv.page Asynchronous
Apex Scheduler
Queue
Operation
Operation
LeadTrigger.trigger
LeadTriggerHandler.cls
LeadIntAsync.cl
s
LeadIntBatch.cls LeadCleanJob.cls
ContactServices.cls LeadServices.cls AccountServices.cls
ContactSelector.cls LeadConversionUtil.cls ConvertedLead.cls AccountSelector.cls
26. Naming Conventions
• Apex and Visualforce Names
• Apex and Visualforce Identifiers
• Objects, Fields, and other Metadata
26
27. Apex and Visualforce Names
• Use UpperCamelCase
• Avoid using underscores
• Use full names, rather than abbreviations (in most cases)
– If using abbreviations, be consistent!
• Test classes append “Test” to the name of the covered class
27
28. Choosing a Name
Apex
• First word(s) should be the API name of the related
component.
– If too long, use a consistent best-approximation
– Ignore underscores
• Middle word(s) can provide context (optional)
• Last word(s) should indicate “functional type” of the class
– Reconsider design of classes that don’t fit one functional type
Visualforce
• For Visualforce names, be descriptive but brief
– Controller classes incorporate the Page / Component name
28
29. Apex Class and Trigger Name Suffixes
Functional Type Name Suffix Examples
Trigger Trigger AccountTrigger
Trigger Handler TriggerHandler AccountTriggerHandler
VF Controller Controller NewAccountController
VF Controller Extension ControllerExt AccountControllerExt
Service Class Services AccountServices
Utility Class Util AccountDupeCatcherUtil
Selector Class Selector AccountSelector
Model / Wrapper Class Varies… Accounts / AccountWrapper
Web Service (SOAP) Ws AccountToolsWs
Web Service (REST) Rest AccountToolsRest
Email Service EmlSvc AccountCreateEmlSvc
Asynchronous (Future) Async AccountIntegrationsAsync
Asynchronous (Batch) Batch AccountMigrationBatch
Scheduled Apex Job AccountCleanupJob
29
30. Apex and Visualforce Identifiers
• Variable Names
– SObjects
• Type of SObject should be clear by looking at name
– Collections
• Should always be plural!
• Method Names
– UseCamelCase…but the first character is always lowercase.
• useCamelCase()
All should…
• Use descriptive words.
– Rapid clarity to others is important!
• NEVER use single-character variables.
30
31. Objects, Fields, and Other Metadata
Create and follow common rules for…
• Use of underscores to separate words in API names.
• Capitalization of words in API names
• Must API names and labels match?
31
33. Recommendations
• Agree on specific org-wide standards, patterns, and practices.
• Refactor code and data model
• Define a regular Quality Control Cycle.
33
34. Agree on Standards
• Figure out what they are
• Socialize with your team
• Seek support from management
34
37. Three Things You Can Do TODAY
• Create a one-page Standards Document
• Make sure you’re using one trigger per object
• Commit to two code reviews
37
40. Appendix
• Google’s Java Style Guide
– http://bit.ly/GoogleJavaStyle
• Separation of Concerns
– Dreamforce Presentation (Video) – “Apex Enterprise Patterns”
• http://bit.ly/DF2013SOC
– Andrew Fawcett’s Blog – “Apex Enterprise Patterns – Separation of
Concerns”
• http://bit.ly/FawcettBlogSOC
– DeveloperForce Technical Library – “Separation of Concerns”
• http://bit.ly/DevForceSOC
40
Notas del editor
The multi-tenant architecture of Salesforce, and the Platform and Governor Limits that go with it, mean that the use of certain best practices and design patterns are not matters of preference, but of requirement.
In any environment, non-existent or ad-hoc standards greatly contribute to technical debt. However, the unique nature of technical debt on Salesforce makes defining and adhering to standards critical to the long-term health of an Enterprise Org.
This presentation is intended to increase our team’s knowledge of Salesforce development best practices, and highlight steps that we can take to bring the B2B Org into compliance with them.
Too many “System Administrators”.
Revolution is easy. Governing is hard.
With great power comes great responsibility.
Changing the data model and adding business logic is EASY.
Just because you can point-and-click something into existence doesn’t mean you should.
Compare to the “old days” when DBAs owned the data model, and only developers could effect how an application behaved.
Beware the Ninja Admin!
Less institutional knowledge of Salesforce (typically)
Knowledge of Salesforce-specific design patterns is critical.
Use of multiple contractors can result in an uneven patchwork of design choices and coding standards.
The story of the Opportunity.Contact__c field is a good example of a Ninja Admin point-and-clicking something into existence when he should not have.
Specific problems with Unit Tests include the use of the “SeeAllData=TRUE” annotation. Creating high quality, flexible “Test Data Utility” classes can help.
Salesforce development takes a lot of effort to do right.
Governor limits can cause pain unexpectedly if not considered early on in the design process. Common pitfalls include…
Number of SOQL Queries
Number of @Future calls
Number of records retrieved.
Deployment is tricky business
Metadata dependencies can be a nightmare to debug.
“Destructive” changes are especially painful!
Writing “instance agnostic” Unit Tests takes extra time and effort.
Team development is either the Wild West…or Soviet Russia.
Lack of Salesforce-specific tools and best practices means most Enterprises fend for themselves (with varying degrees of success).
Beware the Ninja Developer!
Coding Style
Documentation
Apex Classes and Triggers
Visualforce Pages and Components
Non-Code Metadata
Design Patterns
Trigger Design Patterns
“Bulk” Design Patterns
Separation of Concerns
Naming Conventions
Apex Class and Trigger Names
Visualforce Page and Component Names
Apex and Visualforce Identifiers
Objects, Fields, and other Metadata
Various browser based editors may convert TABS to SPACES, rending the use of TABS for indenting an inconsistent experience. For this reason, it is best to standardize on indenting with spaces only.
Whitespace
Always use spaces for indentation. Do not use tabs.
Use a single space to…
Separate reserved words, like if, for, catch, from an open parenthesis or open brace.
Separate closing parenthesis and opening braces.
Add space to both sides of any binary or ternary operator.
Horizontal alignment is allowed, but not required.
Block Indentation / Column Limit
Indent new block or block-like constructs with two spaces.
Code within a 100 character column limit.
Longer statements must be line-wrapped.
Indent continuation with at least +4 spaces.
SOQL Queries
SOQL keywords (eg. SELECT, FROM, WHERE) use ALL CAPS.
SOQL Queries (both inline and constructed strings) break across multiple lines.
The SELECT, FROM, WHERE, and ORDER BY clauses each appear alone, on a single line.
SOQL code between the four “top-level” clauses is indented by at least +2 spaces.
Fields named in the SELECT clause appear alone, one per line.
Fields should be listed in ascending alphabetical order.
Fields added later should respect this ordering.
WHERE predicates appear alone, one per line.
Logical operators (AND / OR) between predicates appear alone, one per line, and are indented by at least +2 spaces.
Child relationship queries follow the same rules.
Apex code files implement a variety of documentation headers using block-formatted (/* */) comments. These include:
File Headers
Method Headers
Other Headers
All headers must respect the 100 column width limit. The use of repeated, contiguous characters (eg. *********) to mark the vertical boundaries of each header is encouraged.
File headers should include:
Description of purpose.
Names / emails of the author, and subsequent editors.
Date of creation, and last modification.
Related metadata (eg. classes, triggers, objects, VF pages).
Apex REST classes should…
Note the HTTP methods they serve.
Note endpoints when using multiple base URIs per method.
Triggers and Trigger Handler classes should
Note the Actions (eg. BEFORE UPDATE, AFTER INSERT) being caught and processed.
Use @deprecated when a class is no longer in use.
Apex Method Headers
All standard (non-test) method headers should include:
One or two sentence description of purpose.
@param description of each parameter, one per line, noting the parameter name, type, and purpose.
@return description of the return type, noting likely returned values / outcomes.
Test method headers require only a description of the test’s functional logic.
Use HTML (<!-- -->) comment blocks to create Visualforce Page / Component documentation headers.
File headers are typically viewed by Developers, and may be updated many times over the life of the file.
File headers should include:
One or two sentence description of purpose.
Names and email addresses of the original author, and anyone making significant modifications.
Date of creation, and date of last modification.
Related metadata (eg. classes, objects, components).
File headers respect a 100 column width limit, and are vertically bound (top and bottom) by single lines of repeated, contiguous characters (eg. *********).
Metadata “Description” Fields
Metadata Descriptions can be edited via the Setup UI, or the -meta.xml file associated with the VF Page or Component.
Metadata Descriptions are typically viewed by non-Developer Admins, and are only updated if the core functionality of the Page or Component changes.
Descriptions are written for a non-technical audience, and summarize the File Header documentation at the time the file was created.
Summaries should include:
One or two sentence description of purpose.
Date of creation, and the full name of the original author.
Administrative notes, eg. “Requested / Approved By”, “User Story ID”, or “Defect ID” (if known).
Description can be accessed via the Setup UI, or by directly editing the “*-meta.xml” files associated with certain metadata files in Eclipse.
Document ALL non-code metadata by writing a detailed summary in the Description field.
Description fields typically hold 255 characters.
Custom Objects and Fields can store 1000 characters!
Almost all metadata types expose this field.
Apex classes / triggers being notable exceptions!
This field should always be filled out!
Metadata Descriptions should always include:
Brief description of purpose.
Be mindful of the 255 character limit for most metadata types!
Date of creation, and the name of the original creator.
Helps maintain accountability after automated deployments and sandbox refreshes.
Administrative notes (optional, but recommended if known)
Requested / Approved by?
Related User Story or Stories
Anything else that can tie the metadata component to external documentation.
Implementing Salesforce-specific design patterns is critical to creating a scalable, maintainable, Enterprise Org.
Trigger Design Patterns
“Bulk” Design Patterns
Separation of Concerns
One trigger per Object
Guaranteed order of execution (at least for your code!)
No business logic in triggers
The only logic present in triggers is simple dispatch logic to route each trigger action to a single action handler.
Business logic begins in the trigger handler class.
Use static variables to prevent trigger recursion
All logic run within a trigger’s execution context MUST be bulk-safe.
“Bulk” code acts on collections, rather than single objects.
Need to consider SFDC governor limits at design time.
SOQL Queries
Query for predicate values in sets, rather than using multiple SOQL queries.
NEVER perform queries inside of loops!
Special consideration needed when dealing with large data sets.
Use SOQL For loops when expecting more than 300 records.
Use selective queries!
DML Operations
Always perform DML on collections of SObjects.
Be aware of “hidden” DML, eg. Database.ConvertLead().
NEVER perform DML inside of loops!
Future Calls
Max of 10 @future calls per execution context.
No callouts from triggers! Business logic often requires use of @future methods.
@future methods called from Triggers MUST be designed for bulk!
All code should be “bulk” code!
Public static methods should always be “bulkified”
Does not apply to web service methods
Public instance methods can sometimes be “non-bulkified” if acting only on the instance of the object itself.
Other public methods should have a really good reason to NOT be bulkified.
If you force yourself to always write “bulk” code, it will eventually become second nature.
There are many ways to invoke Apex code, including…
Anonymous Blocks
Triggers
Asynchronous Apex
Future Methods
Scheduled Apex
Batch Apex
Web Services
SOAP / REST
Email Services
Visualforce Classes
Page / Component / List Controllers and Extensions
JavaScript
JavaScript Remoting / AJAX Toolkit
Apex class names have a 40 character limit on length.
Class and Trigger names are written in UpperCamelCase.
Use full names, rather than abbreviations (in most cases).
Avoid using underscores.
When choosing a name:
First word(s) should be the API name of the related component.
If the API name is too long, use a consistent best-approximation.
Optional middle word(s) may provide context regarding purpose.
Last word(s) should indicate “functional type” of the class.
Ignore underscores in the related component’s name.
Be consistent!
Classes with the same functional type share the same suffix.
Reconsider the design of classes that do not fit a single functional type.
Apex class names have a 40 character limit on length.
Class and Trigger names are written in UpperCamelCase.
Use full names, rather than abbreviations (in most cases).
Avoid using underscores.
When choosing a name:
First word(s) should be the API name of the related component.
If the API name is too long, use a consistent best-approximation.
Optional middle word(s) may provide context regarding purpose.
Last word(s) should indicate “functional type” of the class.
Ignore underscores in the related component’s name.
Be consistent!
Classes with the same functional type share the same suffix.
Reconsider the design of classes that do not fit a single functional type.
The following class types have additional naming rules, which are detailed on the following slides.
Triggers and Trigger Handler Classes
Visualforce Classes
Web Service Classes
Email Service Classes
Asynchronous Classes
Service Classes
Utility Classes
Model / Wrapper Classes
Test Classes
Variable Names
SObjects
Type of SObject should be clear by looking at name
Collections
Should always be plural!
Method Names
UseCamelCase…but the first character is always lowercase.
useCamelCase()
All should…
Use descriptive words.
Rapid clarity to others is important!
NEVER use single-character variables.
Objects
Fields
Custom Labels (*special rules)
All should follow these common rules
Always use underscores to separate words in API names.
The first letter of each word in API names should be capitalized.
Always match API names and Labels.
If you change the label, but haven’t deployed the code, do whatever you have to do to change the API name!
Agree on specific org-wide standards, patterns, and practices.
Define a regular Quality Control Cycle.
Determine necessary milestones to go from current state to “Day 1” of the QCC we define.
Determine a workable timetable for hitting these milestones.
Define, assign, and execute tasks.
Executive Endorsement (1 Week)
Finalize Style Guide (1 Day)
Finalize Architectural Standards (2 Days)
Finalize Naming Conventions (1 Day)
Org-Wide Code Audit / Data Model Analysis (1-2 Weeks)
Review Findings of Code Audit (2 Days)
Review Findings of Data Model Analysis (4 days)
Assign Refactoring and Data Model Cleanup Tasks (2 days)
Refactoring / Data Model Cleanup in DEV (3 – 4 Weeks)
Prepare Comprehensive Deployment Package (4 days)
Deploy and Test in Pre-Production Environments (1-2 weeks)
Validate Changes and Prep for Final Deployment (1 week)
Executive endorsement.
Finalize Style Guide.
Finalize Architectural Standards
Finalize Naming Conventions
Publish “Intuit Standards for Salesforce Development”
Expose standards to entire team
Begin bi-weekly code reviews
Execute org-wide code audit