Apex Design Patterns
Apex Design Patterns
marketing + technology 701.235.5525 | 888.9.sundog | fax: 701.235.8941 2000 44th st s | oor 6 | fargo, nd 58103 www.sundog.net
The Force.com platform is a new platform, and while the Apex programming language is syntactically similar to Java, the way you use it and the rules you must follow are very different. The best practices and design patterns that apply to Java may not apply to Force.com and the Apex language. That does not mean that none of the same principles apply. Many of the best practices you would use in Java can apply to Apex. General rules around efcient coding like limiting database queries and minimizing loops still apply. In this paper, Ill share what I have found to be the best practices and good design patterns through the multiple development projects Ive been a part of.
When I say native functionality, Im referring to the toolset that Salesforce gives you, and that you dont need to write code to implement. Things like validation rules, workow, and formulas can let a developer implement functionality that would require much more time to implement in Apex. Validation rules allow a developer to put conditional requirements on just about any elds or objects in Salesforce. So, for example, if you wanted to require a eld called Email Format Preference to be populated if the Email Opt-In checkbox was selected, but not require it if the Email Opt-In checkbox wasnt selected, you could do that easily with a validation rule. A developer could write the validation rule in a few minutes, whereas the exact same functionality using Apex would require a trigger to be written, along with unit tests, and would take signicantly longer. When implementing simple business logic, consider using Workow instead of writing code. Workow can be used to perform a conditional action on an object. From Workow, you can send emails, create tasks, and update elds on the same object. Workow actions can also be set to execute at future times.
This trigger will work ne as long as only one record is being passed in at a time. If we receive a bulk update to Accounts, we will run into an error because of governor limits that restrict the amount of queries and updates were allowed to do in one transaction. To correct this, we need to assure the update statement is performed on a collection of accounts instead of each account individually. Consider using the following code instead:
While the above code is more complicated, and appears to be more process intensive (due to additional loops and processing), it is actually better in the Apex world. The database interactions have been taken out of loops and only one update statement is made regardless of how may records are processed. The above code also demonstrates another best practice for Apex, which is never to put SOQL queries inside of loops. Doing this allows the same query to be executed multiple times and creates the possibility of breaking another governor limit. Notice in the top part of the example we have the following nested loops:
This causes the query inside the second loop to be executed as many times as accounts that are being processed, which could potentially be quite a few. We correct this problem in the second part of the example by adding the accounts to a map. We then use the map to query all the child accounts we may need to process with one query.
Batch Apex
If you need to update a large data set, and dont need it to happen in real time, consider using batch Apex to perform the logic. To use batch Apex, you write a class that implements the Database Batchable interface. This class will contain a start, an execute, and a nish method. Each pass through the execute method has the governor limits reset. So, for example, if you do not specify a different scope, the governor limits will reset after every 200 records that are being processed. This allows for processing of a lot of records, without hitting governor limits. Here is an example of a batch Apex class from the Salesforce Developers Guide:
The above code works, but a better way to do it would be to use a single query to retrieve all the information needed:
You could then use the above class to tell one trigger the update is coming from another trigger and it should not execute. To do that, put the following code in your trigger that is performing the update, just before the update:
Then, put this check in the second trigger to determine if the update came from the rst trigger:
Setting up a method to be asynchronous is easy. You simply add the @future denition above the method declaration. For example:
When the above method is executed, it would be placed into a queue and executed when resources are available. A couple of things to note are that asynchronous methods must always be static and cannot return anything. And, you can only pass primitive data types into an asynchronous method. If you try to pass an object, like Lead or Account, you will receive an error.
attempt to update a record that is currently being updated by the mass data load, or vice versa. For example, lets say we have a trigger on accounts that makes a call to an asynchronous method that updates all other accounts with the same parent account. If we were to do a mass update to accounts, we may end up updating an account that calls the future method, which in turn updates all the accounts with the same parent account. If the next batch in the mass update contains another account with the same parent account, it may try to update that account at the same time the asynchronous method from the previous batch tries to update that account, and you will receive an error that says something like unable to obtain exclusive access to this record. For this reason, I recommend trying to avoid asynchronous calls that update related records of the same object type. If possible, perform the logic synchronously inside the trigger, or consider using scheduled jobs or batch Apex to perform the logic.
Some of the reasons to use asynchronous Apex are when you need to perform actions that require a lot of processing, or database interactions
Some of the reasons to use asynchronous Apex are when you need to perform actions that require a lot of processing, or database interactions. It can be used to perform updates to a record shortly after it has been inserted. When you use triggers, which are synchronous actions, you need to either perform any logic that will update the record before the insert. The problem is you dont yet have the id for the new record. You can get the id of a new record on an after trigger, but you wont be able to change the record at all. If you need the new id, and want to perform an update to it, you will most likely have to use asynchronous code. There are some reasons to avoid using asynchronous Apex in your applications. One reason is you have a limited amount of asynchronous calls you can make in a 24-hour period. The limit is 200 future method calls per user license, per 24-hour period. If you exceed this limit, you will receive an error every time an attempt to make an asynchronous call is made. This can be detrimental if you have triggers that are commonly used and make asynchronous calls. Another thing to watch out for when using asynchronous Apex is attempting to update a record in an asynchronous method at the same time it is being updated synchronously. This commonly happens when you are doing mass updates to records that use asynchronous methods to update other records of the same type. The method will
The above code checks to see that the number of DML rows you have used, plus the number of records in a list you want to update, are less than the maximum amount of rows you are allowed to process in a single transaction. It will update the rows if you are within your limit, or do something else, perhaps use an asynchronous call, if you are going to go over your limit.
It also gives you exibility to create various scenarios to ensure your code will work under all sorts of conditions. Always use assert statements to ensure your test yielded the results you expected. It is possible to get very high code coverage without actually testing anything. Line coverage can be gained by having your code execute and not throw an exception. However, you wont have any idea if it actually worked if you dont have assert statements to prove the results were expected. Remember, unit testing is critical to writing good, maintainable applications, and should never be skimped on.
10
Constructing your tests this way not only allows the code to run with the governor limits in place, it will be held to in real world execution, but it also is the only way to test asynchronous code. Invoking the asynchronous call after the startTest() method, and before the stopTest() method will allow all of the asynchronous code to complete before running the assertion statements and allows you to properly test your code from asynchronous methods.
11
Separating your unit tests like this can also make your application more maintainable by putting all the unit tests in a central location. Another helpful tip would be to come up with a standard naming convention for test classes to make it easier for future developers to nd them.
Conclusion
Apex is still a relatively new programming language, and for that reason it can be difcult to get started programming properly. Many of the principles of other languages hold true for Apex, but some others do not. The ideas presented here will no doubt change over time as Apex matures and new features become available. I believe documentation for design patterns and best practices in Apex is still scarce, so hopefully I have given you some ideas you can use in your applications to make them more stable, maintainable, and functional.
12
References
Albert, Andrew (n.d.). Apex Code Best Practices. Developerforce. Retrieved November 2010 from http://wiki.developerforce.com/index.php/Apex_Code_Best_Practices Albert, Andrew (n.d.). Best Practices for Apex Code: Lessons from the Trenches. Retrieved November 2010 from http://www.salesforce.com/dreamforce/DF09/pdfs/ADVD008_Albert.pdf Salesforce.com (n.d.). Understanding Execution Governors and Limits. Retrieved November 2010 from http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_gov_limits.htm Salesforce.com (n.d.). Force.com Apex Code Developers Guide Version 20.0. Retrieved November 2010 from http://www.salesforce.com/us/developer/docs/apexcode/index.htm
13