Jetpack Compose's 5-Year Journey: How a 'Bad Idea' Rewrote Android UI
This article traces Jetpack Compose's five-year evolution from a modest attempt to unbundle Android's UI toolkit for faster bug fixes, through its convergence with React-inspired prototypes and Flutter's influence, to a declarative UI framework built on composable functions, Modifier chains, and pragmatic interoperability, culminating in a 1.0 release battle-tested by the Play Store.
Chapter 1: Origin — A Button That Couldn't Be Fixed
The story begins with a fundamental frustration: fixing a bug in the Button class required users to wait for a system OS upgrade, because the UI toolkit was baked into the platform. The team increasingly relied on the Support Library (e.g., RecyclerView) to ship updates independently, sparking the idea to unbundle the entire widget toolkit — a project internally dubbed the Great Widget Migration (GWM).
Ironically, Button was the least problematic widget; the real nightmare was text rendering, where years of buggy behavior had become de facto dependencies for apps, making any correction a compatibility disaster. This "locked by history" problem made the unbundle idea seem essential, yet it topped the Mountain View framework team's "bad ideas" whiteboard for years.
Why the 'Bad Idea' Became Viable
In Android's early days, every byte counted: enums were considered wasteful, code shrinking (pre-R8) was weak, apps were tiny, and RAM was scarce. Bundling a full View toolkit per app was unthinkable. By ~2017, hardware advances, ART's improved GC, and R8's efficiency changed the calculus, making the unbundle feasible. The team realized they were effectively replacing a decade-old toolkit.
Chapter 2: Convergence — Two Parallel Tracks and a Dangerous Phrase
2.1 The Other Track: R4A and the Boston Summit
Simultaneously, engineer Jim built R4A (React for Android) , a Kotlin compiler plugin that brought XML-like tag syntax into Kotlin to generate View hierarchies — similar to JavaScript's E4X. For a long time, the GWM track (widget migration) and R4A track ran separately. Management decided to pick a direction and iterate, even if it meant rewriting later.
The turning point was the 2017 Boston toolkit planning summit. The consensus: React had validated the reactive model on the web, and Google's Flutter had spent three years exploring a similar path. While Flutter's Dart-based stack wasn't directly adoptable, the team asked: "Can we do the same with Kotlin and save three years?" They also brought in Developer Relations (DevRel) and invested heavily in user experience research (UXR) — DevRel ran weekly hackathons on the latest code, profoundly shaping early Compose.
2.2 "While We're At It" — Engineering's Most Dangerous Phrase
The initial goal was modest: escape the platform to fix bugs in the Support Library, keeping the same flawed APIs. But the seductive thought emerged: "Since we're doing all this work, why not rewrite the API the way we actually want it?" This "While we're at it" impulse turned a decoupling project into a full reinvention — Compose.
Chapter 3: Design Philosophy — Subtraction All the Way
3.1 From XML to Classes to Functions
The path to 1.0 was a series of deletions. The earliest codebase was a Kotlin port of Flutter; after merging with R4A, embedded XML (called KTS) appeared in Compose hierarchies. But XML required compiler magic; JetBrains resisted special syntax that could fracture the language ecosystem. The team fell back to classes (like Flutter), then the compiler team showed a top-level function with an annotation could replace the class entirely.
This was highly counterintuitive — critics feared namespace pollution and unfamiliar lambdas. Yet each subtraction brought lightness: no custom syntax, no custom class, just a function developers already understood. The team also learned to trust intuition over survey data: developers initially said they didn't want a new reactive UI toolkit or a new language (Kotlin), yet both became successes. Continuous dogfooding and lucky timing (stable old toolkit, no foldable/XR pressure) gave them space to iterate.
3.2 Modifier: Borrowing from Game Engines
The Modifier concept came from entity-component systems in game/rendering engines: a widget is just a reference; capabilities (rendering, layout) are attached as components. Adam Powell implemented Modifier after discussions. It unlocked massive flexibility: padding became a plugin, not a widget property. Debates raged over boundaries — should Surface be a Modifier or composable? The elegant compromise: composables are entities; Modifiers are decorations. Button today is just Surface plus a chain of Modifiers (~10 lines), making customization trivial compared to rewriting TextView in Java.
3.3 Onion, Cliff, and Stairs
The team aimed for an "onion" architecture: each layer thin and transparent. If Button doesn't fit, peel a layer and copy its 10 lines. The old View system was a "cliff": ListActivity gave a list in two lines, but any customization meant falling off a cliff. Compose provides stairs — you can drill down layer by layer.
Chapter 4: Landing 1.0 — Tools, Interop, and Trial by Fire
4.1 Tooling Debate: Code vs. WYSIWYG
Dropping XML (data) for code broke traditional UI builders. The team built Preview (from the XML layout editor's layoutlib) and @Preview annotations with design-time metadata (like the old tools namespace). Previews coexist with code, never drift during refactors, and Compose's stateless nature encourages preview-friendly structures. Iteration speed remained paramount: Instant Run (2017) tried universal hot patching but left hidden caches; Apply Changes and Live Edit later restricted to Compose, enabling instant constant tweaks (padding, color). The designer-to-code dream (Figma → code) remains unsolved; designers won't use IDEs.
4.2 Defining 1.0: Restraint, Interop, and the Play Store
Replicating 15 years of View features in 1.0 was impossible. The team defined Minimum Viable Products per domain. Text stayed on the platform stack (decoupling it would be another decade). Material components were validated via weekly DevRel hackathons on sample apps ( JetNews , Jetcaster ) — if DevRel could build representative apps (social, news, podcast), the foundation was enough.
Interoperability was a massive investment: rewrite one Button or card, coexist with Java/View code. Borrowed from Kotlin's single-file adoption strategy, it lowered the barrier and provided a two-way escape hatch (e.g., WebView still falls back to View). Interop is credited as the key to real adoption.
The ultimate validation: the Play Store (10+ years old, largest install base) bet on Compose before 1.0 during a major rewrite. This "trial by fire" was painful but decisive; Play Store remains the strictest performance regressor detector. Internally, engineers argued 1.0 wasn't "done," but 1.0's purpose isn't completeness — it signals vision clarity so teams dare adopt. Android 1.0 also cut features frantically before launch. From 1.0 to "ready for all UI" took another five years (until the 2024 Google I/O).
Chapter 5: Retrospective — Commandments, Regrets, and Highlights
5.1 Commandment: Don't Repeat Theming/Styling Mistakes
If Alan and Chris Banes had to explain styles at every I/O, the design was flawed. The team boldly deferred a theming system — "add later, don't carry the baggage now." Result: 20-layer XML indirection vanished; style origins became obvious. Years later, styles returned to fill a remaining "customization cliff" at the component layer — the first API usage change, both tense and exciting.
5.2 Regrets: Drawing API and Performance
Drawing API: Canvas/Paint weren't fully ported; some scenarios still require Android-specific objects, painful for Compose Multiplatform.
Performance: The team worried about performance but underestimated the cost. ART's better GC and hardware progress led to insufficient restraint; some APIs allocate per layout pass. Ergonomics were deliberately prioritized over performance, assuming the runtime would later fix it. Post-1.0, they fixed many issues without API changes, deprecating expensive lambda-bearing Modifiers — proving ergonomics and caution can coexist. R8 helped significantly. The trade-off is deemed worth it: a "super-performant Views 2.0" would have left developers regretting the API.
5.3 Highlights: Slot API, Function-as-Widget, and Self-Dogfooding
Slot API: Realizing a component could accept a lambda (slot) for content dissolved many hard problems, including the original Button dilemma.
Full rewrites enabled by decoupling: Semantics, layout, Modifier were entirely rewritten — only possible because they left the platform.
Function-as-widget: Makes state hoisting unavoidable (state appears in function parameters). Decisions that felt uncomfortable often proved correct.
Pragmatic migration focus: Instead of just enjoying a greenfield framework, they obsessed over bidirectional View compatibility.
Tools team eating their own dogfood: ~1 year ago, Android Studio's new UI (especially AI agent interfaces) moved to Compose. Tool builders experienced elegant animated transitions and UX details firsthand — shifting from "hoping others like it" to "loving it ourselves."
Cross-platform foresight: Android remained priority, but the codebase retained multiplatform hooks from day one; JetBrains launched Compose Multiplatform pre-1.0, now thriving thanks to that foresight.
Closing Thoughts
The team fiercely opposed shipping 1.0 — too much undone. But perfection is asymptotic; no one risks production on 0.x. 1.0 means "direction clear, safe to board." The most moving aspect: a great project's honest origin — not a grand vision, but a humble pain point plus engineers' dangerous "while we're at it." That phrase can start a runaway train or a great refactor's first footnote. The difference: knowing how much you'll pay for the API you truly want, and keeping pragmatic empathy for migrators amid the rewrite-it-all urge. Compose's five-year answer: worth it.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
AndroidPub
Senior Android Developer & Interviewer, regularly sharing original tech articles, learning resources, and practical interview guides. Welcome to follow and contribute!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
