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