Here are a few of the best practices I've develope

Jason Wood:
Here are a few of the best practices I’ve developed and have been using for a while. Thought this might be of interest to others.

In Global Before, set $$BF_Model_OUT to “{}” and update $$BF_State to set modelUpdateMode to “merge”
In Global After, set $$BF_Model to $$BF_Model_OUT
Why? Reduces the response payload to only the data that is changing, increasing performance and decreasing metered Data API usage.
Why?(2) When reading $$BF_Model, you always know it is exactly what came from the app, since you never mutate it until Global After.

App Load Flag
In Global Named Actions, in the onAppLoad action, add a function that sets model.firstLoad to true.
In Global Before, check for this, and if true, populate the app model, then add a function action to delete model.firstLoad
Why? This avoids having two utility hooks fire at the same time when the user first loads the app or refreshes the browser (assuming you need to do anything in onAppLoad on the FileMaker side).

Clear globals
At the top of Global Before, clear all global variables and field used in any FMBetterForms scripts. (You do not need to clear the $$BF globals)
Why? Globals can survive to the next request using the same token, even if it is a different user.

Email to lowercase
If using an older business file, add auto-enter ‘Lower(Self)’ to email field. Also update business file to ensure email addresses are always lowercase.
Why? ExecuteSQL is case sensitive, so if you want to match emails between the BF user table and the business file, they need to be the same case.

Anything in the model can be manipulated and $$BF_User is the only reliable way to confirm identity (unless you’ve built a token system), so any time you lookup information from the database, verify that the user in $$BF_User should be allowed to see that data. In Global Before, you can populate global variables to make these checks easier (primary keys of records the user may access, for example). Be sure to clear these globals at the beginning of Global Before so they can’t be passed into other requests.

^This is pretty good.

The model data can also be reduced with modelFilterKeys (See docs)
I often combine that with just deleting the passed in data vs global code that a given hook can’t override.

In addition to the onAppLoad you should also consider onLogin as this too could require app wide settings to change.

Globals: Be re-instantiates all globals it users. They can persist but get written over.
This happens in the receiver script near the top.

I love how best practices constantly evolve!

Jason Wood:
I was thinking as I wrote this that I also need to start using modelFilterKeys to reduce the incoming payload too!:wink:

onAppLoad & onLogin - yes, I actually do all the app load stuff in Global Before on the following condition (If):

JSONGetElement ( $$BF_Model ; "firstLoad" ) = True
JSONGetElement ( $$BF_Payload ; "hookName" ) = "onLogin"

and my onLogin script doesn’t do anything.

Globals - yes that’s why I said you don’t need to do it with the $$BF ones, but you do need to do it with anything else you create, and any global fields you use.

all I missed that part!

… and yes upstream data is also slower than downstream so has bigger impact.