I’ve had the opportunity to experience some of the pros and cons of various coding styles and techniques over the years. Over time I myself have performed code reviews not only to address performance, but also to resolve execution failures that were not openly obvious. Below are some of the things I try to keep in mind whenever I sit down to look at code on a project.
- Refactor deprecated API calls
- Review list of new API’s and usage with development team when upgrading
- Move late bound string literals of entity and attribute names into constants
- Ensure plugin code is written for stateless execution
- Remove use of class level variables
- Do not attempt to cache variables in memory; constants are okay
- Ensure service insert or update calls do not reuse existing entity objects and instead use new entity objects with only the required fields for the operation.
- End result is columns that do not need to be changed or updated are impacted
- Possible business logic triggered
- Create a new entity and only assign the attributes you intend to update
- Creates inaccurate audit history records
- Use attribute filtering for triggering plugins and workflows to fire as much as possible
- Refactor code that fires on child records that attempt to update a common ancestor record
- Refactor code that retrieve information for the target record in a plugin to use pre and post images
- Developers should instead leverage provided context mechanisms such as Input/OutputParameters and Pre/Post Event Images to access primary entity data.
- Be mindful of and coordinate cascading business logic execution paths
- e.g. Plugins that may cause other plugins and workflow to fire
- Review base class(es) used by plugins/workflows to ensure some component of the event pipeline isn’t being reference by a non-threadsafe member
- Only retrieve the minimum necessary attributes for a business operation to perform its task
- Check for queries for usage of AllColumns()
- In general lean towards synchronous execution over asynchronous to avoid system overhead
- Optimize expensive code when possible
- Code that queries large amounts of data
- Code that queries a data set that continues to grow over time (sneaky performance impact)
- Loops that query data on each iteration
- Optimize expensive loops
- Avoid repetitive field or property access
- Replace recursion with looping
- Use For instead of ForEach in performance-critical code paths
- Exercise extreme caution with code that programmatically
- Updates system users’ records, team memberships, security roles, business units
- Creates new business units, teams, security roles
- Use the string builder object when concatenating strings in loops
- Refactor code that inappropriately doesn’t use CRM query paging to retrieve more than the default 5,000 records on a retrieve
- Refactor code that updates the primary target entity in a post execution event
- Potentially causes an infinite loop
- Refactor use of non-cross-browser compatible code such as ActiveX objects in JavaScript
- Avoid use of modal dialogs
- Chrome and FireFox have deprecated support for modal dialogs. CRM is being updated to eliminate all usage of modal dialogs
- Replace all calls to alert(), confirm(), window.open (“”, “”, “modal=yes”), and window.showModalDialog() with an alternate user experience
- Use Xrm.Utility.alertDialog() and .confirmDialog() as viable alternatives to window.alert()/confirm()
- Do not use window.openStdDlg() which is an internal CRM function and considered unsupported.
- Change all HTTP requests to send asynchronously
- Sending sync requests will block the UI thread and negatively impact user experience due to a non-responsive window.
- Implement an async request with callback handler function pattern.
- Form multiple, dependent requests you can chain subsequent requests in previous request callback. If this becomes too complex, consider implementing the promise or final state machine pattern.
- Refactor use of object properties in loop controllers to use a variable instead
- Don’t create each plugin in for your solution in a separate solution (rather annoying)
- When creating a new entity allow the system to generate the GUID’s instead of creating them yourself in code.
- This will allow SQL to create sequential GUID’s which can be indexed easier.
- When referencing web resources use relative paths to allow for caching
- Explicitly call the close or dispose methods of disposable objects created during execution before they fall out of scope to minimize the life of the object in memory
- This applies to things such as database connections, message queue handles, file handles, etc.
- Either use try/finally blocks or using statements
- Write code that avoids the use of exceptions to control program logic
- Throwing exception as a general coding practice can cause performance issues
- Ensure plugins only use InvalidPluginExceptionExecution to report exceptions to the platform
- The CRM platform introduced cross-browser compatibility in CRM 2011 UR12 so don’t use browser specific API’s
- Use feature detection instead of browser detection in client side code
- Look for opportunities to use business rules for real-time workflows that perform a lot of updates.
Image may be NSFW.
Clik here to view.
Clik here to view.
