Using BuildIt.States for Managing States

Using BuildIt.States for Managing States

Almost every software development course at some point covers object orientated programming where the concept of encapsulation is drummed in. We’re taught to create classes that track state – a typical example is an Order that has a series of items, and then goes through various states as the order is processed. All this information is held within the Order object, including some basic functions such as calculating the total of the items being ordered. As the systems we work on grows in complexity, so does the complexity of the classes that are used to encapsulate aspects of the system. Unfortunately this often results in large, bloated classes, where it’s hard to make changes without fear of breaking other parts of the system.

One common mistake that seems to creep in over time is that it becomes difficult to manage what state a class is in. This can result from either a lack of documentation about what states the class can be in, or the states themselves aren’t clearly defined. Take the Order example, the Order class may have properties such as OrderTimestamp and OrderId which are set when the Order is placed. If the Order is rejected, the OrderTimestamp may be reset, leaving the class is some weird state where it has an OrderId, yet no OrderTimestamp. This is one of the scenarios that BuildIt.States is designed to help with.

Before we jump in, we need to set down a basic understanding of how we define states. States can appear in groups but within a group, there can only ever be one current state. For example in the Order scenario, there might be a group called TransactionStates, and the Order can only be in one of the states, Unprocessed, Processing, Processed, OrderRejected, at any given time. This leads me to the starting point of working with BuildIt.States: I’m going to define an enumeration that defines the states that my class can go between – you’ll notice this includes a Default (I often use Base instead) which BuildIt.States will use to determine if the state has been set or not.

public enum MainStates
{
    Default,
    One,
    Two,
    Three,
    Four
}

The next thing we need is our class, in this case one that inherits from NotifyBase, and raises a PropertyChanged event when the CurrentState property changes.

public class MainViewModel:NotifyBase
{
    private string currentState;

    public string CurrentState
    {
        get { return currentState; }
        set
        {
            currentState = value;
            OnPropertyChanged();
        }
    }
}

Defining the states that this class can be in is as simple as adding a reference to the BuildIt.States NuGet package and then defining each of the states:

public IStateManager StateManager { get; } = new StateManager();

public MainViewModel()
{
    StateManager
        .Group<MainStates>()

        .DefineState(MainStates.One)
        .ChangePropertyValue(vm => CurrentState, “State One”)

        .DefineState(MainStates.Two)
        .ChangePropertyValue(vm => CurrentState, “State Two”)

        .DefineState(MainStates.Three)
        .ChangePropertyValue(vm => CurrentState, “State Three”)

        .DefineState(MainStates.Four)
        .ChangePropertyValue(vm => CurrentState, “State Four”);

}

The notation for defining state groups and states is very fluid in nature and we’re always looking for ways to make defining states more intuitive. Essentially each of these states updates a single property, CurrentState, with a new constant value.

Making use of this class is as simple as creating an instance of the MainViewModel and setting it as the DataContext for the page:

public sealed partial class MainPage : Page
{
    private MainViewModel ViewModel { get; } = new MainViewModel();
    public MainPage()
    {
        this.InitializeComponent();

        DataContext = ViewModel;
    }

    private void StateOneClick(object sender, RoutedEventArgs e)
    {
        ViewModel.StateManager.GoToState(MainViewModel.MainStates.One);
    }

    private void StateTwoClick(object sender, RoutedEventArgs e)
    {
        ViewModel.StateManager.GoToState(MainViewModel.MainStates.Two);
    }

    private void StateThreeClick(object sender, RoutedEventArgs e)
    {
        ViewModel.StateManager.GoToState(MainViewModel.MainStates.Three);
    }

    private void StateFourClick(object sender, RoutedEventArgs e)
    {
        ViewModel.StateManager.GoToState(MainViewModel.MainStates.Four);
    }
}

When this is run, clicking through each of the buttons triggers a state change in the MainViewModel instances. This in turn causes the CurrentState property to change, which is shown on the page via data binding. The really awesome thing about the way states are defined, is that you can have any number of properties being set, and the library is smart enough to set the property values back to what they were originally when the class moves to a different state.

*Note that this library is currently in beta

Migrating BuildIt to .NETStandard

Migrating BuildIt to .NETStandard

At the beginning of the year I blogged quite a bit about a set of libraries that we use at Built to Roam that are available either from NuGet (https://www.nuget.org/packages?q=BuildIt) or as source on GitHub (https://github.com/builttoroam/BuildIt). These started a few years ago as an accumulation of helper functions for building, as the time Windows Phone applications. Since then the libraries have matured a bit and have evolved somewhat. The BuildIt.General library is still just a collection of helper method, whilst some, like BuildIt.Lifecycle, are more framework in nature. Over the coming weeks we’re investing a bit into tidying up these libraries, including:

  • Migrating any of the libraries that were targeting PCL profile 259 across to .NET Standard 1.0
  • Updating, where possible, all NuGet references
  • Setting up an automated build and release process, including support for publishing directly to NuGet
  • Rationalise the number of libraries on NuGet – namely where there are platform specific libraries, these will be combined in with the core library (eg BuildIt.General.UWP will get packaged with BuildIt.General and will be installed for UWP projects)
  • Add some additional packages
    • BuildIt.Media.UWP – This allows you to easily add Cortana voice commands for controlling media playback with the MediaElement control
    • BuildIt.Web.Config (this name may change) – This allows you to easily define application configuration values server side and have them flow to the client application

Right now, we’re going through and migrating the libraries to .NET Standard. This is a painful process as there are often NuGet references that don’t work with .NET Standard – we’re either removing these or deciding to wait on the package author to update. During this phase a lot of the packages will be marked as beta –  you should be able to start using these libraries but just be aware we haven’t completed the migration, so things may change over the coming weeks.

NetStandard, what is it and why do I care?

NetStandard, what is it and why do I care?

Over the past couple of years there hasn’t been a single project where at some point or another it hasn’t encountered NuGet pain – this is the pain associated with trying to upgrade packages, only to discover that you have to carefully select specific package versions due to incompatibilities, and then try and fight the nasty Visual Studio NuGet package manager interface to get them to install correctly. I’m no expert on topics like PCL Profiles, so I thought that I’d spend some time researching a bit more about what’s going on, and just why NuGet seems to fragile. This interest was also driven by the recent release of the .NET Platform Standard (ie NetStandard) and the fact that I need to migrate the BuildIt libraries we use, away from PCL Profiles (yay!) across to NetStandard.

As I said, I’m no guru on this, so rather than post third or fourth hand info. Here’s where I started: Oren Novotny’s post entitled Portable- is dead, long live NetStandard. Start there, and make sure you follow the links in his post as they provide some essential background reading on the topic.