ADR-16: Unity data store architecture

More details about this document
Latest published version:
https://adr.decentraland.org/adr/ADR-16
Feedback:
GitHub decentraland/adr (pull requests, new issue, open issues)
Edit this documentation:
GitHub View commits View commits on githistory.xyz

Context and Problem Statement

In many use cases, we have a lot of data that needs to be accesed on almost a project-wide (or module-wide) scope.

This need brought us to define a standarized approach for data storage.

This approach should cover the following use cases:

In the current state, this kind of necessity is covered by a few static classes wrapped around Unity ScriptableObjects.

Each of field of the static class is a variant of a custom BaseVariable type.

The BaseVariable wraps around a value and gives us OnChange events.

public static class CommonScriptableObjects
{
    private static Vector3Variable playerUnityPositionValue;
    public static Vector3Variable playerUnityPosition => GetOrLoad(ref playerUnityPositionValue, "ScriptableObjects/PlayerUnityPosition");

    private static Vector3Variable playerWorldPositionValue;
    public static Vector3Variable playerWorldPosition => GetOrLoad(ref playerWorldPositionValue, "ScriptableObjects/PlayerWorldPosition");

    private static Vector3Variable playerUnityEulerAnglesValue;
    public static Vector3Variable playerUnityEulerAngles => GetOrLoad(ref playerUnityEulerAnglesValue, "ScriptableObjects/PlayerUnityEulerAngles");

    private static Vector3Variable playerUnityToWorldOffsetValue;
    ...
}

Using ScriptableObject instances like this has the following boons:

However, we are looking at these downsides too:

Considered Options

ScriptableObject-based data storage

We have a data storage of BaseVariables that inherit from ScriptableObject (SO). Adding a new field would involve adding a new asset to the project and wire a new GetOrLoad call with the resource path, as we are doing now.







G



Systems

Systems



Data

Data



Systems->Data





Assets

Assets



Data->Assets





Boundary agnostic data storage

We have a data storage of BaseVariables that are either an interface or a plain old C# object (POCO). On the side, we have a specific ScriptableObject-based BaseVariable implementation. This will give us the versatility of choosing between POCO and the ScriptableObject version on a per-use basis.







G



Systems

Systems



Data

Data



Systems->Data





Assets

SO BaseVariable



Data->Assets





Data_State

POCO BaseVariable



Data->Data_State





Decision Outcome

We choose to be boundary agnostic because this will give us the versatility of using the best approach for any situation. We discussed that in case of going for POCO and needing an SO later, the need refactoring work would be very low.

By choosing to deliberately use a data store pattern, we can name it accordingly and define the system responsibilities in a more direct way than we have now.

Also, we have the added benefit of a more cohesive design between Kernel and Unity, because Kernel already has the redux data store concept.

Participants

License

Copyright and related rights waived via CC0-1.0. Living