Lack a proper form of dependency injection as custom constructors can't be used.
They foster usage of AddComponentGetComponent and GetComponentInChildren. The issue is that those methods have performance issues.
As they lack a proper form of DI, they can't be tested properly.
Also, they lack a well implemented lifecycle. I'm going to enumerate a few of the issues here:
Destroy has a single-frame delay. This single-frame delay is the root cause of many bugs caused by race conditions.
The OnDestroy event method is run when the application is stopped on Editor, causing unneeded errors that are actually noise and can on the worst cases can cause editor crashes. - The Update event method has a well known performance issue that comes from the C++ <> managed code interoperation.
Comparison operators that are run over MonoBehaviours are slower than the POCO objects and don't work well with the null coalescing and null-conditional operators.
There is not a good way of handling the order of initialization for created MonoBehavior objects, Awake() calls are mostly random, they can be managed from the Script Execution Order menu, but this menu implementation is clunky at its best, unusable at its worst. This lead to anti-patterns where the contributor has to implement Start() for objects that has implicit dependencies for another object that's defined on its Awake() call.
To prevent these issues, we aim to implement the following policy:
Most of the features entry point should come from a plain old C# object.
MonoBehavior shouldn't be used, with the exception of views and features where we need to use prefabs and there's no good other way of accomplishing the feature without them.
In all the other cases, business logic should run mainly on plain old C# objects, and rely on composed MonoBehaviour objects for fetching scene references and handling prefabs.
Actionables:
[ ] Remove SettingsController from InitialScene
[ ] Remove NavMap from InitialScene
[ ] Remove Bridges from InitialScene and make the bridges instanced at runtime
[ ] Remove HUDController from InitialScene
[ ] Remove HUDAudioHandler from InitialScene
[ ] Remove CameraController from InitialScene and make it a prefab that's loaded at runtime.
[ ] Remove CharacterController from InitialScene and make it a prefab that's loaded at runtime.
Problem Statement
MonoBehavior
has the following issues:AddComponent
GetComponent
andGetComponentInChildren
. The issue is that those methods have performance issues.Also, they lack a well implemented lifecycle. I'm going to enumerate a few of the issues here:
Destroy
has a single-frame delay. This single-frame delay is the root cause of many bugs caused by race conditions.OnDestroy
event method is run when the application is stopped on Editor, causing unneeded errors that are actually noise and can on the worst cases can cause editor crashes. - TheUpdate
event method has a well known performance issue that comes from the C++ <> managed code interoperation.MonoBehavior
objects, Awake() calls are mostly random, they can be managed from theScript Execution Order
menu, but this menu implementation is clunky at its best, unusable at its worst. This lead to anti-patterns where the contributor has to implementStart()
for objects that has implicit dependencies for another object that's defined on itsAwake()
call.To prevent these issues, we aim to implement the following policy:
MonoBehavior
shouldn't be used, with the exception of views and features where we need to use prefabs and there's no good other way of accomplishing the feature without them.MonoBehaviour
objects for fetching scene references and handling prefabs.Actionables:
SettingsController
fromInitialScene
NavMap
fromInitialScene
Bridges
fromInitialScene
and make the bridges instanced at runtimeHUDController
fromInitialScene
HUDAudioHandler
fromInitialScene
CameraController
fromInitialScene
and make it a prefab that's loaded at runtime.CharacterController
fromInitialScene
and make it a prefab that's loaded at runtime.