Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Strategies for Migrating to Jetpack Compose

Mohit S
April 19, 2022

Strategies for Migrating to Jetpack Compose

Mohit S

April 19, 2022
Tweet

More Decks by Mohit S

Other Decks in Programming

Transcript

  1. Mohit Sarveiya
    Strategies for Migrating to Jetpack Compose
    @heyitsmohit

    View full-size slide

  2. Strategies for Migrating to Jetpack Compose
    ● Challenges

    ● How to think about migration

    ● Strategies & Tools

    View full-size slide

  3. Code size
    Code

    size
    Time

    View full-size slide

  4. Greenfield Project
    ● Easier to use Compose

    ● Fewer roadblocks to use Compose

    View full-size slide

  5. Code size
    Code

    size
    Time

    View full-size slide

  6. Roadmap
    0% Compose
    100% Compose

    View full-size slide

  7. Roadmap
    0% Compose
    100% Compose
    Roadblock
    Roadblock

    View full-size slide

  8. Roadmap
    ● Long road

    ● Obstacles along the way

    View full-size slide

  9. Arch Fragmentation
    Codebase

    View full-size slide

  10. Arch Fragmentation
    Codebase
    Legacy code

    View full-size slide

  11. Arch Fragmentation
    Codebase
    Legacy code
    Feature A
    Feature B

    View full-size slide

  12. Challenges
    ● Interoperability

    View full-size slide

  13. Interop
    ● Compose to old view system

    View full-size slide

  14. Interop
    Codebase
    Feature A
    Compose View
    Legacy code

    View full-size slide

  15. Interop
    Codebase
    Legacy code
    Feature A
    Compose View

    View full-size slide

  16. Interop
    ● Compose to old view system

    ● Use old views in Compose

    View full-size slide

  17. Interop
    Codebase
    Legacy code
    Feature A
    Custom View

    View full-size slide

  18. Interop
    Codebase
    Feature A
    Compose with

    Custom View
    Legacy code

    View full-size slide

  19. Challenges
    ● Interoperability

    ● Architecture

    View full-size slide

  20. Architecture
    Codebase
    Legacy code

    View full-size slide

  21. Arch Challenges
    ● Not using composition over inheritance

    View full-size slide

  22. Legacy Code
    Base Fragment Too much logic

    View full-size slide

  23. Legacy Code
    Base Fragment Too much logic
    Fragment Fragment Fragment

    View full-size slide

  24. Legacy Code
    Base Fragment
    Fragment Fragment Fragment

    Refactor to Compose

    View full-size slide

  25. Legacy Code
    Base View
    Holders
    Too much logic

    View full-size slide

  26. Legacy Code
    Base View
    Holders
    Too much logic
    View Holder View Holder View Holder

    Refactor to Compose

    View full-size slide

  27. Arch Challenges
    ● Not using composition over inheritance

    ● Navigation

    View full-size slide

  28. App Architecture
    API
    Domain
    Navigation
    UI

    View full-size slide

  29. Navigation
    NavHost(navController, startDestination = "profile") {

    composable("profile") {

    Profile(
    /*...*/
    )

    }

    composable("friendslist") {

    FriendsList(
    /*...*/
    )

    }

    }

    View full-size slide

  30. Legacy Navigation
    Main Activity Activity Activity

    View full-size slide

  31. Navigation
    Main Activity
    Fragment A Fragment B Fragment C
    ...

    View full-size slide

  32. Challenges
    ● Interoperability

    ● Architecture

    ● Testing

    View full-size slide

  33. Testing
    Codebase 1% Code coverage
    5% Code coverage

    View full-size slide

  34. Challenges
    ● Interoperability

    ● Architecture

    ● Testing

    ● Tooling

    View full-size slide

  35. Compose Upgrades
    Version
    Time
    alpha05
    alpha06

    View full-size slide

  36. Challenges
    ● Interoperability

    ● Architecture

    ● Testing

    ● Tooling

    View full-size slide

  37. Collaboration
    Org
    CI Arch Design Team Feature Teams
    Teams

    View full-size slide

  38. Roadmap
    0% Compose
    100% Compose

    View full-size slide

  39. Roadmap
    0% Compose
    100% Compose
    Milestone
    Milestone

    View full-size slide

  40. Proposal
    ● Specify milestones over time

    ● Assess & Mitigate Risks

    ● Documentation

    View full-size slide

  41. Roadmap
    0% Compose
    100% Compose
    Milestone

    View full-size slide

  42. Complexity
    Codebase
    High
    Low
    Medium

    View full-size slide

  43. Migration Phase 1
    Complexity
    Migration time
    Low

    View full-size slide

  44. Migration Phase 2
    Complexity
    Migration time
    Medium

    View full-size slide

  45. Migration Phase 1
    ● Migrate Design Components

    View full-size slide

  46. Example
    Feature A Feature B Feature C
    Common

    Design Components

    View full-size slide

  47. Example
    Common

    Design Components
    App A App B
    App C

    View full-size slide

  48. Collaboration
    Org
    CI Arch Design Team Feature Teams
    Teams

    View full-size slide

  49. Migration Phase 1
    ● Migrate design components to Compose

    View full-size slide

  50. Interoperability

    View full-size slide

  51. Interop
    9:41
    Convert to compose

    View full-size slide

  52. Interop


    />


    />


    />


    />



    FrameLayout>

    9:41

    View full-size slide

  53. Interop


    />


    />


    />


    />



    FrameLayout>

    9:41

    View full-size slide

  54. Interop


    />


    />



    android:id="@+id/compose_view"

    android:layout_width="match_parent"

    android:layout_height="wrap_content"
    />



    FrameLayout>

    View full-size slide

  55. Compose View
    binding.composeView.apply {

    setContent {

    }

    }

    View full-size slide

  56. Compose View
    binding.composeView.apply {

    setContent {

    MaterialTheme {

    DescriptionView()

    }

    }

    }

    View full-size slide

  57. Challenges
    strings.xml
    dimen.xml
    theme.xml
    Compose
    Resuse

    View full-size slide

  58. Compose View
    @Composable

    fun DescriptionView() {

    Text(

    text = stringResource(id = R.string.title)

    )

    }

    View full-size slide

  59. Compose View
    @Composable

    fun DescriptionView() {

    Text(

    modifier = Modifier.padding(dimensionResource(R.id.margin_small))
    )

    }

    View full-size slide

  60. Challenges
    ● How do you reuse dimen and string resources?

    ● Interop Theming

    View full-size slide

  61. Challenges
    strings.xml
    dimen.xml
    theme.xml
    Compose
    Resuse

    View full-size slide

  62. Interop Theming
    implementation “com.google.android.material:compose-theme-adapter:1.1.1”

    View full-size slide

  63. Interop Theming
    binding.composeView.apply {

    setContent {

    MaterialTheme {

    DescriptionView()

    }

    }

    }

    View full-size slide

  64. Interop Theming
    binding.composeView.apply {

    setContent {

    MdcTheme {

    DescriptionView()

    }

    }

    }

    View full-size slide

  65. Challenges
    ● How do you reuse dimen and string resources?

    ● Interop Theming

    ● View lifecycle

    View full-size slide

  66. Compose View
    binding.composeView.apply {

    setContent {

    setViewCompositionStrategy(

    ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed

    )

    }

    }

    View full-size slide

  67. Phase 1 Migration
    Common

    Design Components
    App A App B
    App C

    View full-size slide

  68. Common Design Components
    ● View all compose components

    ● Document design system

    View full-size slide

  69. airbnb/Showkase
    Code ! Issues Pull Requests
    Showkase

    Compatible with Compose 1.0.4
    Showcase 1.0.0-beta12
    Showkase is an annotation-processor based Android library that
    helps you organize, discover, search and visualize Jetpack
    Compose UI elements.

    View full-size slide

  70. Showkase
    9:41
    App
    com.app
    General
    Logs
    Other
    Keyline overlay
    Slow down animations
    Network Activity
    Logs
    Lifecycle logs
    Show UX

    View full-size slide

  71. Showkase
    9:41
    App
    com.app
    General
    Logs
    Other
    Keyline overlay
    Slow down animations
    Network Activity
    Logs
    Lifecycle logs
    Show UX
    9:41
    Design Components
    Components
    Colors
    Typography

    View full-size slide

  72. Showkase
    Compose Design Spec
    Generate

    View full-size slide

  73. Showkase
    @ShowkaseRoot

    class AppRootModule: ShowkaseRootModule

    View full-size slide

  74. Showkase
    startActivity(Showkase.getBrowserIntent(this))

    View full-size slide

  75. Showkase
    @Preview(name = “Custom component", group = "Custom group")

    @Composable

    fun PostView()

    View full-size slide

  76. Showkase
    9:41
    Design Components
    Post view
    Title

    View full-size slide

  77. Arch Fragmentation
    Codebase
    Legacy code
    100% Compose
    100% Compose

    View full-size slide

  78. Interop
    @Composable

    fun PostView() {

    AndroidView(factory = { context
    ->






    })

    View full-size slide

  79. Interop
    @Composable

    fun PostView() {

    AndroidView(factory = { context
    ->


    CustomView(context).apply {

    layoutParams = LinearLayout.LayoutParams(

    MATCH_PARENT,

    WRAP_CONTENT

    )

    }

    })

    View full-size slide

  80. Interop
    ● ComposeView

    ● AndroidView

    View full-size slide

  81. Migration Phase 1
    ● Migrate Design Components

    View full-size slide

  82. Roadmap
    0% Compose
    100% Compose
    Milestone

    View full-size slide

  83. Roadmap
    0% Compose
    100% Compose
    Milestone
    Milestone

    View full-size slide

  84. Migration Phase 2
    Complexity
    Migration time
    Medium

    View full-size slide

  85. Testing
    Codebase 1% Code coverage
    5% Code coverage

    View full-size slide

  86. Migration Phase 2
    ● Migrate medium complexity features

    ● Setup scaffolding to catch regressions

    View full-size slide

  87. Testing Infra
    Compose Conversions
    Testing Infra

    View full-size slide

  88. Goals
    ● Catch regressions earlier

    ● Increase covers with compose migration

    View full-size slide

  89. Testing Infra
    ● Snapshot testing

    ● UI Testing Interop

    View full-size slide

  90. cashapp/paparazzi
    Code ! Issues Pull Requests
    Paparazzi

    An Android library to render your application screens without
    a physical device or emulator.

    View full-size slide

  91. Paparazzi
    Screenshot
    Unit Test

    View full-size slide

  92. Paparazzi
    ● 1.0.0-Snapshot has compose support

    View full-size slide

  93. Paparazzi
    @get:Rule

    val paparazzi = Paparazzi()

    View full-size slide

  94. Paparazzi
    @get:Rule

    val paparazzi = Paparazzi()

    @Test

    fun testView() {

    paparazzi.snapshot {

    PostView(uiState)

    }

    }

    View full-size slide

  95. Paparazzi
    9:41
    Post
    Title

    View full-size slide

  96. Paparazzi
    Git (LFS)
    Snapshot

    View full-size slide

  97. Testing Infra
    ● Snapshot testing

    ● UI Testing Interop

    View full-size slide

  98. Interop


    />


    />


    />



    FrameLayout>

    9:41

    View full-size slide

  99. Interop
    9:41
    Semantics Tree

    View full-size slide

  100. Compose UI Testing
    @get:Rule

    val composeTestRule = createAndroidComposeRule()

    View full-size slide

  101. Compose UI Testing
    @Test

    fun postViewTest() {

    composeTestRule.onNodeWithText(“Title").assertIsDisplayed()

    }

    View full-size slide

  102. Interop
    @Composable

    fun PostView() {

    AndroidView(factory = { context
    ->


    CustomView(context)

    })

    }

    View full-size slide

  103. Interop
    @Test

    fun postViewTest() {

    composeTestRule.onNodeWithText("Submit").performClick()

    }

    View full-size slide

  104. Interop
    @Test

    fun postViewTest() {

    composeTestRule.onNodeWithText(“Submit").performClick()

    Espresso.onView(withText(“Success")).check(matches(isDisplayed()))

    }

    View full-size slide

  105. Migration Phase 2
    ● Migrate medium complexity features

    ● Setup scaffolding to catch regressions

    View full-size slide

  106. Migration Phases
    0% Compose Milestones

    View full-size slide

  107. Migration Phases
    ● Milestones depend on complexity & code size

    ● Low Complexity
    ->
    High Complexity

    View full-size slide

  108. Migration Phases
    0% Compose Milestones
    Testing Infra

    View full-size slide

  109. Internationalization

    View full-size slide

  110. Migration Phases
    0% Compose Milestones

    View full-size slide

  111. Languages Support
    strings.xml
    values-en
    values-de
    values-fr
    strings.xml
    strings.xml

    View full-size slide

  112. Languages Support
    Add strings

    View full-size slide

  113. Languages Support
    Translation service
    Add strings

    View full-size slide

  114. Languages Support
    Translation service
    Provides translated strings
    Add strings

    View full-size slide

  115. Languages Support
    ● Compose language interop

    View full-size slide

  116. adrielcafe/lyricist
    Code ! Issues Pull Requests
    Lyricist

    The missing I18N and L10N multiplatform library for Jetpack
    Compose!

    View full-size slide

  117. Languages Support
    Strings

    (xml)
    Types
    KSP
    Composition

    Local

    View full-size slide

  118. Languages Support
    strings.xml
    values
    values-pt
    strings.xml

    View full-size slide

  119. Languages Support


    Hello world

    string>



    Avocado

    item>


    string-array>



    %d zero

    item>


    plurals>


    resources>

    View full-size slide

  120. Languages Support


    Olá mundo

    string>



    Abacate

    item>


    string-array>



    %d zero

    item>


    plurals>


    resources>

    View full-size slide

  121. Languages Support
    ksp {

    arg("lyricist.xml.resourcesPath",

    android.sourceSets.main.res.srcDirs.first().absolutePath)

    arg("lyricist.xml.moduleName", “xml")

    arg("lyricist.xml.defaultLanguageTag", "en")

    }

    View full-size slide

  122. Languages Support
    data class Strings(

    val greeting: String,

    val array: List,

    val plurals: (quantity: Int)
    ->
    String

    )

    object Locales {

    val En = "en"

    val Pt = "pt"

    }

    View full-size slide

  123. Languages Support
    @Composable

    public fun ProvideStrings() {

    CompositionLocalProvider(

    provider provides lyricist.strings

    )

    }

    View full-size slide

  124. Languages Support
    @Preview

    @Composable

    fun PostViewPreview() {



    val xmlStrings = rememberXmlStrings()

    ProvideXmlStrings(xmlStrings) {

    Text(text = xmlStrings.greeting)

    }

    }

    View full-size slide

  125. Languages Support
    @Preview

    @Composable

    fun PostViewPreview() {



    val xmlStrings = rememberXmlStrings()

    ProvideXmlStrings(xmlStrings) {

    Text(text = xmlStrings.greeting)

    }

    }

    View full-size slide

  126. Languages Support
    @Preview

    @Composable

    fun PostViewPreview() {



    val xmlStrings = rememberXmlStrings()

    ProvideXmlStrings(xmlStrings) {

    Text(text = xmlStrings.greeting)

    }

    }

    View full-size slide

  127. Languages Support
    @Preview

    @Composable

    fun PostViewPreview()

    9:41
    Post
    Hello World

    View full-size slide

  128. Languages Support
    @Preview(locale = “pt”)

    @Composable

    fun PostViewPreview()

    9:41
    Post
    Olá mundo

    View full-size slide

  129. Migration Phases
    0% Compose Milestones

    View full-size slide

  130. Kotlin Upgrades
    This version (1.1.1) of the Compose Compiler requires

    Kotlin version 1.6.10 but you appear to be using

    Kotlin version 1.6.20 which is not known to be compatible.

    View full-size slide

  131. Kotlin Upgrades
    composeOptions {

    kotlinCompilerExtensionVersion compose_version

    suppressKotlinVersionCompatibilityCheck true

    }

    Not Recommended

    View full-size slide

  132. Kotlin Upgrades
    ● Wait for compose to be updated

    View full-size slide

  133. Kotlin Upgrades
    ● Wait for compose to be updated

    ● Test out compose upgrades

    View full-size slide

  134. Kotlin Upgrades
    ● Wait for compose to be updated

    ● Test out compose upgrades

    View full-size slide

  135. Strategies for Migrating to Jetpack Compose
    ● Challenges

    ● How to think about migration

    ● Strategies & Tools

    View full-size slide

  136. Thank You!
    www.codingwithmohit.com
    @heyitsmohit

    View full-size slide