Hey! :wave: Not sure if this is really a question ...
# multiplatform
n
Hey! 👋 Not sure if this is really a question for this channel. I’m planning the architecture of a new app that will be used on browser, iOS and Android and I’m going to use KMM to share as much as possible. This includes the ViewModel/Controller/Service layer. Lately we are getting used to see more and more the single data flow pattern for the view layer on frameworks for the three platforms. Let’s call the object holding the state
Store
for convenience. Normally on Android (I’m not sure on iOS) this `Store`’s lifecycle is bound to the lifecycle of the screen itself (or navigation subgraph) and there’s one store per feature. But on web (if I’m not mistaken) usually there’s a single
Store
and it’s bound to the lifecycle of the whole app. This makes for me sense because usually on web there are a lot of components seen at the same time on screen. My question is, if we’re sharing the
Store
logic between mobile and web, does it make sense to have a single
Store
or is it better to have multiple
Stores
, one per component? Also, does it make sense to bind that to the screen lifecycle on mobile or keep a single instance for the whole app lifecycle? I know this is completely subjective, I’m only asking for some advice here! And sorry if the terms are not accurate, I’m only experienced on Android and I don’t really know the best practices on web dev and iOS, just what I read online. Thanks!
l
Actually on Android it's advisable by the Model View Viewmodel architecture to hold any state and values on the viewmodel. And why that is? Viewmodel lifecycle doesn't get destroyed when the activity changes, and can be used by multiple activities and fragments.
I have no idea about using viewmodel on shared code, but I think it works the same way (at least in principle)
n
Hey Lucas! Thanks for your answer. Indeed, that’s also achievable by holding the state in an object that you bind to Android’s screen lifecycle even if it’s not a Jetpack’s ViewModel. That can be done in shared code too!
âś… 2
c
Hey Nacho! I’ve been working toward this same thing on my team, and am building out a state management library for KMP, so this is something I’ve given a lot of thought to recently. Here are my general thoughts: My opinion is that most apps will probably do fine with a 2-layered architecture, consisting of a UI layer and a Repository layer. In the UI layer, you should treat each mobile Screen or web/desktop Component as it’s own isolated entity, and it should hold its own ViewModel and State/Store. Don’t share VMs or State objects between screens; instead, pass simple values directly through URL route params, or pass IDs so that the destination routes can look up that data themselves. On Android, use the official
androidx.lifecycle.ViewModel
to scope the VM to the Fragment, but the pattern works much the same on other targets, too, you just have the manage the lifecycle of the ViewModel on your own. The Repository layer is what is managing access to APIs, local databases, handling caching logic, etc, and is generally a Singleton. Any data that needs to be shared between multiple screens should be stored in the Repository layer, and each screen looks up the data it needs from the Repository. Each UI should assume that looking up a value by ID could suspend, but the Repository can cache those fetches to provide a better end-user experience. Feel free to break up your Repository layer into smaller classes as fits your app, for example by domain (
LoginRepository
,
AccountRepository
,
BillingRepository
, etc.) or more granular into individual Use-Cases.
n
Hello Casey! đź‘‹ Thank you for your in-deep answer. And thank you also for your contribution to the open source community. Your idea of a state management library for KMP looks fantastic. So I get what you say, and I feel it makes all the sense. In your approach, technically speaking, it would be the repo layer the one that will be holding the state (the
Store
I was talking about), right? I’m super fine with that; I agree that the ViewModel/Controller shouldn’t really be the one holding the state of the app, but only the state of the view and that is actually nourished from the repository/store layer. I will give a though on this, then. Maybe the repo layer should hold the app state as a big singleton object a la redux and then expose slice functions for the ViewModel/Controllers to get what the want and to modify that state. I just also wanted to point you out to this library, I think you can get inspiration from there to your library too. Thanks again! Edit: I’ve been digging into your library and I see that you’re also proposing a solution to hold the state in the repository layer, that’s great! I’m getting it correctly by saying that your proposal is to have 1 to 1 screen to ViewModel relationship and N to M ViewModel to Repository relationship? State is really held by the repositories and ViewModel’s own state is getting nourished from there (with any needed transformation).
c
Yup, you’ve pretty much got the idea. The Repository layer is more-or-less the “source of truth” for the application runtime, and each Screen hold onto its own local state and observes “slices” of what’s in the Repository, which can be transformed to the needs of the individual screen. So 1 screen has 1 VM but that VM may be talking to several Repositories, and each Repository is potentially shared by many screens. And yes, realizing that the same MVI model could actually work as the Repository layer has made things so much easier to reason about for my team. We were using Dropbox Store before, but had issues when we needed multiple cached values to be used together, and the inner workings were a bit tricky to understand and use correctly. Plus that’s a JVM only library and we’re also investigating iOS, so that’s where the Ballast Repository module came from. It works well in theory, but is quite verbose at the moment and could do with some cleaning up. And yes, I’m aware of MVIKotlin, and actually have a feature table comparing features of several similar libraries in the Ballast docs
n
Oh, that’s great. Thanks for sharing this! 🤗
👍 1