Skip to content
Source

Effects and Compose

On air the regular rubric "someone fought on the internet". Today on the agenda is this exchange of tweets. It all starts with mundane hating on Compose, and then one of the Compose developers comes in and it's off to the races.

Key points:

  • Using effects is generally a bad practice
  • Our documentation in this sense teaches people bad things, we tried to convey this to devrels, they don't listen
  • The remember function is also better not to use except for some use cases like animations. ✏️

And these are pretty funny insights. It's clear where this desire comes from for Composable functions to be (conditionally) pure, but in life in my opinion it doesn't really work, given the mountains of our legacy behind the Compose world.

Too bad the alternatives aren't really revealed. I dug into our code base and tried to formulate our use cases for effects.

  • First, they're still used somewhere under the hood of collectAsState*. I'm not sure if this is considered a bad practice. But without this, it seems, we can't at all in the place where we're trying to connect a Composable function with some logical component, for example a viewmodel, literally in all popular approaches to architecture.
  • Second, these are subscriptions to various Flows, since only inside effects do we have a scope. And all this could be handled somewhere in those same logical components, if we didn't need to interact with these events with UI or platform things. Somewhere we have shitty Material APIs like bottom sheets and snackbars, which in m2 you can neither hide nor show without coroutines. Somewhere we need an activity context, for example, to open another activity. Somewhere we have rakes under the leaves in the form of AndroidView, with which you need to communicate imperatively. Somewhere we have to wrap permissions and Result API in all this. And what to do without effects?
  • Third, this is often used as a callback from UI that it started drawing there, like "business logic, start up". In this case I agree, you don't have to pull this to the Composable level. With remember I also mostly agree in product code, but when we write a library not so much. The guys at Accompanist won't let you lie.

In general, a typical fight between those who write a tool and assume how it should be used, and those who try to apply it in practice and fight with the whole world just to get it running at all, and don't care how ideologically pure it is. You can understand both sides, but both aren't very right. We understand that all this is better not to use if you can do without. We'd also like to write such Composable functions that simply accept already prepared state. But it's impossible, either from the point of view of existing libraries (from other Google departments), or from the point of view of legacy, or from the point of view of performance, or simply the alternative is so boilerplate that it's easier for the whole community this way.