Immutable Business Logic in Flutter

Immutable Business Logic in Flutter

Disclaimer: I know that the described pattern has many names, and MVI is one of them. But one of the things to learn from this article is that you can name your components whatever until you do break the app logic.

In mobile development, it is impossible to live without some mutable state: the device location changes, screen rotation, the battery is dying, and so on. Mutable state leads to undefined behavior much more often that we are ready to admit, and a good thing would be trying to make the app state immutable where possible.

As you see, I use the word state quite a lot here, and that is because the idea of immutable states highly relies on State Machines.

In OOP languages we use classes a lot. Languages like Kotlin allow creating classes that are variations of other classes — That allows specifying that something is an edge case of something else. For a screen of Reddit posts, for instance, we will have a and specific

Dart doesn’t have such functionality, but we still can use inheritance in a way that describes relations like this. Runtime type checking and casting can help with that.

Let’s unfold that Reddit posts screen idea in a bit more detail.

As you can see we are only using getters and hopefully will just use List.unmodifiable for the That should make the states truly immutable.

As mentioned, we will use a State Machine to move from one state to another. Some might call a state machine like this a To move from one state to another the has a method called which receives the current and an that needs to be applied for that state. If the and are not related, we usually throw an Exception.

I find it useful to treat the same way as we treat — one class for each . Sometimes an might do the job, but we never know when some additional data will be needed for the state change.

There are different ways to bind the to a specific I will create the actions as classes and check in the if the action is valid.

And our would look something like this:

The code above is simplified for readability reasons, but hopefully, the idea is clear.

As you could imagine, testing code like this is pure joy. No one has to deal with callbacks, async operations or multithreading while testing the

Testing the positive case would most likely look like this:

While testing a wrong action would look like this:

Like in the books: calling a method — checking if the result is correct.

Of course, in real life, we have to deal with async operations and callbacks, and putting any async code to the UI layer is not preferable. That’s why a good solution might create an additional layer between the UI and our

This layer would hold the reducer, and it’s only responsibility would be to work with any async operations and notifying our Widgets.

I decided to store the current state in the but different options are available. You could do this directly in the

I find this approach highly usable and accessible to process, so free to try it in your project ;)

Images Powered by Shutterstock

Thank you for your referral

Please list your name and e-mail and we’ll contact you shortly

  • This field is for validation purposes and should be left unchanged.