RxVMS a practical architecture for Flutter Apps

This is the fist post of a series of posts that will explain my take on App architecture for Flutter. It will be highly opinionated so be warned 😇

Planned posts so far:

Background

I’m in software now for about 20 years. I started with mobile 4 years ago with Xamarin Forms because cross platform was the only thing that made sense to me for an Indie App. Xamarin Forms almost forces you to use MVVM because you define the UI in XAML so you need some glue layer to connect the UI to your Model seems to make a lot of sense on the first view. While working with Xamarin I was introduced to ReactiveUI and fell in love with streams and Reactive Extensions (Rx) which made my Apps much more robust.

While using MVVM with Xamarin Forms was just natural I was surprised when coming to Flutter that there was no recommend architectural pattern. So I started to explore different options but didn’t really like any of them:

  • InheritedWidget never managed to make it only update the part of the Widget tree that’s data changed, so I just used it to access a model class publishing Dart Streams but soon dropped it in favour of a generic Service Locator
  • Scoped Model better than InheritedWidget but didn’t give me the flexibility I was used from ReactiveUI
  • Redux which was the one pattern that was recommend from a lot developers coming from React Native. I have written a whole post on why I don’t like it
  • BLOC If I hadn’t already started to work on my own pattern when BLOC was promoted I probably would have be stuck with it because it offers a really flexible and reactive solution. What I don’t like is that it publishes Stream Sinks so I can not just pass a function/command to an event handler of a Widget. Also having one big BLOC object doesn’t make live easier if you develop in bigger team and makes testing harder.
  • MVVM As I was used to it I first checked out if it would fit with Flutter too. It doesn’t! The whole point of an ViewModel is to provide representation of your model to that it can be easily consumed by your Views by using Bindings. But Flutter doesn’t update its Widgets with new data, it always rebuilds them as I discussed here. Further ViewModels need to keep in sync with the underlying Model which can lead to nasty bugs and reality shows that the promised advantage of reuse ViewModels across Apps almost never happen. Adam Pedley has a great ranting post on the shortcomings

The ugly truth of too much Layering

It’s almost a dogma in software development that you always should build your Apps in several layers where each layer should only access the next layer below because it will allow you to:

  • Reuse layers in other project
  • Let’s you easily replace on layer with another one
  • Makes them easier testable

I have almost no project I have seen that whole layers got reused. If you have generic code that can be used somewhere else it makes much more sense to factor that out into a generic library. Also replacing whole layers is not a really common use case. Most people will never replace a data base after an App is beyond a certain development stage, so why add an abstraction layer for it. And in case you really have to our current development tools make refactoring quite easy. What it makes indeed easier is testing.

I don’t say you shouldn’t use layering but I question if we have to do it as strictly as we did in the past. Extensive layering lets you use a lot of code and can make problems in keeping a single source of truth of your App’s state. Introduce layers only where it helps you not just because it’s a best practice.

An ideal architecture for Flutter

So what do I expect from an ideal architecture?

  • Make it easy to understand how your App works. This one extremely important goal for me. New developers starting with an existing App’s code should be able to follow execution paths easily
  • Make it easy to work as a team on one App
  • The architecture itself should be easy to understand and to follow
  • No boiler plate code just to make the architecture work
  • Support the reactive UI approach of Flutter
  • Make debugging easy
  • Don’t hurt Flutters great performance
  • Easy to extend
  • Make testing easy
  • Let’s you focus on your Application instead of internals

The self responsible Widget

Given the aimed stateless nature of Flutter UIs one Page/Widget shouldn’t depend on another Page/Widget or change another Page/Widget. This lead to the idea that every Page/Widget should be self responsible for displaying itself and all it’s user interactions. This will make it easy to understand how your App works as you typically explore an App beginning from its UI. It also would make it easy to split work between developers because one developer can work on one Page without the need to know of the work of others.

RxVMS

RxVMS is an evolution of RxVAMS that I described in a previous post While applying RxVAMS in my current real world Flutter project I realized some weaknesses in it and improved it.

The current result of all this thoughts is what I call RxVMS which stands for Rx-View-Managers-Services. It fulfils all the above goals with the only requirement that you have to grasp Streams and parts of Rx. To help you with that I will devote the next post.

This is a partial schema of my current App

RxVMS

Services

These are abstractions of interfaces to the outside of your App this can be a Database which requires you to serialize your objects, a REST API or some hardware of your phone. They don’t change any state of your app.

Managers

Managers group together semantically related functionality. Like everything needed for user management / authentication, everything related to an order or to your product catalogue. They provide CRUD operations on your objects.

Every state change (change of data of your App) has to be done through a Manager. They typically don’t store state themselves unless it’s critical for performance or it’s data that doesn’t change throughout the live time of the App.
They also can provide data sources for views if the data needs some additional transformation after retrieving it from a service. An example could be if you need to access two different data sources and combine them to one business object that a View can display. Managers can interact with each other.

Views

Typically a StatefullWidget or a Widget that contains a StreamBuilder so that it can consume returned data from Managers or Services. This will often be a whole Page but could also be a complex custom Widget. They do not store any state that has to persist. Views are allowed to directly access Services so far they don’t change any state.

Domain Objects

Although not in the diagram this are the objects that represent your business objects. In other models they belong to their own Model layer which also contains all business logic. In RxVMS they don’t contain any business logic that could change state. They are almost always plain data objects. (If I had included them it would have got RxVMMS which is long and VM could be misunderstood as ViewModel). Logically they belong to the manager layer.

In the upcoming posts we will explore this parts and how they work together in detail.

Contact me:

15 thoughts on “RxVMS a practical architecture for Flutter Apps

  1. Tuan Vu says:

    Really interested in your concepts. I used Redux with React and currently using ScopedModel right now. I have the same opinions as you about them. I’ve seen tutorials about BLOC, but haven’t used it to get a sense of how it fits in a decent sized app. Your post about RxVAMS was convincing and it seems like you’ve cut even more fat out with RxVMS. Looking forward to this series. Keep up the great work, you explain your opinions very well.

    • admin says:

      Thanks a lot for your comment! It’s rarely that people give feedback who h so important for us bloggers. Working already on the next part.

    • Jonah Fang says:

      I think ScopedModel is very simple and elegant, any reason switch to other solution?

      • admin says:

        In the end ScopedModel is just a more comfortable Version of InheritedWidget that allows you to access your model Classes. It is not a real Architecture on how you organize your App. It does not make any assumption how you will manage your Apps State. It does not facilitate the reactive nature of Flutter like a Stream based Architecture does.

  2. This is a topic that really interests me so much. I read your previous posts and found them very enlightening. Same as @Thuan, I am reading a lot on this topic (BLoC, MVVM …) since I too find that we need to decouple the Widgets from the business logic. However, so far, I could only find implementations of very basic applications (one screen, login…) which is quite far from a real app.

    Any idea of a milestone for your next article?

    Meanwhile, many thanks for sharing all this with us.

    • admin says:

      Hi thanks for your kind words. I can’t get milestones yet unfortunately. I know samples are always not like real Apps, but they have to be easy to follow and also not too much work.

  3. Jonah Fanag says:

    Any time of next article?

  4. Adrian says:

    Cannot wait for your next post. Been trying to get my head around a workable architecture and RxVMS stands out from the croud.

  5. Nguyen says:

    Very exciting with RxVMS. Good job!

  6. Romane says:

    Hello, this looks really promising, been using reactivex for like 2 years now and found nothing better, it’s my bread and butter.

    However, I can’t really work with RxVMS in the project I’m about to start because the posts are still a WIP and I can’t understand what are the deficiencies of the RxVAMS and how these issues would impact my soom-to-become project.

    • Thomas Burkhart says:

      Although RxVMS is still evolving it has proven its usefulness in my current real world app project. I really would like to already have the next post finished but I have to write posts in my spare time šŸ˜€ Luckily soon a video from my talk on RxVMS in London will be online.

  7. Romane says:

    Btw, the articles are VERY well written, direct, didactic and concise.

Leave a Reply

Your email address will not be published. Required fields are marked *