7+1 tips about [Android] App Modularization | droidcon Madrid 19

7+1 tips about [Android] App Modularization | droidcon Madrid 19

Nowadays, App modularization is a technique largely adopted that gives lots of advantages. But how to approach it?
This talk will not focus on the pro and cons of modularization but instead on the approach and the process to achieve it. In particular, I want to share the approach that I followed to modularize an existing application and a new one. I want also to share the failures and all the struggles that came in my head while approaching the process.

9da5d5cc4b6a9f28058152e28364b02a?s=128

Marco Gomiero

December 20, 2019
Tweet

Transcript

  1. 2.

    ! What this talk is not about • 101 about

    modularization • Pro and cons droidcon Madrid 19 - @marcoGomier
  2. 3.

    ! What this talk is about • 101 about modularization

    • Pro and cons • Approach and process • Failure and struggles droidcon Madrid 19 - @marcoGomier
  3. 4.

    Marco Gomiero ! Mobile Engineer @ Uniwhere "# $ Co-Lead

    @ GDG Venezia ! Stalking info • Twitter: @marcoGomier • Github: prof18 • Website: marcogomiero.com droidcon Madrid 19 - @marcoGomier
  4. 5.

    Uniwhere We use data to make students' journey from college

    to the job market less stressful • ! Started in 2015 as MVP • " Lots of iterations • # Time for [more] solid architecture droidcon Madrid 19 - @marcoGomier
  5. 6.
  6. 9.

    Modularization in few words emojis • ! Simple development •

    "# Split responsibilities • $ Reusable modules Source: https://speakerdeck.com/beraldofilippo/the-clean-cut?slide=10
  7. 10.

    Modularization in few words emojis • ! Dynamic features modules

    • " Faster Builds • # Simple test automation Source: https://speakerdeck.com/beraldofilippo/the-clean-cut?slide=10
  8. 11.
  9. 14.

    Jeroen Mols's series about modularization 1. Modularization - Why you

    should care 2. Modularization - A successful architecture 3. Modularization - Real-life example 4. Modularization - How to approach 5. Modularization - Lessons learned https://jeroenmols.com/blog/
  10. 20.

    Monolithic Application └── app └── src └── main └── java

    └── com.prof18.myapplication ├── DashboardFragment.kt ├── HomeFragment.kt ├── MainActivity.kt ├── NotificationsFragment.kt ├── ProfileActivity.kt └── ProfileSettingsActivity.kt droidcon Madrid 19 - @marcoGomier
  11. 21.
  12. 23.
  13. 24.
  14. 25.
  15. 26.

    Think a feature as a flow of screens [in the

    same context] droidcon Madrid 19 - @marcoGomier
  16. 30.

    Library Modules • Android or Pure Kotlin library • Never

    depend on feature or app • A library can depend on another droidcon Madrid 19 - @marcoGomier
  17. 31.

    Feature Modules • Android library • Never depend on other

    features or app • Depends on one or more libraries droidcon Madrid 19 - @marcoGomier
  18. 32.

    App Module • Android application • Link all the modules

    together • Depends on other features and library droidcon Madrid 19 - @marcoGomier
  19. 33.

    Monolithic Application └── app └── src └── main └── java

    └── com.prof18.myapplication ├── DashboardFragment.kt ├── HomeFragment.kt ├── MainActivity.kt ├── NotificationsFragment.kt ├── ProfileActivity.kt └── ProfileSettingsActivity.kt droidcon Madrid 19 - @marcoGomier
  20. 34.

    Modularized App [1] ├── app │ └── src │ └──

    main │ └── java │ └── com.prof18.myapplication │ └── MainActivity.kt │ droidcon Madrid 19 - @marcoGomier
  21. 35.

    Modularized App [2] └── features ├── home │ └── src

    │ └── main │ └── java │ └── com.prof18.myapplication.features.home │ ├── DashboardFragment.kt │ ├── HomeActivity.kt │ ├── HomeFragment.kt │ └── NotificationsFragment.kt └── profile └── src └── main └── java └── com.prof18.myapplication.features.profile ├── ProfileActivity.kt └── ProfileSettingsActivity.kt droidcon Madrid 19 - @marcoGomier
  22. 37.

    How about navigation? • Within a feature -> "Classic way",

    e.g. explicit intent, navigation component • Between features -> Implicit intent droidcon Madrid 19 - @marcoGomier
  23. 38.

    Between features navigation Declare the implicit intent in the Manifest

    <activity android:name="com.prof18.filmatic.features.home.ui.HomeActivity" android:theme="@style/AppTheme.NoActionBar"> <intent-filter> <action android:name="com.prof18.filmatic.features.home" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> droidcon Madrid 19 - @marcoGomier
  24. 39.

    Between features navigation Create an object to help you with

    the boilerplate object Actions { fun openHomeIntent(context: Context): Intent = internalIntent(context, "com.prof18.filmatic.features.home") private fun internalIntent(context: Context, action: String) = Intent(action).setPackage(context.packageName) } droidcon Madrid 19 - @marcoGomier
  25. 41.

    Pull Code Up • Treat the old code "as a

    library" and then create new modules • A gentle process droidcon Madrid 19 - @marcoGomier
  26. 42.

    Pull Code Down • Hold the app together and then

    extract new modules • A more aggressive process droidcon Madrid 19 - @marcoGomier
  27. 43.
  28. 44.

    Pull Code Up 1. Create new module core 2. All

    existing code into core 3. New app module that decides what to open 4. Extract a new feature from core 5. … droidcon Madrid 19 - @marcoGomier
  29. 45.
  30. 47.
  31. 48.

    Change of strategy: Pull Code Down 1. Maintain all the

    code in the existent app module 2. Move [some] common code to the core module 3. Start creating new features and libraries droidcon Madrid 19 - @marcoGomier
  32. 50.

    Fail as fast as you can • It's ok to

    fail during this process • Keep pushing • Allocate a big initial push to get things started droidcon Madrid 19 - @marcoGomier
  33. 53.

    String resources • Each module has its strings • Common

    strings on core module • ! for separation of concerns • " to maintain with a "translation platform" droidcon Madrid 19 - @marcoGomier
  34. 54.

    String resources • Each module has its strings • Common

    strings on core module • All strings on core module droidcon Madrid 19 - @marcoGomier
  35. 57.
  36. 61.

    How to approach a no Dagger project? • Start gently

    with some [common] dependencies • Continue with more dependencies droidcon Madrid 19 - @marcoGomier
  37. 63.

    Modules configuration We need a smart way to handle dependencies

    and configurations across all modules droidcon Madrid 19 - @marcoGomier
  38. 64.

    SDK Configuration subprojects { afterEvaluate { project -> if (project.hasProperty('android'))

    { android { buildToolsVersion Config.buildTools compileSdkVersion Config.compileSdk defaultConfig { minSdkVersion Config.minSdk targetSdkVersion Config.targetSdk testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } compileOptions { sourceCompatibility Config.javaVersion targetCompatibility Config.javaVersion } } } } } droidcon Madrid 19 - @marcoGomier
  39. 65.

    SDK Configuration object Config { val minSdk = 21 val

    compileSdk = 29 val targetSdk = 29 val javaVersion = JavaVersion.VERSION_1_8 val buildTools = "29.0.0" } droidcon Madrid 19 - @marcoGomier
  40. 66.

    Dependency Management object Versions { val appcompat = "1.0.2" val

    design = "1.0.0" val cardview = "1.0.0" ... } object Deps { val appcompat = "androidx.appcompat:appcompat:${Versions.appcompat}" val design = "com.google.android.material:material:${Versions.design}" val cardview = "androidx.cardview:cardview:${Versions.cardview}" ... } droidcon Madrid 19 - @marcoGomier
  41. 68.

    Common dependencies: dependencies { implementation Deps.appcompat implementation Deps.constraintLayout implementation Deps.design

    implementation Deps.vectorDrawable implementation Deps.timber } apply from: '../../shared_dependencies.gradle' droidcon Madrid 19 - @marcoGomier
  42. 70.

    Dependencies Update ./gradlew dependencyUpdates ------------------------------------------------------------ : Project Dependency Updates (report

    to plain text file) ------------------------------------------------------------ The following dependencies are using the latest milestone version: - androidx.cardview:cardview:1.0.0 - androidx.constraintlayout:constraintlayout:2.0.0-beta3 - androidx.emoji:emoji-bundled:1.0.0 .... The following dependencies have later milestone versions: - androidx.appcompat:appcompat [1.1.0 -> 1.2.0-alpha01] https://developer.android.com/jetpack/androidx - androidx.browser:browser [1.0.0 -> 1.2.0-rc01] https://developer.android.com/jetpack/androidx - androidx.core:core-ktx [1.0.1 -> 1.2.0-rc01] droidcon Madrid 19 - @marcoGomier
  43. 72.

    What approach to follow? A big sprint? Small chunks of

    work? droidcon Madrid 19 - @marcoGomier
  44. 73.

    My approach • Start with preliminaries • move common code/resources

    to a [or many] core module[s] • Setup the navigation between features • … • Start by modularizing a single feature droidcon Madrid 19 - @marcoGomier
  45. 74.

    My approach • Ship that feature [after testing, QA, etc.

    ] • Start modularizing more features droidcon Madrid 19 - @marcoGomier
  46. 78.

    Conclusions • Plan a big initial push to get things

    started • It's a long [and difficult] journey but it totally worth it • Don't be afraid to fail droidcon Madrid 19 - @marcoGomier
  47. 79.
  48. 81.