Flux for .NET (Part I)

Feb 6, 2021·

5 min read

Hello, World! This is an introductory post for .NET developers interested in learning or using the Flux pattern in .NET projects. I'll be discussing the overall ideas and motivation for the Flux pattern. In the following posts, we'll do a bit of a deeper dive looking at three implementations:

  1. Implementing Flux using Plain old C# objects (Part II)
  2. Implementing Flux using .NET Dataflow (Part III)
  3. Implementing Flux using Observables (Part IV)

Here's the TLDR;

  1. What is Flux? Flux is a reactive pattern for state management through shared immutable state.
  2. Why use it? It's useful for managing complexity and side effects.
  3. How is it done? It achieves this through unidirectional data flows.
  4. Who should use it? It fits well with OO and FP, but is a paradigm shift for procedural programmers.
  5. When should it be used? Useful for medium to large application with lots of external dependencies.
  6. Where is it used? Extremely mature pattern heavily used in the JavaScript community. React and Redux are the main drivers, but it has roots with ReactiveX, which has roots in LINQ (🎶And the circle of life🎶).

To setup the story so far, during my career, I've had the great fortune of working on several projects where every new feature that was added would break something. Velocity and productivity would grind to a halt as time went on. And it was not fun.

In almost all of these cases, the cause of these unintended side effects was the inability to manage state and side effects. State management is difficult, but is essential for software that behaves consistently. These painful experiences drove me to look for a solution and one of them was Flux.

Flux is a pattern for state management. In almost all my experiences, state management issues have come from shared mutable state. Flux is a pattern for state management using shared immutable state.

If I was to distill Flux down to its core, it could be explained with these two interface:

    public interface IStore<out T>
        T State { get; }
        void Dispatch(IFluxAction action);
        Action Subscribe(Action<T> onNewState);

    public interface IFluxAction { }

An implementation of a IStore is a service that has the sole responsibility for updating and changing state. An implementation of IFluxAction is a plain old C# object that represents a request for a change of state. Flux works by enforcing a workflow to ensure consistency.

  1. A request for state change is created by creating an instance of IFluxAction which contains all the data required for the state change.
  2. The requester dispatches the action by calling IStore.Dispatch.
  3. IStore updates its state asynchronously.
  4. All subscribers are notified with a copy of the updated state.

If this seems familiar, it's effectively the command pattern and the publisher subscriber pattern together. It's can even be considered as an implementation of the Actor-Model.

If you consider the Actor-Model as the purest form of Object Oriented programming, then Actors can send each other messages, but only an Actor can mutate its own state. In this case, we can see that the Store can receive three types of messages:

  1. Get the current state
  2. Request for state change
  3. Add a subscriber

By having the state reside in the store and processing messages sequentially, your application has a single source of truth. This makes it easier to understand who, what, when, why and how a state change has been made.

In the next post, we'll be looking at an implementation of Flux using WPF.