General Guidelines

ActiveJS doesn't concern itself with how or where it gets used, it's intended to be immersed in your development workflow and practices. It's just an improvement over already existing native data structures, and more powerful than a simple Observable or Subject.

The whole point of ActiveJS is to provide a non-intrusive and non-disruptive State Management solution that just fits in, without drawing too much attention to itself.

However, for the sake of having an official guideline, and to avoid some problems that we've identified, which you might run into at some point, you can follow this guideline.

Don't mutate the state

To get predictable and reliable cache navigation, otherwise, you would get unexpected results.

To avoid view-rendering problems in your framework of choice. You might be expecting your framework to detect a change and render it, but since you mutated the value, the framework can't know whether there's a change or not.

To make things more predictable in general, since you can be sure that once you dispatch a value to a Unit, it's not going to change until you dispatch a new value again. Which can help avoid a lot of bugs.

A simple solution to avoid mutating the state is to make your Units immutable. See Immutability.

Don't put non-serializable values in Units

For persistent Units, you should always make sure that the value of the Unit is serializable, otherwise, the information will be lost in serialization, which is done for storing the value into LocalStorage.

ActiveJS Units can only clone simple serializable objects, so if you're relying on immutable Units to provide a clone, that won't happen for non-serializable objects.

It's generally a good idea to not use non-serializable objects like Date, Map, Set, DOM-Element, etc. in your state for predictability and simplicity. However, if you are not using persistence, immutability or cache-navigation, in rare cases it's probably okay to do so, and ActiveJS shouldn't have a problem with it.

Keep shared things in a separate file

To avoid cyclic dependencies while still having the freedom to pull in data from different files and services, you must put the shared Units, Actions, Streams, Systems, or Clusters in a dedicated, shared file or service.

Keeping the Streams in a separate file alone will help avoid most of the possibilities of having a cyclic dependency. Since the Streams tend to interact with a lot of other instances of Units, Action, or Systems; keeping them in separate files will ensure that you don't import something into a file that has a Stream, which is importing something from the said file.

Try to keep the related Units, Actions, Systems, or Clusters as close as possible, to avoid fragmentation that's hard to keep track of. Keep the related Streams together as well, but as pointed out earlier, try to keep them away from Units, Actions, Systems, or Clusters.

Keep the streams simple

Streams are supposed to make complex things easy, but if a Stream starts to have too many dependencies or unrelated side-effects embedded into it, then it has the potential of making the Streams incomprehensible and hard to debug.

When you create a Stream on AsyncSystem to populate its data, you should try to not have other unrelated side-effects in that Stream, try to keep it as simple as possible. If you need to have side-effects, you can create new Streams on AsyncSystem's Units e.g.: dataUnit, errorUnit