I wasn’t excited about Jetpack Compose. There. I said it.
When it first came out, it felt like Flutter in a different outfit. Kotlin instead of Dart. Same declarative energy. And look, I didn’t have anything against Flutter. Once you get comfortable with it you can build a solid multiplatform app.
I just didn’t feel the need to adopt something new. XML worked. Views worked. We were shipping.
And then there was the terminology. <insert multiple facepalms> mutableStateOf. derivedStateOf.
It sounded like I needed an encyclopedia just to build a button. I wasn’t eager to relearn concepts I already understood — definitely a lot of “get off my lawn” going on.
Back in 2017 at Google I/O, I ran into Dave Burke. He was leading Android at the time. I asked him what he thought about Flutter. Was it the future? Should we all be paying closer attention?
He didn’t tip his hand. But he mentioned that declarative UI had clear advantages. I remember nodding politely. It was Dave after all. But I wasn’t fully sold.
Years later, however, that comment made a lot more sense.
Shifting my thinking
The shift didn’t happen in a keynote. It happened while debugging. You know the kind of bug I’m talking about. The tiny one that somehow eats the rest of your day.
The button that won’t show the correct state.
The view that’s holding onto old data.
The binding variable you’re absolutely sure you updated.
With XML-based layouts, everything feels stable… until it doesn’t. And when it doesn’t, you’re tracing lifecycle callbacks, adapter updates, wondering if you missed a refresh somewhere. Maybe you forgot to notify the adapter. Maybe the fragment reattached. Maybe something else entirely.
You start second guessing everything.
It’s not chaos. It’s cognitive drag. And cognitive drag compounds.

That’s what I had quietly accepted. It’s what the entire Android community just accepted.
Compose changed that experience for me. For us.
Composables emit UI. They don’t return views. They’re designed to be idempotent and free of side effects. The screen becomes a reflection of state — not a bunch of view mutations scattered across callbacks and listeners.
When something looks wrong, the question narrows fast: “What state is this reading?” That’s it.
And when state changes, only the composables that depend on it are recomposed. Just data and a UI reacting to it. It’s subtle. But subtle things add up.
Supporting multiple screens
The second moment it clicked was form factors. Developing for phones is pretty easy.
Then someone asks for tablet support. Or a different width breakpoint. And suddenly you’re juggling alternative resources and hoping nothing was missed between layout files — because yes, that happens.
Compose Previews made that feel almost unfair. I could see how the UI behaved across sizes without deploying. Without juggling emulators. Without guessing. I’d tweak something and immediately see if it broke on a wider layout.
The feedback loop shortened.
And shorter feedback loops change behavior. You experiment more. You try ideas you would have previously talked yourself out of. You catch layout issues before they become production bugs.

You develop with more confidence.
Writing tests for Compose
The testing story surprised me too. The first time I wrote a set of Compose UI tests I remember thinking, this can’t be it. But it was.
The semantics tree and testing APIs make it straightforward to assert on behavior. I wasn’t digging for view IDs just to confirm that a button reacted properly. I wasn’t fighting the framework to test the thing I just built.
Back in 2021, when Compose was still early, I wrote about testing hybrid Jetpack Compose apps — mixing View-based screens with composables and figuring out how to test across that boundary. At the time, it felt experimental. A little scrappy. Like we were bridging two worlds.
Looking back, that post reads like a transition period.
Testing composables today feels far more direct. Less wiring. Less “did I hook this up correctly?” Testing composables is… calm. I like calm.
And calm engineering environments tend to produce better results.
The bottom line
After a while, I stopped thinking about the “mechanics” of Compose. The pattern just felt natural.
State flowed down. Events flowed up. It wasn’t something I had to force.
The runtime behaves in a way that matches how you naturally think about changes. But don’t get me wrong. There’s still complexity — there’s always complexity — but it shows up in more predictable places.
Less framework song and dance. More product thinking. That difference compounds across a team.
I’ve led enough engineering organizations to know this: the biggest slowdowns rarely come from lack of talent. They come from friction that everyone has normalized.
Compose removed some friction I didn’t realize we were carrying. And once you notice friction disappearing, it’s hard to ignore.