Wednesday, July 31, 2019

Design Guidelines for New Patterns, Architectures and Principals.

I've spent a while considering and clarifying internal rules I apply to selecting and designing new patterns to apply to code projects.  I've reflected in particular on what makes projects more sustainable over time and what keeps them fun to work on.  I wanted to share these out and get feed back.  Please let me know what you think, disagreements, likes, recommendations or clarifications?


DVS's Pattern Design Guidelines Version 1


1.  I want any architecture to offer simple implementation.  I.e. Observable<IType>.Set(this); would be a great short line to make an instance globally accessible, while other solutions might require 5 lines to setup.

2. I want the architecture to allow me to focus on the fun parts of programming.  I still want to solve problems without stressing over how to make it fit in an existing architecture, or requiring boiler plate code.  Typically, any thing a class does that doesn't influence other classes, can do WTF it wants.  (E.g. a script that makes a button shake when a its is clicked and disabled)  But any communication from class to class needs should have some level of standards.

3.  I want it to avoid edge cases.  Any "flexibility" I add to an architecture, that will only work in one case, or one spot in the code, should probably not be part of the core architecture, but should find itself more closely tied to the class or purpose that needs it.

4.  I want the architecture to be small in size, easy to understand, and easily documented.  If an architecture (of which there will likely be multiple) is hard to document in one power point page, its probably overly complicated.  If the architecture setup requires a dozen files, it is probably too complicated to deal with upkeep and any future redesign.

5. An architecture should be easy to change.  If only a couple core architectures are used, and the code/concepts are easy to work with/well defined, then a future understanding that requires a different architecture should be easier to implement.  Its a little hard to define, but throwing out core architectures usually makes people want to throw out the entire code base and start over.  I find this often is because edge case uses of the architecture, and Step 6 might clarify this more.

6. It should have only 1 clear way to resolve a clear problem.  Things like Dependency Injection might have multiple ways to bind, such as bind to an instance, bind to a type, create as singleton, create as pool, etc...  But for creating as a singleton, if it offers 6 ways to structure a singleton, then they will likely all be used at various points.  If you ever need to change this out, then you will have many different implementations to restructure.  This increases the likely hood you will need throw out a project to fix the architecture rather than replace it in a more structured way.

7. There should only be a handful of core architectures.  Think of your first day joining a project that is already in development.  There is so much learning.  But if that same project were built primarily on only 5 different architectures, that someone could look through a power point in an hour to review, and then reference later, then on boarding becomes easier.  If code reviews require consideration of any new potential pattern or architecture, and make group decisions as to whether or not a problem can be solved with existing patterns, no patterns, or that the group needs to add a new pattern to the list, then maintaining the project will be much simpler.

This is just a first draft, so I anticipate changes with this.  Please tear this apart with an Axe, but preferably in a constructive way.  :D

 - Thanks!

Tuesday, July 2, 2019

Unity: RuntimeInitializeOnLoadMethod - Order and Fault



RuntimeInitializeOnLoadMethod allows us to execute code at the start of a Unity program, without it being part of a Component.  This saves a lot of headache on special initializations and having to load things when you are not in the initializer scene. However, what is the exact order of these events, and are their any gotchas?

Order of events based on load type.
  1. After Assemblies Loaded
  2. Before Splash Screen
  3. Before Scene Load
  4. After Scene Load
    1. This is also the default, if you do not include a load type.
Example code:
using UnityEngine;

public class RuntimeInitializeLoadTypeTest
{
    [RuntimeInitializeOnLoadMethod()]
    public static void Default()
    {
        Debug.Log("Default");
    }

    [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)]
    public static void AfterAssembliesLoaded()
    {
        Debug.Log("AfterAssembliesLoaded");
    }

    [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
    public static void AfterSceneLoad()
    {
        Debug.Log("AfterSceneLoad");
    }

    [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
    public static void BeforeSceneLoad()
    {
        Debug.Log("BeforeSceneLoad");
    }

    [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSplashScreen)]
    public static void BeforeSplashScreen()
    {
        Debug.Log("BeforeSplashScreen");
    }
}

Faults:

  • Only BeforeSceneLoad and AfterSceneLoad execute in the editor, and these will execute for each scene.  
    • This means using this for a 1 time execution is out, if you want to be able to test it in the IDE.  
    • Or, at least, your code has to remember if it has been executed before.
  • AfterAssembliesLoaded and BeforeSplashScreen do not execute in the IDE, so you cannot test them very easily, nor depend on them for typical debugging.

If you intend to use something for a one time execution, its then Before and After SceneLoad will work, but make sure the state will not be harmed by repeat calls or that only one scene will be in use in your app.