Friday, 28 February 2014

Force.com Programming Best Practices

Wes and I are adding a few more topics to our Salesforce Handbook before we put it to bed and I thought a great topic would be programming best practices. I’ve never seen a “complete” list of best practices so I thought I would put something together based upon my experiences. I know I’ve left some out, so if you have any to add, please chime in and we may include them in the book.
Apex
  • Since Apex is case insensitive you can write it however you’d like. However, to increase readability, follow Java capitalization standards and use two spaces instead of tabs for indentation.
  • Use Asychronous Apex (@future annotation) for logic that does not need to be executed synchronous.
  • Asychronous Apex should be “bulkified”.
  • Apex code must provide proper exception handling.
  • Prevent SOQL and SOSL injection attacks by using static queries, binding variables or the escapeSingleQuotes method.
  • When querying large data sets, use a SOQL “for” loop
  • Use SOSL over SOQL where possible – it’s much faster.
  • Use Apex Limits Methods to avoid hitting governor exceptions.
  • No SOQL or SOSL queries inside loops
  • No DML statements inside loops
  • No Async (@future) methods inside loops
  • Do not use hardcoded IDs

Triggers
  • There should only be one trigger for each object.
  • Avoid complex logic in triggers. To simplify testing and resuse, triggers should delegate to Apex classes which contain the actual execution logic. See Mike Leach’s excellent trigger template for more info.
  • Bulkify any “helper” classes and/or methods.
  • Trigers should be “bulkified” and be able to process up to 200 records for each call.
  • Execute DML statements using collections instead of individual records per DML statement.
  • Use Collections in SOQL “WHERE” clauses to retrieve all records back in single query
  • Use a consistent naming convention including the object name (e.g., AccountTrigger)

Visualforce
  • Do not hardcode picklists in Visualforce pages; include them in the controller instead.
  • Javascript and CSS should be included as Static Resources allowing the browser to cache them.
  • Reference CSS at the top and JavaScript a the bottom of Visualforce pages as this provides for faster page loads.
  • Mark controller variables as “transient” if they are not needed between server calls. This will make your page load faster as it reduces the size of the View State.
  • Use <apex:repeat> to iterate over large collections.
  • Use the cache attribute with the <apex:page> component to take advantage CDN caching when appropriate

Unit Testing
  • Use a consistent naming convention including “Test” and the name of the class being tested (e.g., Test_AccountTrigger)
  • Test classes should use the @isTest annotation
  • Test methods should craete all data needed for the method and not rely on data currently in the Org.
  • Use System.assert liberally to prove that code behaves as expected.
  • Test each branch of conditional logic
  • Write test methods that both pass and fail for certain conditions and test for boundary conditions.
  • Test triggers to process 200 records – make sure your code is “bulkified” for 200 records and doesn’t throw the dreaded “Too many SOQL queries: 21″ exception.
  • When testing for governor limits, use Test.startTest and Test.stopTest and the Limit class instead of hard-coding governor limits.
  • Use System.runAs() to execute code as a specific user to test for sharing rules (but not CRUD or FLS permissions)
  • Execute tests with the Force.com IDE and not the salesforce.com UI. We’ve seen misleading code coverage results when running from the salesforce.com UI.
  • Run the Force.com Security Source Scanner to test your Org for a number of security and code quality issues (e.g., Cross Site Scripting, Access Control Issues, Frame Spoofing)

Announcing Force.com Tooling API for Node.js (nforce)

Over Christmas break I stared playing around with the Force.com Tooling API in node.js. We have some ideas over at topcoder for the Tooling API and I wanted to build a POC to see how crazy I was.
After a couple of days I started to realize how cool the Tooling API could be and the development impact it could make. I’ve always been big fan and user of Kevin O’Hara‘s nforce package so I emailed him to see if he would be interested in including it in nforce. After a few emails we decided to go the Passport route and implement the new functionality with plugins that could be developed and maintained independently and not “muddy-up” the core nforce package. Brilliant! My guess is that there are more plugins coming down the road for nforce ;).

So while Kevin essentially rewrote nforce (added plugin functionality, improved performance, simpler signatures, etc), I worked on the nforce-tooling plugin. I did most of the work while on my vacation in Jamaica (you can only lay around in the sun drinking daiquiris for so long!) and finally release version 0.0.1 this morning.

Github repo: https://github.com/jeffdonthemic/nforce-tooling

Like anything else with Salesforce.com, it’s a work in progress as the Tooling API revs. I’ll be adding more features as they become available but please send me any issues or pull requests. I’ll be writing a few tutorials in the near future but for some sample code see the mocha tests. See the github readme for complete info.

The 0.0.1 plugin supports the following functionality:

createContainer() – Creates a container as a package for your workspace that manages working copies of Tooling objects, including collections of objects that should be deployed together.

getContainer() – Returns a container.

addContainerArtifact() – Adds an artifact to the container for deployment. The artifact object links the container, to the saved copy of the object (e.g., ApexClass), to the working copy of the object (e.g., ApexClassMember) for deployment.

deployContainer() – Compiles and deploys a container.

getContainerDeployStatus() – Returns the deploy status of a container.

deleteContainer() – Deletes a container.

getObjects() – Returns a collection of available Tooling API objects and their metadata.

getObject() – Returns the individual metadata for a specified object.

getRecord() – Returns high-level metadata for a specific object. For more detailed metadata, use getDescribe().

getDescribe() – Returns detailed metadata at all levels for a specified object.

getCustomField() – Returns the metadata on a custom field for a custom object. Includes access to the associated CustomField object in Salesforce Metadata API.

query() – Executes a query against a Tooling API object and returns data that matches the specified criteria.

insert() – Creates a new Tooling API object.

update() – Updates a Tooling API object with the specified data.
 
delete() – Deletes a Tooling API object..

executeAnonymous() – Executes some Apex code anonymously and returns the results.

getApexLog() – Returns a raw debug log.