Best Practices
Design your system first
Create and overview diagram of your system before plunging into coding. It will be easier to understand the model.
Use one synchronous node as a controller when possible
Coordination of a design is preferably done by synchronization of one-time domain. The controller time domain will be the one that activates other asynchronous nodes through propagation of data. For example, a controller will write a step on a port connected to a asynchronous stepper driver node, which will receive a change event and act only when the data has changed.
It's possible to have many synchronous nodes, however care must be taken to properly synchronize data propagation.
Decouple large functionality in many nodes
When dealing with a complex node, it might be better to extract reusable functionality from that node into simpler nodes. This will make the design more modular and easier to understand visually.
Don't be afraid to iterate
Iterate your design until you achieve the proper level of details and functionality you wish for. You can plan an overview of the system and adjust the design incrementally, that way you will achieve results faster and be able to work on smaller chunks without being overwhelmed.
Enable a standalone build
When creating a IL2CPP build, you must add the [assembly: Preserve] attribute to at least one script in the assembly that exposes NodeRuntimes to SystemGraph. SystemGraph creates nodes by reflection, and IL2CPP doesn't see the dependency to certain calls and might remove the dependency during optimization.
For example, the following is an example of the assembly insertion into a generic node file:
using UnityEngine.Scripting;
[assembly: Preserve]