MVVM / MVC is dead? Is Unidirectional a MVVM / MVC Killer?

Ah so now when you’ve learnt MVC/MVVM, everyone’s decided that we shouldn’t do it anymore? Huh?

MVVM is a great pattern which allows for a clean separation between views and logic, it also lends itself well to unit testing, but is it the only way? If you didn’t already know there’s some new kids on the block, Unidirectional User Interface Architectures which is basically applying the CRQS/Event Sourcing pattern on the client side. The idea of these patterns is to have a single DataStore which is the source of truth and data is updated via events, all Views read from the single source of Data and can only update via events/actions. From what I can gather at the moment, the specific problems they solve are 1) Avoid data being duplicated across viewmodels and stale data 2) Avoid the situation of Fat ViewModels. At the moment this concept is being driven from the web clientside world, but eventually it might make it’s way into the Xamarin world and become popular, maybe? 

There’s new unidirectional frameworks appearing all the time, the ones I’ve looked into recently are Flux and Redux.

Flux Diagram 

flux-diagram

Redux Diagram

Redux Diagram

So can we have these in Xamarin? Yes, these are simply design patterns and can easily be implemented in C#. Infact someone has already created a project based on Redux named Redux.net. In some R&D we’ve been doing on a project we’ve also implemented a Xamarin.Forms sample for the Redux.net project.

Here’s some code from the redux project:

Let’s start with our Application state.

public class ApplicationState
{
    public ImmutableArray<Todo> Todos { get; set; }

    public TodosFilter Filter { get; set; }
}

The Actions are basically any changes in your apps state.

public class AddTodoAction : IAction
{
    public string Text { get; set; }
}

public class DeleteTodoAction : IAction
{
    public Guid TodoId { get; set; }
}

public class CompleteTodoAction : IAction
{
    public Guid TodoId { get; set; }
}

public class CompleteAllTodosAction : IAction
{
    public bool IsCompleted { get; set; }
}

public class ClearCompletedTodosAction : IAction
{

}

public class FilterTodosAction : IAction
{
    public TodosFilter Filter { get; set; }
}

The application reducer will then take an Action and modify the state.

public static class ApplicationReducer
{
    public static ImmutableArray<Todo> AddTodoReducer(ImmutableArray<Todo> previousState, AddTodoAction action)
    {
        return previousState
            .Insert(0, new Todo
                {
                    Id = Guid.NewGuid(),
                    Text = action.Text
                });
    }

    public static ImmutableArray<Todo> ClearCompletedTodosReducer(ImmutableArray<Todo> previousState, ClearCompletedTodosAction action)
    {
        return previousState.RemoveAll(todo => todo.IsCompleted);
    }

    public static ImmutableArray<Todo> CompleteAllTodosReducer(ImmutableArray<Todo> previousState, CompleteAllTodosAction action)
    {
        return previousState
            .Select(x => new Todo
                {
                    Id = x.Id,
                    Text = x.Text,
                    IsCompleted = action.IsCompleted
                })
            .ToImmutableArray();
    }

    public static ImmutableArray<Todo> CompleteTodoReducer(ImmutableArray<Todo> previousState, CompleteTodoAction action)
    {
        var todoToEdit = previousState.First(todo => todo.Id == action.TodoId);

        return previousState
            .Replace(todoToEdit, new Todo
                {
                    Id = todoToEdit.Id,
                    Text = todoToEdit.Text,
                    IsCompleted = !todoToEdit.IsCompleted
                });
    }

    public static ImmutableArray<Todo> DeleteTodoReducer(ImmutableArray<Todo> previousState, DeleteTodoAction action)
    {
        var todoToDelete = previousState.First(todo => todo.Id == action.TodoId);

        return previousState.Remove(todoToDelete);
    }

    public static ImmutableArray<Todo> TodosReducer(ImmutableArray<Todo> previousState, IAction action)
    {
        if (action is AddTodoAction)
        {
            return AddTodoReducer(previousState, (AddTodoAction)action);
        }

        if (action is ClearCompletedTodosAction)
        {
            return ClearCompletedTodosReducer(previousState, (ClearCompletedTodosAction)action);
        }

        if (action is CompleteAllTodosAction)
        {
            return CompleteAllTodosReducer(previousState, (CompleteAllTodosAction)action);
        }

        if (action is CompleteTodoAction)
        {
            return CompleteTodoReducer(previousState, (CompleteTodoAction)action);
        }

        if (action is DeleteTodoAction)
        {
            return DeleteTodoReducer(previousState, (DeleteTodoAction)action);
        }

        return previousState;
    }

    public static ApplicationState Execute(ApplicationState previousState, IAction action)
    {
        return new ApplicationState
        {
            Filter = action is FilterTodosAction ? ((FilterTodosAction)action).Filter : previousState.Filter,
            Todos = TodosReducer(previousState.Todos, action)
        };
    }
}

Then the UI will be updated, below we see  a UI element binding directly to the state and updating on changes.

public partial class MainSection : ContentView
{
    public MainSection()
    {
        this.InitializeComponent();

        App.Store.Subscribe((ApplicationState state) =>
            {
                TodosItemsControl.ItemsSource = FilterTodos(state.Todos,state.Filter);
            });
    }

    private IEnumerable<Todo> FilterTodos(IEnumerable<Todo> todos, TodosFilter filter)
    {
        if(filter == TodosFilter.Completed)
        {
            return todos.Where(x => x.IsCompleted);
        }

        if(filter == TodosFilter.InProgress)
        {
            return todos.Where(x => !x.IsCompleted);
        }

        return todos;
    }
}

Should I use this over Mvvm? Will this kill Mvvm? 

In all truthfulness I (like most people) don’t know if Unidirectional User Interface Architectures are the answer but I feel like they’re going to be around for a while.

I feel like I’ve hardly done these architectures justice in my explanations but I encourage you to look further into these patterns (maybe even try them or built a Unidirectional Framework for Xamarin). Anyways here’s some links for further reading.

https://facebook.github.io/flux/

https://github.com/rackt/redux

https://github.com/GuillaumeSalles/redux.NET

http://staltz.com/unidirectional-user-interface-architectures.html

 

Dont forget to subscribe to michaelridland.com.


11 Responses

    1. Hi Petar. Thanks for the comment. Can I ask the differences between Reducto and Redux.net, also why is it better?

  1. I understand Redux is not about the UI layer directly, and I appreciate the work done on Reducto and Redux.net. However, shouldn’t an additional goal be to construct the UI like React does with its render()-function?

    I understand re-rendering the UI is way more complex than the work discussed here, but wouldn’t the ability to render the UI like React be a huge win?

    1. The web browser and native application render differently, both iOS and Android have their own models for rendering. The advantages of react don’t really apply as both iOS and Android already have performant rendering.

  2. I don’t think that this idea is in competition with MVVM exactly. I’ve been doing this for years before it got a name, just to escape weird binding loops, the UI having direct access to data that it shouldn’t have access to, and duplicated state all over the place. First, all user input should trigger commands, and all databinding should be one-way only. The commands should only modify your “one source of truth” that sits below the VMs, and whatever VMs are alive at the moment are all subscribed to to your “one source of truth” and only provide a “filtered view” of it, they don’t actually hold any state.

    ReactiveUI and RX are all you need to build this. Works just fine.

    1. Hi Mike,

      Thanks for the comment. Sounds good.

      I’d like to see/discuss your solution I’m wondering if you would have a sample app? or would like to do a guest post on the blog?

      Thanks

  3. Hi Michael,

    Sorry for the late replay, I was expecting an e-mail when something happened on this thread, I was asked for an e-mail after all 😉 I guess it was for different reasons.

    Reducto and Redux.net are not too far off, you can see it in the code especially for the basic stuff – middleware, dispatching of actions. Here is what I find better with Reducto:

    1. A clearer path for building and more importantly *composing* reducers – http://pshomov.github.io/better-mvvm-with-xamarin-forms/#the-reducer

    2. Lighter – no external dependencies. It is important especially on mobile. I guess it is all the same if you are already using Rx.

    3. Async actions seem completely missing in Redux.net. I find them an essential piece of the puzzle though. They should have the capability to dispatch actions to report progress and status of long-running operations. I have done my best to make them as effortless as possible – http://pshomov.github.io/better-mvvm-with-xamarin-forms/#async-actions

    4. Reducto is modelled pretty close to the original so that should help should one have any experience from the JS side.

    5. ‘Redux.net’ is such a cliché, ‘Reducto’ is magical 😉 https://github.com/pshomov/reducto#what-about-the-name. I am kidding I’m just bitter I didn’t get the name 😉

    I am sad and surprised I do not see more comments on this post. I think you did a really good job explaining the concept. All in good time I guess 😉

    All the best,

    Petar

    1. Hi Petar,

      First of all, I would like to say that I really like what you did with Reducto! Thanks for your comments, I understand better the mind behind Reducto.

      IMO, I don’t think one is better than the other. I see Redux.NET and Reducto as two opinionated ports of Redux.js. I never took the time to explain my architectural choices with Redux.NET but maybe here is a good tribune to start :

      1. Originally, my colleagues and I combined the reducers in a similar fashion. After a while, we found it more confusing than simple functions composition and switch cases. So I choose to not be opinionated for the structure of reducers and let the consumers build helpers on top of Redux.NET if they want to avoid switch/cast boilerplate. A guy even proposed an F# helper (https://github.com/GuillaumeSalles/redux.NET/issues/23)! At the end of the day, a reducer is just a pure function that takes the previous state and an action, and returns the next state.

      2. Totally agree with you. Rx is not mandatory to Redux. I choose Rx for the following reasons :
      – It was faster for me to build Redux.NET since I use Rx at my day to day job.
      – The source can be reduced to less than 30 lines codes (without middlewares). https://twitter.com/gllm_slls/status/662347148110004224
      – Leverage the native System.IObservable interface.
      – Handy tool to avoid unnecessary rendering (https://github.com/GuillaumeSalles/redux.net#performance-optimization) and multithread issues (that are still not fixed by the way…)

      My plan is to remove the Rx dependencies (if someone complain about the package size) before 1.0.0 release without breaking changes. (by reimplementing the store as IObservable without Rx)

      3. Pretty much like reducers, I think async actions can be built on top of Redux.NET. Unlike Redux.js, I’m still not sure that it should be handled in a middleware (like redux-thunk) because of the static typing nature of C#. At work, we use extension methods on IStore and delegates to create complex action creators. Maybe I’ll add a recipe for that on github if some folks are interested ! I started a simple example of async actions here : https://github.com/GuillaumeSalles/redux.NET/tree/master/examples/async

      4. Unfortunately for .NET, I think more developers are going from .NET to javascript than the opposite. So I tried to focus on explaining the concept rather than having the exact same API surface.

      5. The name Redux.NET has some downsides… Some of my colleagues thought that Redux.NET was some kind of “artistic” photo album of nude women… http://redux.net/ 🙂

      In any case, I think Reducto and Redux.NET are great tools! I hope the opensource .NET ecosystem will become like the javascript one. A lot of small packages that do a lot of things in a lot of different ways to fulfill a lot of developers needs !

      Guillaume

  4. You’re seeing this the wrong angle: Redux is about functional programming (pure functions, DRY, keep sanity checked). You can use Redux even in a ASP.net MVC project. It’s all about DRY, testable functions and simple logic, not about UI!

Leave a Reply to Petar Shomov Cancel reply