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 BLoC does not tell you how you should structure your App as a whole. There is no clear definition of how big a BLoC should be or what's the scope of a single BLoC.
  • 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:

41 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.

    • Valery says:

      Hi, Thomas. This is interesting approach to the Flutter architecture. May i translate this series to russian and publish on Habrahabr?
      Sincerely Yours, Valery Kulikov (https://habr.com/users/rookie_cruekie/)

    • Very nice, after a architecture journey like yours I found the same architecture, I think streams already are a interface form, the implementation is hide behind a stream. The only changed I recently did is add mobx between manager and view. My app really don’t need this mobx layer, but I found advantages in the code generation reducing a little my boilplate. Its a RxVMS but state of view is sll inside mobx store.

  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.

  8. Erick says:

    Nice! I saw your talk. This solution is the best one right now! I’m planning to develop my app using this approach. We need at least 1 example of a manager and services implementation (Examples on the video were too short). Thanks for your awesome work!!

    I think the best way for a newbie (Like me) to learn this pattern using this blog and the video is the following:

    Introduction (this post)
    Fundamentals of Dart Streams
    RxDart: Magical transformations of Streams
    One to find them all: How to use Service Locators with Flutter
    (This is important if you want to understand the sl.get statements on the video. Also, check github example to grasp the concept)
    Watch video (link: https://skillsmatter.com/skillscasts/12265-flutterldn-september)
    Use docs (Rxcommands, GetIt)

    We’re missing at least 1 full example on each part (View, Manager and services) since the snippets you showed in the video were too short, hehe.

    Thanks for your awesome work!

    Greetings from the Dominican Republic.

  9. Paulo says:

    Hi, I’m using this pattern on my app. With get_it + rx_command + rx_widget and of course stream builders. But imagine you have a complex view with lots of events to be done, the fact that we need to specify a stream builders each time we want to inject a stream is a tedious, specially in this 1638 events situation. Why we can’t just add the stream as a var and flutter will automatically assumes it as a stream and listens then refreshes the parent widget with the new var under the hood? Imagine the power: A widget which could take a stream or a var in the parameters. So I think flutter team should look at this, if it’s not a stream proceed normally if it’s a stream , set’s a listner to rebuild the widget with the new var

    • Thomas Burkhart says:

      I agree having more than 10 StreamBuilders might not be a good idea. In that case I would bundle data for a Page together in a sort of ViewModell and publish that with a stream so that you use less Streambuilders. I haven’t had this problem yet.

  10. Pawan Sharma says:

    Hi Thomas,

    I have read most of your blogs and watched your skillsmatter video and are interested in RxVMS pattern to try it out. Thank you for sharing your knowledge. I would like to know when you publish your next articles in these series. Again, danke schon for a lucid explanation of important concepts.

    Cheers
    Pawan

  11. Chris says:

    Very interesting approach, congrats !
    I’ve been working with rxJava for a while and love the concept.
    I started to learn flutter and I believe using rxdart and related can short my learning curve.
    could you point me to an app code using rxvms ? thanks

    • Thomas Burkhart says:

      Thanks!
      Unfortunately there is no real world app as open source at the moment.

  12. Carlo Nyte says:

    Hey Thomas, I can’t thank you enough for taking the time to write these articles! You’ve provided so much clarity, easy to follow instructions and explains on how to use RxVMS. For those of us out there who really want to write code in the most efficient way possible, these articles have been an extraordinary help!

    You’ve definitely inspired me to do more things that give back and help others. Thank you again.

    Carlo

  13. […] app is structured according to RxVMS so we have a UI-, a Manager- and a ServiceLayer with Stream communication in […]

  14. The Hoang says:

    Hi Author,
    Your articles are very good for community.
    It will be great if you can share us source code of JoinOrCreate, it is very good as starter point for newbies.

    Thank you very much!

  15. […] Burkhart will speak on a topic that is rarely met at Flutter conferences. Thomas will talk about RVMS – a practical architecture for Flutter applications, will share his experience and the latest […]

  16. […] встретить на Flutter-конференциях. Томас расскажет про RVMS — практичную архитектуру для Flutter-приложений, […]

  17. […] Burkhart will speak on a topic that is rarely met at Flutter conferences. Thomas will talk about RVMS – a practical architecture for Flutter applications, will share his experience and the latest […]

  18. Fredrick A Grott says:

    Thomas, this is great stuff.

    I borrowed your idea and modified it to re-use with getX.
    Getx is somewhat similar to getit except using it I avoid ver having to use stateful widgets directly and my command stuff it through using get_command.

    Fits my dissatisfaction with the way Google wants developers to architecture an app.

    • Thomas Burkhart says:

      Hi Frederick,
      thanks a lot! Unfortunately the article is not really up-to-date any more. I moved from RX to ValueListenables (I wrote functional_listener to have rx like operators) and wrote the flutter_command package. To solve the Stateful problem I wrote the get_it_mixin which you really should check out. this combination as a lot of features getX doesn’t have while being much more lightweight

Leave a Reply

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