DEV Community

Cover image for A case against the MVI architecture pattern

A case against the MVI architecture pattern

Raviola on April 12, 2021

The opinions in this article are based on my own experience working with different implementations of MVI in both personal projects and at my day j...
Collapse
 
1gravity profile image
Emanuel Moecklin • Edited

orbit-mvi.org/ and github.com/genaku/Reduce (and other frameworks like Redux or the SAM pattern) both have interesting ideas that inspired me to create my own KMM ui framework: 1gravity.github.io/Kotlin-Bloc. It supports different styles of writing the business logic which can be combined idiomatically to support your specific preference. In the end it's a "matter of taste" which style a developer/team prefers. Mixing different styles can make sense even in the same app.
You can write reducer functions contextually (MVVM+ style) or group them together (Redux style). Even when grouped together you can write them single-action style like:

reduce<Increment> { state + 1 }

reduce<Decrement> { state - 1 }
Enter fullscreen mode Exit fullscreen mode

It also supports Redux style thunks and side effects and completely eliminates the need for a ViewModel on Android which is, in a KMM project, basically just boilerplate code.

Collapse
 
genaku profile image
Gennadiy Kuchergin • Edited

Thanks for the article! You inspired me to do it even easier than orbit-mvi.
github.com/genaku/Reduce#simplify

Collapse
 
viktorpetrovski profile image
Viktor Petrovski

I definitely feel the same way about MVI, it looks good on paper but is so hard to read. I recently adopted a codebase that used MVI, personally I think they did a lot of things wrong in their MVI, but I can definitely related that I've spend majority of my time trying to understand what the heck is going on.

Collapse
 
ikakus profile image
ikakus

github.com/badoo/MVICore
This one is my favorite. It is very simple actually, and it IS used for years already in a huge project.

Collapse
 
emitchel profile image
Elliot Mitchell

I agree that it can be hard to follow the flow and I shared similar thoughts around boilerplate, ctrl+b eventually becomes your best friend - which it should be anyways!

Where we disagree is that MVI really comes to shine in larger code bases with complex UI interactions, and is overkill for simple UI. When you think about refactoring or adding on more functionality, MVI pinpoints the exact interactions that already occur and what their side effects are, and eventually results in the exact state expected - you know exactly what to expect and how to modify pre existing states. Without that unidirectional flow of intentions, the codebase only becomes increasingly more difficult to scale on top of and maintain.

Collapse
 
feresr profile image
Raviola • Edited

Hi! Thanks for reading, appreciate the feedback!

"MVI pinpoints the exact interactions that already occur and what their side effects are"

MVI does not do this by default though, it requires developers to model those interactions themselves. MVI only provides the framework to do so, just like any other architecture pattern. And MVI is really strict about this, it imposes a lot of artifacts and rules down your throat. Rules and constraints can be good, but in my opinion, the ones MVI encourages are not.

Without that unidirectional flow of intentions, the codebase only becomes increasingly more difficult to scale

The idea of the unidirectional flow is nice, you can still implement it without strictly adhering to all MVI ruleset or go with a different architecture altogether

Collapse
 
mochadwi profile image
Mochamad Iqbal Dwi Cahyo

Have you consider to take a look the pedroql.github.io/mvflow/? MVFlow eliminates those drawbacks (imho)

tl;dr: github.com/pedroql/mvflow/blob/mas...

Collapse
 
feresr profile image
Raviola • Edited

I don't see how that eliminates the drawbacks. Let's take a flow in your example: the Reset counter flow. To understand how it works you need to go to line 45 in the handler, read one single line, then jump to line 67 in the reducer, read another single line, and the jump again!. Both lines are surrounded with completely unrelated code.
Also, it's not clear where to jump exactly, no shortcut will take you where the code should continue, cmd+f/b is your best bet and even so it might take you a while.

In the end, you spend more time jumping around trying to find code than actually reading code.

Collapse
 
mochadwi profile image
Mochamad Iqbal Dwi Cahyo

for now the MVFlow is the simplest we can think of at the moment, also I'm fully agreed with you

Both lines are surrounded with completely unrelated code

any suggestion at the moment to optimize this instead?

spend more time jumping around trying to find code than actually reading code.

Thread Thread
 
feresr profile image
Raviola

any suggestion at the moment to optimize this instead?

Personally, I'd just switch to another Archtecture pattern (MVVM) or use an MVI library that does not impose strict rules regarding where you have to do the mapping, and where you have to perform state reduction.

This library for example avoids the (intent -> action) mappings altogether. When you call add you can follow the flow linearly and the state is reduced contextually.

orbitlibrary

Thread Thread
 
mochadwi profile image
Mochamad Iqbal Dwi Cahyo • Edited

thanks for the suggestion, the Orbit-MVI 3 seems fit our usecases and a simplified version! ❤️