cancel
Showing results for 
Search instead for 
Did you mean: 
EricRegnier

Best practices when customizing Power Platform and Dataverse

In my last article about Power Platform best practices, the tips covered the configuration aspect using out-of-the-box capabilities (i.e. low/no code). In this one, I touch on the best practices extending Power Platform and Dataverse with customizations. This is aimed more for pro-developers or anyone using code (e.g. C#, JavaScript). Like in the previous article, these guidelines are based on past experiences and projects, and also from common questions/mistakes seen in the community.

 

#

Guideline

Brief Rationale

1

Choose low code/no code approach over customizations (code). This may sound obvious but it’s easy to fall back on old ways and methods that we’re conformable with. Examples:

  • Power Automate flows can handle a lot of logic that previously plugins would do
  • Use embedded canvas app or custom pages instead of custom HTML web resources
  • Business Rules as opposed to JavaScript for show/hide logic or setting field values

Adds value quicker to the business

 

Less maintenance effort

 

Easily adopt new features

 

More likely to have upgrade path and less likely to break with upgrades and API changes

2

Should server-side logic be required, leverage Azure Functions with Azure aware plugins instead of traditional plugins when (but not limited to):

  • Plugin is subject to take longer than 200ms to execute
  • Integration with external systems or APIs
  • Need to reference 1st/3rd party assemblies like KeyVault or Newtonsoft

Note: Sync operations with Azure Functions is possible with webhooks 😊

 

More info: https://docs.microsoft.com/powerapps/developer/data-platform/azure-integration

Better scalability

 

Can handle long running processes

 

Azure stack becomes available

 

Better monitoring

3

Prevent all-purpose plugins (traditional and Azure aware). Scope plugins to perform a single task based on a clear set of inputs and outputs. Select only the required columns for the step/trigger and for pre/post images. Example:

 

Not desirable

Desirable alternative

Single PostOperationAccountUpdate plugin which is responsible to do all post-op type of operations on accounts. Branching is done within the plugin handler.

ValidateAccountAddress which is sync on create/update of address specific columns

 

PopulateDefaultAccountValues which is async on create

With the 2nd approach, we have a clear idea what the plugins are doing, and we have the flexible to have different plugin step configuration for each.

Better scalability and flexibility

 

Better performance as async plugins can run in parallel

 

Better maintainability

4

Use Custom API instead of custom workflow activities or custom actions which also provides more flexibility.

Workflows are getting phased out

 

Better flexibility

5

Limit the data retrieved from the APIs or SDK calls by:

  • Prevent selecting all columns (Columns.All or select whole entity in Linq)
  • Use inner joins as opposed to outer
  • Omit ordering clause if not required
  • Avoid distinct if not required, try to apply the right filtering/joins instead

More info: https://docs.microsoft.com/powerapps/developer/data-platform/best-practices

Better scalability and performance

 

Less code smells

6

Reference dependent web resources with the dependency feature instead of adding them to model-driven forms or ribbon.

 

More info: https://docs.microsoft.com/dynamics365/customerengagement/on-premises/developer/web-resource-depende...

Dependencies traceability

 

The system does not guarantee the load order

 

Better performance

 

7

Be aware of the deprecated client scripts (e.g. Xrm.Page) or messages. Recommend reviewing these under a regular frequency.

Deprecated list: https://docs.microsoft.com/power-platform/important-changes-coming#some-client-apis-are-deprecated

 

Tip: Using Solution Checker with help to detect those 😊

Better performance

 

More likely to have upgrade path and less likely to break with upgrades and API changes

8

Use the async pattern when writing JavaScript/TypeScript to reduce chaining and complexity. For example (taken from MS docs)

Xrm.WebApi.retrieveMultipleRecords("account", "?$select=name&$top=3").then(
    function success(result) {
        for (var i = 0; i < result.entities.length; i++) {
            console.log(result.entities[i]);
        }                    
        // perform additional operations on retrieved records
    },
    function (error) {
        console.log(error.message);
        // handle error conditions
    }
);

Can be rewritten like this:

try {
    let result = await Xrm.WebApi.retrieveMultipleRecords("account", "?$select=name&$top=3");
    for (let entity in result.entities) {
        console.log(result.entities[entity]);
    }
    // perform additional operations on retrieved records
}
catch (error) {
    console.log(error.message);
    // handle error conditions
}

Which one is more readable?

 

Note: Model-driven apps now support awaiting for async OnLoad and OnSave events.

Better maintainability, cleaner code that’s easier to read

9

Might seem strange but do not use ExecuteMultipleRequest or ExecuteTransactionRequest in traditional plugins due to their overheard and plugin execution limit. Performance of these messages are gain more in external processes.

More info: https://docs.microsoft.com/powerapps/developer/data-platform/best-practices/business-logic/avoid-bat...

Better Performance

 

Supporting documentation and additional readings:

https://docs.microsoft.com/powerapps/developer/data-platform/best-practices

https://docs.microsoft.com/power-platform/alm

https://docs.microsoft.com/power-platform/guidance

Comments