Tips for making your apps more maintainable
In this blog, we will go over 10 tips that I find useful when building apps with PowerApps. They help me keep my app easy to read, debug and maintain. Hope you find them useful as well.
1. Avoid Nested If/Else statments
Suppose we have the following scenario: a news feed app with actionable cards. Pressing the card buttons can take you to another page, open another app, open your default browser or call a custom API.
To accomplish the scenario. The OnSelect Button would have the following logic:
as you can see, the above can be hard to read, test and maintain. In general nested if/else statements can makes it hard to read your code and therefore hard to debug and maintain. A possible simplification is to use a combination of Switch and LookUp as follow:
The above code is easier to read, you can easily add different type of actions. As you can see Switch helped in this case with readability. LookUp also helped reduce the complexity as we will see in the next tip.
2. Use Collections & LookUps
In the above example, we used a lookup to identify the correct screen to navigate to. Rather than doing an If/else on screen name, we used a look up to a collection (value pair) where our key was the screen name and the value is an actual reference to a screen. With this approach, it becomes easy to extend your app as you are adding more screens without have to update your OnSelect logic.
This approach works well in a number of scenarios. In our example, notice that the button style is different depending on the action type:
Here we define a collection locally but this can be obtained from an external source as well such as SharePoint or CDS.
The logic that select the correct style becomes a simple look in your style collection rather than a complex if/else statement:
3. Filter & Searching
Search and Filtering can easily lead to complex formulas specially as you add more filters. Consider this simple example of a photo gallery where you can filter photos by “My Photos” or “All Photos” , “Public” or “Private” and by a search parameter.
The typical implementation of the above example would be to be bind the Items property of a control to the following formula:
As you can see, this formulas above are becoming hard to read and maintain. Any additional filters will make things even more unreadable. Another option to reduce the complexity is delegate the filtering and searching operation to the individual dropdowns and search box respectively. In that case, our Items property will be bound to a simple and easy to read formula as follow:
As you can, it becomes this is easier to read and maintain. We are constructing individual filtered collections and taking the intersection of the items to bind to our items property. Adding and removing filters becomes easy. In this example, publicPrivateFilteredPhotos is constructed in the OnSelect event for the corresponding dropdown. We are effectively breaking the complexity in chunks and assigning it to individual controls.
It’s worth noting that the above method has some drawbacks as well. First, it will only works if the filter operation returns less than 2k items (which is the max a clearcollect will hold for each API/data source call). The second disadvantage is that you are allocating a collections for each filter. You have to ensure that those collections are properly initialiazed in the OnVisible or OnStart events.
4. Optimize formulas
Another area that is worth spending sometime optimizing is around formulas. Let’s start with a simple example which I surprisingly see often in my code reviews:
The above can be optimized by nothing that doing filter operation and taking the first item is almost always equivalent to doing a LookUp
The advantage of doing a LookUp is that only 1 item will result in a smaller payload from your data source which will result in a faster experience. Filter on the other hand might download a collection of items (larger payload size) for which you are only going be taking the first item which is not optimal. Other than the performance implication, more compact formulas can improve the readability of your app as well.
5. Avoid API calls within your Filter or LookUp expressions
Another formula optimization consist of avoid nesting API calls in Filter or LookUp Operation. Here is an example where are performing filter operation width a condition requiring an API Call. In this case to the Office365 API.
A better approach that would result in better performance is to set a variable and then re-use it within your filter operation.
The above will be easier to read specially if you give your variable a meaningful name (currentUser reads better than Office365Users().MyProfile().Mail)
6. Avoid multiple calls to server
Along the same lines of the above 2 examples, caching a single item locally and referencing it will ended up improving your perf but will also result in more compact formulas. The following statements will perform poorly since we are making multiple calls to our backend to retreive the same object.
On the other hand, the first statement here will fetch the entire object and save it locally. Subsequent calls will simply refer to the local object.
7. New/Edit Pattern
Another way to simplify your app is to avoid using multiples screens to perform CRUD (Create, Update, Delete) operations. So if you come across something like this:
you can take the following approach to combine the above to screens:
In your gallery (for example), notice how I am setting a variable depending whether I intend to do edit an item or create a new item.
I can then simply Patch my Customer table in this case as follow:
The controls in this screen are bound to the customer variable regardless of whether this is a new item (Defaults(‘Customer Issue’)) in which case all the fields will be blank or an existing item in which case my controls default will be set automatically.
8. Avoid hard coding app content
Hardcoding your content can also makes your app hard to read, maintain and localize. You can keep all of your content in an external source such as SharePoint or Common Data Service. If your content is static and unlikely to change, then embedding an excel sheet is going be the most performant option as you will avoid a network call to get your content.
Here is an example of a long string. As you can see, the app becomes harder to read and you might see some performance issues in the maker experience (web authoring) as formulas and statements gets evaluated:
Instead, you can put all your Settings in external source and use substitutions techniques detailed in this blog to inject contextual app data: https://powerapps.microsoft.com/en-us/blog/html-markup-with-dynamic-data/ “
9. Passing Context Variable
When passing data between screens, I tend to use a context variable within the Navigate function as follow:
HomeScreen -> Gallery -> OnSelect
I found that this approach leads to cleaner “code” as you remove the dependency on UI elements (a gallery in this example) which might or might not be your only entry point to the next screen. For example, your app might need to enable deep-linking to detail screen as a result of a push notification. In that case, you would set the same context variable (selectedItem) and everything in the DetailScreen would remain the same (if you had relied on something like Gallery1.Selected, you would have to introduce some additional logic to enable the deep-linking scenario as well)
HomeScreen –> OnStart
10. Use a Gallery control when you can !
As mentioned in my previous blog post https://powerapps.microsoft.com/en-us/blog/performance-considerations-with-powerapps/ under Control optimization section, reducing the number of controls in your app can lead to a better authoring experience but can also lead to an easier to read and maintain app. If you have a menu system in your app, then consider using a gallery control for that. If you are using a Canvas control, take another look at your data cards. Are they similar ? can you use a gallery control instead and toggle visibility of certain elements ?