How do you guys scale MVI?
# android-architecture
u
How do you guys scale MVI?
t
If only I knew... There is some research on composable state machines but I haven't gotten around to reading it yet. In its current state (MVI à la Hannes Dorfmann or any of the Elm-like derivatives) for me it is unmaintainable. On the other hand it's clear that we need more type safety so a compromise has to be found.
u
Well, what would be the problem there if we were to compose reducers? Losing being "local" to the view model?
t
How would you do that? If I understand MVI à la Hannes Dorfmann correctly, all the business logic should happen in the rx streams outside the reducer. To make these streams generic, they emit intents, which are basically simple named actions, common to all screens, that should be performed on the state. The reducer is then the part that "adapts" this to our specific state by applying the action to the specific state. Obviously this can't possibly scale because the reducer keeps growing with the number of intents. Not only that, if the intents are in any way non-trivial we have unnecessary code duplication as well. The MVI-reducer abstracts away the actions, which is backwards. We really want to abstract the data. Here I experimented with something more reusable where the business logic is generic over the view and state. The presenter then simply consists of mappings from the specific state to the abstract one by passing accessor functions: https://github.com/tschuchortdev/Commit-Strip-Reader/blob/stream_arch/app/src/main/java/com/tschuchort/readerforcommitstrip/UseCases.kt This is far from usable but perhaps it can give you some ideas to cook up something better. The main conceptual difference to MVI is that instead of "intents" I use generic functions that are executed by a hidden reducer. I'm not sure how a truly composable solution would even look due to the disconnect of view and presenter. But for the business logic I think we would need to make each use case have it's own state machine and then adapt that through composition. In android this is even harder due to the issues with process death, debouncing and navigation.
u
hmm interesting althought not really sure what you mean. If I were to scale it then yes I'd probably decompose the reducer into subreducers which each have their own state and them compose it back into the top level state
but, if decomposition would mean simply routing x, y, z actions into reducer1 and others to reducer2, then they both act on Action, which would be weird, probably better would be if there was some hierarchy in Actions like FooActions, BarActions..
but mostly, im not sure how it would look, afaik reducers are anynymous in view models, by composition you'd have to have everything via ctors, which adds code.. not sure
what whats your gripe exactly with mvi? cant be bothered to write the Actions sealdclass?
d
Metaprogramming can help with boilerplate.
u
like what, annotations?
t
I had many annoyances with MVI. For example that there is no structured way to read the state outside reducers. Sometimes I had to pass arguments from the reducer all the way through the streams, just so I could pass it back to the reducer at a later time. All in all it felt like too much boilerplate for too little gain.