State management is the debate that just won’t go away. It seems like every week, there is a new discussion attempting to determine which pattern or library is the best approach for state management in Flutter. We get it — selecting a state management solution could determine your entire application architecture, which is no small decision. And, there are many popular state management solutions to choose from such as redux, mobX, flutter_bloc, and even vanilla setState.
Our perspective on the state management debate is: The best state management solution is the one that works the best for you. When it comes to our projects at VGV, we know exactly what state management solution works best for our team: flutter_bloc.
This blog is not intended to be the last word in conversations about state management, nor is it an attempt to prove that there is a “winner” once and for all. Instead, we will explain why we use flutter_bloc, the benefits it brings to our team, and how we address common concerns about it.
Building expertise on a solid foundation
We work with clients across various industries — including automotive, entertainment, healthcare, and financial services. To date, we’ve provided Flutter expertise to over 20 companies, which means we’ve seen a lot of Flutter apps, as well as a mix of approaches to scalable Flutter development. Our team continually pools together our knowledge and refines the way we approach building scalable apps — that is, apps optimized for growth over the long run (read what we mean by scalable here).
Building a robust product requires our team to pick and define a set of tools and practices that makes us feel comfortable and confident in our ability to deliver and maintain that product successfully over time. One of those tools you need first is your state management solution.
A while ago we had to ask ourselves as a team: How do we provide more value to our customers? We had two options:
- Learn and continually improve on a single, well-known and popular solution
- Start each project with a different solution, hoping for the benefits and accepting risks it might bring
At Very Good Ventures, we are in the business of providing confidence to our clients: we deliver our best when we avoid surprises and are predictable and boring.
We came to the conclusion that it would be easier and more impactful in the long-run to commit to a single tool that we have used before and know works well, rather than spending our time testing out other solutions. The tool we have selected is flutter_bloc. Before we explain the specific benefits that it brings to our team, we should note that some of our clients come to us with codebases that are already using a state management solution other than flutter_bloc. In these cases, we will work with them to deliver the best code with their preferred tools. However, our job as consultants also entails that we provide recommendations, especially when clients are looking for a solid architecture to start building from, or an effective way to refactor existing code. In these cases, we recommend flutter_bloc as our preferred solution for building predictable, scalable Flutter applications.
Predictable, simple, and highly testable
One of the cultural values we have defined at Very Good Ventures is to “scale with standards.” We define it like this:
- We create scale through solid, repeatable practices
- We grow client capabilities in addition to creating software
- We are principled with our work and avoid shortcuts
- We seek out and build solutions to repeating needs
- We embrace automation and long-run optimizations
Once our team defined a set of values and principles that we wanted to follow, it was much easier to pick the tool that most accurately represents and embraces those values. And, well, flutter_bloc is the perfect match for this:
One of the biggest challenges of product development is knowing, at any point in time, the real state of your application.
Flutter helps developers to answer this question through the widget tree. But in order to make your product interesting and interactive, you will need to modify the widget tree; that is, you need to decide how you will manage the structure of your tree (or, in other words, state management).
flutter_bloc allows you to decompose your app’s state into smaller, well-defined state machines that transform events into zero, one, or multiple states. For example, when you open your favorite food delivery app, something like this might happen:
When I open my favorite food delivery app, I get a loading indicator that indicates that we are fetching data from the network. If the connection was successful, I will be presented with a list of my favorite restaurants. Otherwise, an error message will be displayed.
Say no more! You could code that requirement in a predictable way using an approximation of plain English:
Every UI application is reactive by nature: your UI is idle most of the time waiting for your customer’s interaction (or a system event) to then provide and transform data. But you never know when that interaction will happen, or even if it will happen at all. That’s why your application needs to react to those events.
Traditionally, the APIs that helped developers to capture that reactiveness were powerful, but incredibly complex to use properly (callbacks, Rx, Streams, etc.).
With flutter_bloc, we still honor the fact that every application is reactive by nature, while abstracting the complexity of streams from developers. Forget about maintaining complex subscriptions and lifecycles, and instead, focus on the real, predictable interactions of your product. Only focus on what matters: for the received event, the state that we need produced.
One of the key qualities that VGV developers have to feel confident about when selecting tools is that they should be testable. Along with the production code, our team values automated tests that can validate the behavior of the product at any point in time.
bloc_test is a utility library that removes all the complexity of testing reactive code, and allows you to unit test your code with almost no setup required.
Onboarding and documentation
Documentation, tutorials, examples, guides, and migration guides are all key to ensure a healthy and productive community. flutter_bloc is known in the community for its detailed documentation (which currently provides translations for 10 languages), selection of high-quality tutorials (from a simple counter project to complex integrations with Firebase), as well as support for Angular Dart.
We’ve been able to successfully onboard entire engineering organizations by just going through the flutter_bloc documentation. Even our internal onboarding, especially these days when remote work is the norm, heavily relies on the flutter_bloc documentation.
Used by thousands
flutter_bloc started as a solution for an internal need that some of our teammates faced when working at BMW: how can we help our teammates all around the world commit their features to Flutter in an efficient, productive, and safe way? flutter_bloc quickly scaled from being used internally by a few dozen engineers to being open-sourced with more than 7,000 stars on Github! To put it in perspective, dagger has 7,300 stars on GitHub. That’s a huge accomplishment for a Flutter package!
In addition, flutter_bloc has helped companies of all sizes to scale and release their products successfully, and we are incredibly proud and excited to keep investing and supporting this amazing library! flutter_bloc has even been named a Flutter Favorite by the Flutter Ecosystem Committee, who consider metrics like overall package score, feature completeness, usability, and more.
Addressing some bloc concerns
“Bloc is too complex.”
A quote that is very present in our work is “complex problems, easy solutions.” Flutter already introduces a very powerful solution to manage state: setState on StatefulWidgets. So, why do we need a state management solution at all?
setState is ultimately what every state management solution ends up calling to modify the widget tree, but it can be easy to mismanage when your application gets complex, especially when it comes to managing multiple variables, touch events, navigation, push notifications, analytics. At scale, problems can arise, such as passing state around the widget tree (prop-drilling), unnecessary widget tree rebuilds, and code that is generally hard to read and test due to logic injected throughout the UI.
With flutter_bloc, we introduce a way to adapt to the reactive nature of every application without having to be proficient in tools and APIs like Streams or RxDart. You will still need to learn a few core concepts such as the Bloc API itself and the difference between a BlocBuilder and a BlocListener. The good news is these are all things that are well-documented and covered in multiple tutorials.
flutter_bloc might not be the first tool you need to learn when getting started in programming, or even during your first attempts with Flutter (after all, you need to learn first how to walk before you can run). But in our experience, flutter_bloc can boost your productivity and efficiency as a developer due to its simplicity and relatively few concepts to learn.
“Bloc has too much boilerplate.”
flutter_bloc requires you to model your events and states with different classes. This, compared to the simplicity of simply declaring variables if you were using setState, could be considered a step back since it might require you to write more lines of code to achieve the same functionality. However, is the sheer number of lines of code a fitting metric for considering a piece of software good software?
A beautiful thing about modeling your events and states with separate classes is that:
- You can truly make them immutable
- Your events, states, and their properties are completely independent of each other
If your problem is complex, what at the beginning might seem like a burden (“Ugh, do I have to write a single class per state?”) will turn into a benefit! (“Yes! I am so glad that my success logic is completely separate from my error handling!”).
Alternatively, if you truly consider your event information boilerplate, you can default to using cubit instead of bloc: after all, cubit is mostly a bloc without events as a class, but as a public method. You'll lose functionality, like automating logs and analytic events, but you can then write less code without sacrificing legibility. Tooling can also make it easier to write this code quickly and consistently — such as the bloc VS Code and IntelliJ extensions.
Finally, we are excited and hopeful for the changes that the Dart team is considering with the static metaprogramming issue; they could help even further to simplify the bloc API, be more strict and safe, and do more with less.
We have the highest level of confidence in flutter_bloc
In our business, providing confidence and meeting expectations is key, which means our team must be flexible and adapt to changing client needs. As a highly experienced team of Flutter developers, clients ask us to recommend tools and approaches that will provide the best results. When it comes to state management, flutter_bloc is the fastest and safest path to engineering excellence for our team.