Slide 1

Slide 1 text

@MOLSJEROEN SUCCESSFULLY MODULARIZING APPS

Slide 2

Slide 2 text

@MOLSJEROEN @MOLSJEROEN @MOLSJEROEN

Slide 3

Slide 3 text

@MOLSJEROEN WHY MODULARIZATION ARCHITECTURE HOW TO APPROACH LESSONS LEARNED

Slide 4

Slide 4 text

WHY

Slide 5

Slide 5 text

@MOLSJEROEN 1. SPEED UP BUILDS Gradle does two things to speed up builds • Avoid work/caching • Parallellization Need smaller items of work

Slide 6

Slide 6 text

@MOLSJEROEN 1. SPEED UP BUILDS: SMALLER ITEMS OF WORK

Slide 7

Slide 7 text

@MOLSJEROEN 1. SPEED UP BUILDS: SINGLE MODULE

Slide 8

Slide 8 text

@MOLSJEROEN 1. SPEED UP BUILDS: MULTI MODULE

Slide 9

Slide 9 text

@MOLSJEROEN 1. SPEED UP BUILDS: MULTI MODULE

Slide 10

Slide 10 text

@MOLSJEROEN 2. ALLOW ON DEMAND DELIVERY

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

@MOLSJEROEN 2. ALLOW ON DEMAND DELIVERY At-install delivery On demand delivery Conditional delivery Instant delivery Need to split up app Support future requirements

Slide 13

Slide 13 text

@MOLSJEROEN 3. SIMPLIFY DEVELOPMENT APP

Slide 14

Slide 14 text

@MOLSJEROEN 3. SIMPLIFY DEVELOPMENT APP FEATURE 1 FEATURE 2 FEATURE 3 FEATURE 4 FEATURE 5 FEATURE 6

Slide 15

Slide 15 text

IT’S EASIER TO BUILD SEVERAL SMALL THINGS THAN TO BUILD ONE BIG THING Unknown

Slide 16

Slide 16 text

@MOLSJEROEN 3. SIMPLIFY DEVELOPMENT Clear contracts between modules • Less spaghetti code • Fewer cascading changes • Easier in-module refactoring Easy to understand code Cheaper maintenance

Slide 17

Slide 17 text

@MOLSJEROEN 4. REUSE MODULES

Slide 18

Slide 18 text

@MOLSJEROEN 4. REUSE MODULES: MULTIPLE APPS APP 1 FEATURE 1 FEATURE 2 FEATURE 3 FEATURE 4 FEATURE 5 FEATURE 6 LIBRARY 1 LIBRARY 2 APP 2

Slide 19

Slide 19 text

@MOLSJEROEN APP 1 FEATURE 1 FEATURE 2 FEATURE 3 FEATURE 4 FEATURE 5 FEATURE 6 LIBRARY 1 LIBRARY 2 APP 2 4. REUSE MODULES: MULTIPLE APPS

Slide 20

Slide 20 text

@MOLSJEROEN APP 1 FEATURE 1 FEATURE 2 FEATURE 3 FEATURE 4 FEATURE 5 FEATURE 6 LIBRARY 1 LIBRARY 2 APP 2 FEATURE X FEATURE X 4. REUSE MODULES: MULTIPLE APPS

Slide 21

Slide 21 text

@MOLSJEROEN APP 1 FEATURE 1 FEATURE 2 FEATURE 3 FEATURE 4 FEATURE 5 FEATURE 6 LIBRARY 1 LIBRARY 2 APP 2 FEATURE X FEATURE X 4. REUSE MODULES: MULTIPLE APPS

Slide 22

Slide 22 text

@MOLSJEROEN APP 1 FEATURE 1 FEATURE 2 FEATURE 3 FEATURE 4 FEATURE 5 FEATURE 6 SDK LIBRARY 2 4. REUSE MODULES: SDK

Slide 23

Slide 23 text

@MOLSJEROEN APP 1 FEATURE 1 FEATURE 2 FEATURE 3 FEATURE 4 FEATURE 5 FEATURE 6 SDK LIBRARY 2 4. REUSE MODULES: SDK

Slide 24

Slide 24 text

@MOLSJEROEN APP 1 EXPOSED FEATURE WITH INTENT FEATURE 2 FEATURE 3 FEATURE 4 FEATURE 5 FEATURE 6 LIBRARY 1 LIBRARY 2 4. REUSE MODULES: EXPOSE FEATURES

Slide 25

Slide 25 text

@MOLSJEROEN APP 1 EXPOSED FEATURE WITH INTENT FEATURE 2 FEATURE 3 FEATURE 4 FEATURE 5 FEATURE 6 LIBRARY 1 LIBRARY 2 4. REUSE MODULES: EXPOSE FEATURES

Slide 26

Slide 26 text

@MOLSJEROEN APP 1 FEATURE 1 FEATURE 2 FEATURE 3 FEATURE 4 FEATURE 5 FEATURE 6 AWESOME GITHUB LIBRARY LIBRARY 2 4. REUSE MODULES: OPEN SOURCE

Slide 27

Slide 27 text

@MOLSJEROEN APP 1 FEATURE 1 FEATURE 2 FEATURE 3 FEATURE 4 FEATURE 5 FEATURE 6 AWESOME GITHUB LIBRARY LIBRARY 2 4. REUSE MODULES: OPEN SOURCE

Slide 28

Slide 28 text

@MOLSJEROEN 5. EXPERIMENT WITH NEW TECHNOLOGIES Rapidly evolving Android landscape Need to experiment rapidly Cost of wrong technology choice Avoid technology lock-in

Slide 29

Slide 29 text

@MOLSJEROEN Source: https://blog.daftcode.pl/hype-driven-development-3469fc2e9b22

Slide 30

Slide 30 text

@MOLSJEROEN 5. EXPERIMENT WITH NEW TECHNOLOGIES APP FEATURE 1 FEATURE 2 FEATURE 3 FEATURE 4 FEATURE 5 FEATURE 6

Slide 31

Slide 31 text

@MOLSJEROEN 6. SCALING Large teams cause new issues • Merge conflicts • Dependencies • Code ownership

Slide 32

Slide 32 text

@MOLSJEROEN 6. SCALING: DEVELOP IN PARALLEL Team A Team B APP FEATURE 1 FEATURE 2 FEATURE 3 FEATURE 4 FEATURE 5 FEATURE 6

Slide 33

Slide 33 text

@MOLSJEROEN 6. SCALING: DEVELOP IN PARALLEL Team A Team B APP FEATURE 1 FEATURE 2 FEATURE 3 FEATURE 4 FEATURE 5 FEATURE 6

Slide 34

Slide 34 text

@MOLSJEROEN 6. SCALING: OUTSOURCE Team A External company APP FEATURE 1 FEATURE 2 FEATURE 3 FEATURE 4 FEATURE 5 FEATURE 6

Slide 35

Slide 35 text

@MOLSJEROEN 7. IMPROVE LEGACY CODE

Slide 36

Slide 36 text

@MOLSJEROEN Aggressive High impact Lot of work Not value focussed Risky launch Exciting Less risky Gradual Slow Tedious Continuous releases Unsatisfying REWRITE REFACTOR V S

Slide 37

Slide 37 text

@MOLSJEROEN Aggressive High impact Lot of work Not value focussed Risky launch Exciting Less risky Gradual Slow Tedious Continuous releases Unsatisfying REWRITE REFACTOR V S

Slide 38

Slide 38 text

@MOLSJEROEN 7. IMPROVE LEGACY CODE: REWRITE, REFACTOR OR ACCEPT APP FEATURE 1 FEATURE 2 FEATURE 3 FEATURE 4 FEATURE 5 FEATURE 6

Slide 39

Slide 39 text

@MOLSJEROEN 7. IMPROVE LEGACY CODE: REWRITE, REFACTOR OR ACCEPT APP FEATURE 1 FEATURE 2 FEATURE 3 FEATURE 4 FEATURE 5 FEATURE 6

Slide 40

Slide 40 text

@MOLSJEROEN 7. IMPROVE LEGACY CODE Able to rewrite parts of code base Keep ability to release Gradually roll out possible Faster time to market

Slide 41

Slide 41 text

@MOLSJEROEN 8. SIMPLIFY TEST AUTOMATION

Slide 42

Slide 42 text

@MOLSJEROEN 8. SIMPLIFY TEST AUTOMATION

Slide 43

Slide 43 text

@MOLSJEROEN 8. SIMPLIFY TEST AUTOMATION Speeds up tests Simplified test setup Higher test reliability

Slide 44

Slide 44 text

@MOLSJEROEN WHY: RECAP Speed up builds Allow on demand delivery Simplify development Reuse modules across apps Experiment with new technologies Scale development team Improve legacy code Simplify test automation

Slide 45

Slide 45 text

MODULARIZATION ARCHITECTURE

Slide 46

Slide 46 text

YOU HAVE YOUR WAY. I HAVE MY WAY. THE RIGHT WAY, THE CORRECT WAY, AND THE ONLY WAY DOES NOT EXIST. F. Nietzsche

Slide 47

Slide 47 text

@MOLSJEROEN APP STRUCTURE

Slide 48

Slide 48 text

@MOLSJEROEN APP STRUCTURE

Slide 49

Slide 49 text

@MOLSJEROEN APP STRUCTURE

Slide 50

Slide 50 text

@MOLSJEROEN APP STRUCTURE

Slide 51

Slide 51 text

FEATURES ARE A FLOW OF SCREENS

Slide 52

Slide 52 text

@MOLSJEROEN APP WIREFRAME

Slide 53

Slide 53 text

@MOLSJEROEN APP WIREFRAME

Slide 54

Slide 54 text

@MOLSJEROEN APP WIREFRAME

Slide 55

Slide 55 text

APPS CONSIST OF SEVERAL FEATURES

Slide 56

Slide 56 text

@MOLSJEROEN ANDROID APP COMPONENTS ACTIVITY SERVICE BROADCAST RECEIVER CONTENT PROVIDER

Slide 57

Slide 57 text

@MOLSJEROEN ANDROID APP COMPONENTS Full screen UI Reuse across apps Started via explicit or implicit intents ACTIVITY SERVICE BROADCAST RECEIVER CONTENT PROVIDER

Slide 58

Slide 58 text

@MOLSJEROEN IMPLICIT INTENTS

Slide 59

Slide 59 text

ANDROID LINKS MULTIPLE APPS TOGETHER VIA IMPLICIT INTENTS

Slide 60

Slide 60 text

@MOLSJEROEN MODULARIZED ARCHITECTURE APP

Slide 61

Slide 61 text

@MOLSJEROEN MODULARIZED ARCHITECTURE APP FEATURE 1 FEATURE 2 FEATURE 3 FEATURE 4 FEATURE 5 FEATURE 6

Slide 62

Slide 62 text

@MOLSJEROEN MODULARIZED ARCHITECTURE APP FEATURE 1 FEATURE 2 FEATURE 3 FEATURE 4 FEATURE 5 FEATURE 6 LIBRARY 4 LIBRARY 4 LIB 1 LIBRARY 2 LIBRARY 3

Slide 63

Slide 63 text

@MOLSJEROEN FEATURE MODULES Full screen, coherent user facing functionality in the app Android library module Single activity with (optional) navigation graph Respond to implicit intents and pass back a result Never depend on other features or app Depend on several library modules APP FEATURE 1 FEATURE 2 FEATURE 3 FEATURE 4 FEATURE 5 FEATURE 6 LIBRARY 4 LIBRARY 4 LIB 1 LIBRARY 2 LIBRARY 3

Slide 64

Slide 64 text

@MOLSJEROEN LIBRARY MODULES Plumbing that is reused across several or all features Android library, pure Java or pure Kotlin module Never depend on features or app Can (but don’t have to) depend on other libraries APP FEATURE 1 FEATURE 2 FEATURE 3 FEATURE 4 FEATURE 5 FEATURE 6 LIBRARY 4 LIBRARY 4 LIB 1 LIBRARY 2 LIBRARY 3

Slide 65

Slide 65 text

@MOLSJEROEN APP MODULE Links feature modules together in a useful app Android application module Depends on other features and libraries Orchestrates navigation between features Decides what features are enabled using feature toggles Doesn’t contain much code APP FEATURE 1 FEATURE 2 FEATURE 3 FEATURE 4 FEATURE 5 FEATURE 6 LIBRARY 4 LIBRARY 4 LIB 1 LIBRARY 2 LIBRARY 3

Slide 66

Slide 66 text

@MOLSJEROEN ADVANTAGES Application structure Navigation Testing Scaling Feature flagging Experiment with new technology

Slide 67

Slide 67 text

@MOLSJEROEN APPLICATION STRUCTURE

Slide 68

Slide 68 text

@MOLSJEROEN DASHBOARD FEATURE

Slide 69

Slide 69 text

@MOLSJEROEN DASHBOARD ACTIVITY

Slide 70

Slide 70 text

@MOLSJEROEN LOGIN FEATURE

Slide 71

Slide 71 text

@MOLSJEROEN SHARING FEATURE

Slide 72

Slide 72 text

@MOLSJEROEN NAVIGATION Split navigation in smaller parts • Within a feature -> handled by the feature • Between features -> handled by the app module APP FEATURE 1 FEATURE 2 FEATURE 3 FEATURE 4 FEATURE 5 FEATURE 6

Slide 73

Slide 73 text

@MOLSJEROEN NAVIGATION: IN FEATURE Android Navigation components • Visualize navigation flow • Find back screens • Easy code browsing

Slide 74

Slide 74 text

@MOLSJEROEN NAVIGATION: IN FEATURE

Slide 75

Slide 75 text

@MOLSJEROEN NAVIGATION: IN FEATURE

Slide 76

Slide 76 text

@MOLSJEROEN NAVIGATION: IN FEATURE

Slide 77

Slide 77 text

@MOLSJEROEN NAVIGATION: IN FEATURE

Slide 78

Slide 78 text

@MOLSJEROEN NAVIGATION: IN FEATURE

Slide 79

Slide 79 text

@MOLSJEROEN NAVIGATION: IN FEATURE

Slide 80

Slide 80 text

@MOLSJEROEN NAVIGATION: IN FEATURE

Slide 81

Slide 81 text

@MOLSJEROEN NAVIGATION: IN FEATURE

Slide 82

Slide 82 text

@MOLSJEROEN findNavController().navigate(R.id.action_welcomeFragment_to_loginFragment) NAVIGATION: IN FEATURE

Slide 83

Slide 83 text

@MOLSJEROEN NAVIGATION: IN FEATURE

Slide 84

Slide 84 text

@MOLSJEROEN NAVIGATION: BETWEEN FEATURES startActivity(Intent(activity, DashboardActivity::class.java))

Slide 85

Slide 85 text

@MOLSJEROEN NAVIGATION: BETWEEN FEATURES startActivity(Intent("action.dashboard.open"))

Slide 86

Slide 86 text

@MOLSJEROEN NAVIGATION: BETWEEN FEATURES

Slide 87

Slide 87 text

@MOLSJEROEN NAVIGATION: BETWEEN FEATURES

Slide 88

Slide 88 text

@MOLSJEROEN NAVIGATION: BETWEEN FEATURES String duplication of action In depth knowledge of intent creation Other apps could also handle action

Slide 89

Slide 89 text

@MOLSJEROEN NAVIGATION: BETWEEN FEATURES APP FEATURE 1 FEATURE 2 FEATURE 3 FEATURE 4 FEATURE 5 FEATURE 6 ACTIONS LIBRARY 4 LIB 1 LIBRARY 2 LIBRARY 3

Slide 90

Slide 90 text

@MOLSJEROEN NAVIGATION: BETWEEN FEATURES object Actions { fun openLoginIntent() = Intent("action.login.open") fun openDashboardIntent() = Intent("action.dashboard.open") fun openSharingIntent() = Intent("action.sharing.open") } activity.startActivity(Actions.openDashboardIntent())

Slide 91

Slide 91 text

@MOLSJEROEN NAVIGATION: BETWEEN FEATURES object Actions { fun openLoginIntent() = Intent("action.login.open") fun openDashboardIntent() = Intent("action.dashboard.open") fun openSharingIntent() = Intent("action.sharing.open") } activity.startActivity(Actions.openDashboardIntent())

Slide 92

Slide 92 text

@MOLSJEROEN NAVIGATION: BETWEEN FEATURES object Actions { fun openDashboardIntent(userId: String) = Intent(context, "action.dashboard.open") .putExtra(EXTRA_USER, UserArgs(userId)) } activity.startActivity(Actions.openDashboardIntent("userId"))

Slide 93

Slide 93 text

@MOLSJEROEN NAVIGATION: BETWEEN FEATURES object Actions { fun openDashboardIntent(userId: String) = Intent(context, "action.dashboard.open") .putExtra(EXTRA_USER, UserArgs(userId)) } activity.startActivity(Actions.openDashboardIntent("userId"))

Slide 94

Slide 94 text

@MOLSJEROEN NAVIGATION: BETWEEN FEATURES

Slide 95

Slide 95 text

@MOLSJEROEN NAVIGATION: BETWEEN FEATURES object Actions { fun openLoginIntent(context: Context) = internalIntent(context, "action.login.open") private fun internalIntent(context: Context, action: String) = Intent(action).setPackage(context.packageName) }

Slide 96

Slide 96 text

@MOLSJEROEN NAVIGATION: BETWEEN FEATURES object Actions { fun openLoginIntent(context: Context) = internalIntent(context, "action.login.open") private fun internalIntent(context: Context, action: String) = Intent(action).setPackage(context.packageName) }

Slide 97

Slide 97 text

@MOLSJEROEN NAVIGATION: BETWEEN FEATURES Implicit intents Actions module Abstract away feature parameters Restrict to current package

Slide 98

Slide 98 text

@MOLSJEROEN TESTING UNIT INTEGRATION E2E

Slide 99

Slide 99 text

@MOLSJEROEN TESTING APP FEATURE 1 FEATURE 2 FEATURE 3 FEATURE 4 FEATURE 5 FEATURE 6 LIBRARY 4 LIBRARY 4 LIB 1 LIBRARY 2 LIBRARY 3

Slide 100

Slide 100 text

@MOLSJEROEN FEATURE TESTING class LoginFlowTest { @Rule @JvmField var mActivityTestRule = ActivityTestRule(LoginActivity::class.java) @Test fun loginFlowTest() { onView(withId(R.id.button_login_start)).perform(click()) onView(withId(R.id.button_login_signin)).perform(click()) onView(withId(R.id.button_login_toapp)).check(matches(isDisplayed())) } }

Slide 101

Slide 101 text

@MOLSJEROEN FEATURE TESTING class LoginFlowTest { @Rule @JvmField var mActivityTestRule = ActivityTestRule(LoginActivity::class.java) @Test fun loginFlowTest() { onView(withId(R.id.button_login_start)).perform(click()) onView(withId(R.id.button_login_signin)).perform(click()) onView(withId(R.id.button_login_toapp)).check(matches(isDisplayed())) } }

Slide 102

Slide 102 text

@MOLSJEROEN FEATURE TESTING class LoginFlowTest { @Rule @JvmField var mActivityTestRule = ActivityTestRule(LoginActivity::class.java) @Test fun loginFlowTest() { onView(withId(R.id.button_login_start)).perform(click()) onView(withId(R.id.button_login_signin)).perform(click()) onView(withId(R.id.button_login_toapp)).check(matches(isDisplayed())) } }

Slide 103

Slide 103 text

@MOLSJEROEN APP FLOW TESTING class AppFlowTest { @Rule @JvmField var mActivityTestRule = ActivityTestRule(MainActivity::class.java) @Test fun test_criticalUserFlow_throughoutEntireApp() { onView(withId(modularization.login.R.id.button_login_start)).perform(click()) onView(withId(modularization.login.R.id.button_login_signin)).perform(click()) onView(withId(modularization.login.R.id.button_login_toapp)).perform(click()) onView(withId(R.id.action_albums)).perform(click()) onView(withId(R.id.action_sharing)).perform(click()) onView(withId(R.id.button_social_facebook)).perform(click()) onView(withId(R.id.recyclerView_sharing_contacts)).check(matches(isDisplayed())) } }

Slide 104

Slide 104 text

@MOLSJEROEN SCALING: TEAMS Team A Team B APP FEATURE 1 FEATURE 2 FEATURE 3 FEATURE 4 FEATURE 5 FEATURE 6 LIBRARY 4 LIBRARY 4 LIB 1 LIBRARY 2 LIBRARY 3

Slide 105

Slide 105 text

@MOLSJEROEN APP 1 FEATURE 1 FEATURE 2 FEATURE 3 FEATURE 4 FEATURE 5 FEATURE 6 LIBRARY 1 LIBRARY 2 APP 2 FEATURE X FEATURE X SCALING: APPS

Slide 106

Slide 106 text

@MOLSJEROEN SCALING: SDKS APP EXPOSED FEATURE WITH INTENT FEATURE 2 FEATURE 3 FEATURE 4 FEATURE 5 FEATURE 6 LIBRARY 4 AWESOME GITHUB LIBRARY LIB 1 SDK LIBRARY 3

Slide 107

Slide 107 text

@MOLSJEROEN SCALING: TECHNOLOGY APP FEATURE 1 FEATURE 2 FEATURE 3 FEATURE 4 FEATURE 5 FEATURE 6 LIBRARY 4 LIBRARY 4 LIB 1 LIBRARY 2 LIBRARY 3

Slide 108

Slide 108 text

@MOLSJEROEN IMPROVE LEGACY APP FEATURE 1 FEATURE 2 FEATURE 3 FEATURE 4 FEATURE 5 FEATURE 6 LIBRARY 4 LIBRARY 4 LIB 1 LIBRARY 2 LIBRARY 3

Slide 109

Slide 109 text

@MOLSJEROEN IMPROVE LEGACY: REWRITE FEATURE APP FEATURE 1 FEATURE 2 FEATURE 3 FEATURE 4 FEATURE 5 FEATURE 6 LIBRARY 4 LIBRARY 4 LIB 1 LIBRARY 2 LIBRARY 3

Slide 110

Slide 110 text

@MOLSJEROEN IMPROVE LEGACY: REWRITE FEATURE APP FEATURE 1 FEATURE 2 FEATURE 3 FEATURE 4 FEATURE 5 FEATURE 6 LIBRARY 4 LIBRARY 4 LIB 1 LIBRARY 2 LIBRARY 3 FEATURE 5*

Slide 111

Slide 111 text

@MOLSJEROEN IMPROVE LEGACY: FEATURE FLAGS object Actions { fun openLoginIntent() = if (FeatureFlag.loginRewrite) { Intent("action.login2.open") } else { Intent("action.login.open") } }

Slide 112

Slide 112 text

@MOLSJEROEN IMPROVE LEGACY: FEATURE FLAGS object Actions { fun openLoginIntent() = if (FeatureFlag.loginRewrite) { Intent("action.login2.open") } else { Intent("action.login.open") } }

Slide 113

Slide 113 text

@MOLSJEROEN IMPROVE LEGACY: ROLL OUT

Slide 114

Slide 114 text

@MOLSJEROEN

Slide 115

Slide 115 text

@MOLSJEROEN ARCHITECTURE: RECAP Easy code navigation Simple in-feature and across feature navigation Better test automation Enables scaling Able to experiment with new technologies Staged rollout of rewritten features

Slide 116

Slide 116 text

HOW TO APPROACH

Slide 117

Slide 117 text

@MOLSJEROEN APP FEATURE FEATURE FEATURE FUTURE. FEATURE FUTURE FEATURE FUTURE FEATURE OLD APP LIB LIBRARY FUTURE LIBRARY APP FEATURE FEATURE FEATURE FUTURE FEATURE FUTURE FEATURE FUTURE FEATURE LIB 1 LIB FUTURE LIBRARY LIBRARY CHOOSE YOUR SIDE

Slide 118

Slide 118 text

@MOLSJEROEN PULL CODE UP APP FEATURE FEATURE FEATURE FUTURE FEATURE FUTURE FEATURE FUTURE FEATURE OLD APP LIB LIBRARY FUTURE LIBRARY Pull modules up

Slide 119

Slide 119 text

@MOLSJEROEN PULL CODE UP Conceptually very simple Extract features without dependency issues Huge upfront change Encourages gradual modularization Incompatible with Butterknife: change to R2.id.*** Features need to be extracted before libraries

Slide 120

Slide 120 text

@MOLSJEROEN PUSH CODE DOWN APP FEATURE FEATURE FEATURE FUTURE FEATURE FUTURE FEATURE FUTURE FEATURE LIB 1 LIB FUTURE LIBRARY LIBRARY Push modules down

Slide 121

Slide 121 text

@MOLSJEROEN PUSH CODE DOWN Initially a lot harder Extract libraries without dependency issues No big upfront change Forces aggressive modularisation Better grip on modularisation process Bottom up code clean up

Slide 122

Slide 122 text

@MOLSJEROEN APP FEATURE FEATURE FEATURE FUTURE. FEATURE FUTURE FEATURE FUTURE FEATURE OLD APP LIB LIBRARY FUTURE LIBRARY APP FEATURE FEATURE FEATURE FUTURE FEATURE FUTURE FEATURE FUTURE FEATURE LIB 1 LIB FUTURE LIBRARY LIBRARY CHOOSE YOUR SIDE

Slide 123

Slide 123 text

@MOLSJEROEN APP FEATURE FEATURE FEATURE FUTURE. FEATURE FUTURE FEATURE FUTURE FEATURE OLD APP LIB LIBRARY FUTURE LIBRARY APP FEATURE FEATURE FEATURE FUTURE FEATURE FUTURE FEATURE FUTURE FEATURE LIB 1 LIB FUTURE LIBRARY LIBRARY CHOOSE YOUR SIDE

Slide 124

Slide 124 text

@MOLSJEROEN CONSIDERATIONS Make a big initial push Aggressively restrict visibility Combine with general code improvements Postpone/avoid problems • Cut dependencies using abstractions • Deprecate and rewrite • Clean up internals later

Slide 125

Slide 125 text

WHEN PLANNING IS LONG THEN IT’S WRONG, IF IT’S TIGHT THEN IT’S RIGHT Elon musk

Slide 126

Slide 126 text

LESSONS LEARNED

Slide 127

Slide 127 text

@MOLSJEROEN CONFIGURE MODULES Adding a new module must be easy Maintaining module configurations must be easy

Slide 128

Slide 128 text

@MOLSJEROEN CONFIGURE MODULES subprojects { afterEvaluate { project -> if (project.hasProperty('android')) { android { buildToolsVersion Config.buildTools compileSdkVersion Config.compileSdk defaultConfig { minSdkVersion Config.minSdk targetSdkVersion Config.targetSdk } compileOptions { sourceCompatibility Config.javaVersion targetCompatibility Config.javaVersion } } } } }

Slide 129

Slide 129 text

@MOLSJEROEN CONFIGURE MODULES subprojects { afterEvaluate { project -> if (project.hasProperty('android')) { android { buildToolsVersion Config.buildTools compileSdkVersion Config.compileSdk defaultConfig { minSdkVersion Config.minSdk targetSdkVersion Config.targetSdk } compileOptions { sourceCompatibility Config.javaVersion targetCompatibility Config.javaVersion } } } } }

Slide 130

Slide 130 text

@MOLSJEROEN CONFIGURE MODULES subprojects { afterEvaluate { project -> if (project.hasProperty('android')) { android { buildToolsVersion Config.buildTools compileSdkVersion Config.compileSdk defaultConfig { minSdkVersion Config.minSdk targetSdkVersion Config.targetSdk } compileOptions { sourceCompatibility Config.javaVersion targetCompatibility Config.javaVersion } } } } }

Slide 131

Slide 131 text

@MOLSJEROEN CONFIGURE MODULES apply plugin: 'com.android.library' apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-android' dependencies { implementation project(':libraries:ui-components') implementation project(':libraries:actions') implementation Deps.androidx_material implementation Deps.androidx_constraintlayout implementation Deps.androidx_navigation_fragment implementation Deps.androidx_navigation_ui testImplementation Deps.testlib_junit androidTestImplementation Deps.testandroidx_runner androidTestImplementation Deps.testandroidx_rules androidTestImplementation Deps.testandroidx_espressocore }

Slide 132

Slide 132 text

@MOLSJEROEN CONFIGURE MODULES

Slide 133

Slide 133 text

@MOLSJEROEN MODULE GRAPH apply from: 'https://raw.githubusercontent.com/JakeWharton/SdkSearch/master/ gradle/projectDependencyGraph.gradle' ./gradlew projectDependencyGraph

Slide 134

Slide 134 text

@MOLSJEROEN MODULE GRAPH

Slide 135

Slide 135 text

@MOLSJEROEN ORGANIZE SETTINGS.GRADLE include ':app', ':features:login', ':features:dashboard', ':features:sharing', ':libraries:ui- components', ':libraries:actions'

Slide 136

Slide 136 text

@MOLSJEROEN ORGANIZE SETTINGS.GRADLE include ':app' include ':features:login' include ':features:dashboard' include ':features:sharing' include ':libraries:ui-components' include ':libraries:actions'

Slide 137

Slide 137 text

@MOLSJEROEN ORGANIZE SETTINGS.GRADLE include ':app' include ':features:login' include ':features:dashboard' include ':features:sharing' include ':libraries:ui-components' include ':libraries:actions'

Slide 138

Slide 138 text

@MOLSJEROEN MODULE INTERNALS

Slide 139

Slide 139 text

@MOLSJEROEN MODULE INTERNALS - ORGANIZATION

Slide 140

Slide 140 text

@MOLSJEROEN MODULE INTERNALS - ORGANIZATION

Slide 141

Slide 141 text

@MOLSJEROEN MODULE INTERNALS - PACKAGE NAME features: [project-name].features.[feature-name]
 e.g. modularization.features.login libraries: [project-name].libraries.[library-name]
 e.g. modularization.libraries.actions

Slide 142

Slide 142 text

@MOLSJEROEN MODULE INTERNALS - PACKAGE NAME import android.content.Intent import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import modularization.features.login.LoginActivity import modularization.features.sharing.SharingActivity import modularization.features.dashboard.DashboardActivity import modularization.libraries.actions.Actions import modularization.libraries.uicomponents.RoundedButton

Slide 143

Slide 143 text

@MOLSJEROEN LAYOUT PREVIEWS

Slide 144

Slide 144 text

@MOLSJEROEN LAYOUT PREVIEWS

Slide 145

Slide 145 text

@MOLSJEROEN LAYOUT PREVIEWS

Slide 146

Slide 146 text

@MOLSJEROEN LAYOUT PREVIEWS

Slide 147

Slide 147 text

@MOLSJEROEN LAYOUT PREVIEWS

Slide 148

Slide 148 text

@MOLSJEROEN DEPENDENCY MANAGEMENT object Config { val minSdk = 23 val javaVersion = JavaVersion.VERSION_1_8 val buildTools = "28.0.3" } object Versions { val androidx_core = "1.0.1" val androidx_nav = "2.0.0" ... } object Deps { val androidx_core = "androidx.core:core-ktx:${Versions.androidx_core}" val androidx_nav_fragment = "androidx.navigation:navigation-fragment-ktx:${Versions.androidx_nav}" val androidx_nav_ui = “androidx.navigation:navigation-ui-ktx:${Versions.androidx_nav}" ... }

Slide 149

Slide 149 text

@MOLSJEROEN CONFIGURE MODULES apply plugin: 'com.android.library' apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-android' dependencies { implementation project(':libraries:ui-components') implementation project(':libraries:actions') implementation Deps.androidx_material implementation Deps.androidx_constraintlayout implementation Deps.androidx_navigation_fragment implementation Deps.androidx_navigation_ui testImplementation Deps.testlib_junit androidTestImplementation Deps.testandroidx_runner androidTestImplementation Deps.testandroidx_rules androidTestImplementation Deps.testandroidx_espressocore }

Slide 150

Slide 150 text

@MOLSJEROEN DEPENDENCY MANAGEMENT ./gradlew dependencyUpdates

Slide 151

Slide 151 text

@MOLSJEROEN SPEED UP BUILDS dependencies { // Avoid doing this api project(':libraries:ui-components') // Do this instead implementation project(':libraries:ui-components') }

Slide 152

Slide 152 text

@MOLSJEROEN API VS IMPLEMENTATION DEPENDENCY APP

Slide 153

Slide 153 text

@MOLSJEROEN API DEPENDENCY APP

Slide 154

Slide 154 text

@MOLSJEROEN API DEPENDENCY APP

Slide 155

Slide 155 text

@MOLSJEROEN API DEPENDENCY APP

Slide 156

Slide 156 text

@MOLSJEROEN IMPLEMENTATION DEPENDENCY APP

Slide 157

Slide 157 text

WRAP UP

Slide 158

Slide 158 text

THERE ARE NO BIG PROBLEMS, THERE ARE JUST A LOT OF LITTLE PROBLEMS. Henry Ford

Slide 159

Slide 159 text

@MOLSJEROEN MODULARIZATION HAS TONS OF BENEFITS APP FEATURES LIBRARIES NAVIGATION WITHIN AND BETWEEN FEATURES PUSH CODE DOWN SIMPLIFY ADDING MODULES

Slide 160

Slide 160 text

@MOLSJEROEN

Slide 161

Slide 161 text

@MOLSJEROEN HTTPS://JEROENMOLS.COM/BLOG

Slide 162

Slide 162 text

@MOLSJEROEN REFERENCES Blog posts: 1. http://bit.ly/modularization_why 2. http://bit.ly/modularization_architecture 3. http://bit.ly/modularization_example 4. http://bit.ly/modularization_how 5. http://bit.ly/modularization_lessons http://bit.ly/modularization_code

Slide 163

Slide 163 text

@MOLSJEROEN IMAGE CREDITS Welcome image by Clement127 https://flic.kr/p/n9ctTn Official Android documentation https://d.android.com Font awesome https://fontawesome.com/

Slide 164

Slide 164 text

MOLSJEROEN