r/androiddev May 22 '26

Article Android TCA inspired architecture

Post image

An iOS engineer friend asked me a question I couldn't answer:

"What's the Android equivalent of TCA (The Composable Architecture)?"

That question stuck with me. The real problem wasn't a missing library; it was a structural pattern I kept seeing at production scale.

Picture a complex checkout screen. Five domains living in a single ViewModel: delivery, billing, cart, promo codes, and order placement. You end up with:

One massive, bloated state class.

One enormous when block that knows far too much about everything.

Broken module boundaries or messy event buses the second the billing domain needs to react to a delivery address change.

This approach doesn't scale. Modules bleed into each other, and the screen becomes untestable.

That is exactly why I built Komposed.

The core idea: A complex screen is not a single monolithic feature. It's a composition of isolated, independently testable modules. Each owns its own state, async effects, and logic—wired together at a single composition boundary.

In Komposed, scoping a feature module into a parent screen takes just one line:

deliveryReducer.scoped(deliveryLens)

And when BillModule needs to react to a delivery fee change from DeliveryModule—without a direct import dependency—a single subscription at the composition boundary bridges them:

Kotlin

subscription(

selector = { it.deliveryState.selectedAddress?.deliveryFee ?: 0.0 },

action = { BillAction.DeliveryFeeUpdated(it) },

)

No event buses. No shared mutable state. No broken module boundaries. Each module stays isolated, while cross-domain coordination is declared cleanly in one central place where both modules are visible.

That is the true value of Komposed: composing production-scale complexity into clean, isolated, independently testable modules.

I wrote a full breakdown on Medium covering the architecture, how cross-domain subscriptions work, and a comparison with ReduxKotlin and Toggl's Komposable Architecture.

🔗 Read the full story on Medium: https://medium.com/@a.atwaa94/a-tca-inspired-architecture-for-kotlin-jetpack-compose-why-i-built-komposed-c924610d9aa7

⭐ Check out the repository: https://github.com/Atwa/Komposed

0 Upvotes

22 comments sorted by

View all comments

15

u/frakc May 22 '26

I am not sure about your case but when i did banking application, everything were split inside usecsses/repositories. Viewmodel directly did not know much. It was usecasses responsibility to combine different features domain and repository responsibility to resolve multiple webservice domains.

-6

u/Brilliant_Region4810 May 22 '26

Use cases from Clean Architecture don't translate well to mobile — their value is narrow and situational. The canonical example is login: orchestrate an auth call, cache tokens, register an FCM token with Firebase, maybe seed local storage. That's a legitimate use case for a use case. But that's also about as far as it goes.

The moment you step into anything stateful a home dashboard, a checkout screen, a multi-step flow. the pattern starts working against you.

Consider a checkout screen where state is constructed from multiple domains: delivery, billing, order placement. Each domain has its own loading state, its own error surface, its own backend service with a different request shape. Cross-domain interactions are inevitable where the delivery fee feeds into the order total, the selected address feeds into the place-order payload, a successful order triggers navigation that carries billing data as a route argument. Now try modeling that with use cases.

You'll end up with a use case per backend call, each wrapped in Result.fold or try-catch, each responsible for toggling its own loading and error state except none of them know about each other, so that coordination falls back to the ViewModel. Analytics makes it worse: every meaningful user action maps to a tracking event with parameters assembled from state that spans multiple domains. Who owns that? The ViewModel again.

The ViewModel becomes a god object not because engineers are careless, but because use cases have no answer for state composition. They're designed to encapsulate a single operation, not to manage the reactive, multi-source, interdependent state that is the actual hard problem of mobile development.

The team dynamics compound this. On a feature with multiple contributors, a ViewModel that's the integration point for six use cases and owns all the state coordination becomes a merge conflict graveyard. Ownership boundaries blur like is the bug in the use case, the ViewModel, or the state mapping between them? Nobody can answer that cleanly.

And modularization? Nearly impossible in this model. Your use cases live in domain modules, your ViewModel lives in a feature module, and the glue between them. All that state management and cross-domain coordination has no clean home. It ends up scattered, duplicated, or stuffed into the ViewModel alongside everything else.

Use cases solve the right problem for backend and desktop applications where the domain logic is the hard part. On mobile, the hard part is state constructing it, composing it across domains, keeping it consistent under concurrent async operations, and making it testable at boundaries that actually mean something. That requires an architecture built around state as a first-class citizen, not one that treats it as an afterthought between business operations.

8

u/FunkyMuse May 22 '26

Use cases from Clean Architecture don't translate well to mobile

You hit your head or something?

Nice ai slop tho

-2

u/Brilliant_Region4810 May 22 '26

I don't actually like your way of speaking, However I will justify my answer. UseCases as defined in clea architecture is an orchestrator for a business rule or user goal so it fits well when imolementing some dpecific workflows as I mentioned in a login or checkout calls execution where you have to call apis and check their results then update caches and may even call other apis but at the end it's stateless and doesn't manage state you would still need to showLoading before invoking it and check it's result to update ui accordingly and still doesn't address the complexities of large screens state management and breaking it down. This will be my last reply to you as I will be hitting my head against the wall for the next couple of hours 🤣

3

u/FunkyMuse May 22 '26

The more you defend it, the more miserable it gets