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

Modularization - how hard can it be? (Droidcon ...

Modularization - how hard can it be? (Droidcon Berlin)

Recording can be found here: https://youtu.be/opsiSaUS2bg

Modularizing Android codebases is all the hype these days. It can be as simple as moving a few files, and maybe creating a new build config or two along the way, or it can be much more gruelling. At Spotify, it has meant clearing out years and years of tech debt, re-writing APIs, rethinking the architecture and structure of the application and features that goes into it, wrestling with build tools, and then some.

This talk will walk you through the Spotify modularization journey: why we got started, how we went about it, what we have learned through the process, and also why you should be thinking about modularizing your code, if you haven't already started.

Links shared in the presentation:

Instagram: https://atscaleconference.com/videos/app-modularization-and-module-lazy-loading/
Square: https://youtu.be/GesiS2bkTKA
Yelp: https://engineeringblog.yelp.com/2018/06/how-yelp-modularized-the-android-app.html
Soundcloud: http://uk.droidcon.com/skillscasts/10525-modularizing-android-applications
Google: https://youtu.be/tYf9ivnQ0eI
Don't stop believing: https://open.spotify.com/track/4bHsxqR3GMrXTxEPLuK5ue?si=F9TZB4JbSAWrb_ZZzm3kQA

Elin Nilsson

June 27, 2018
Tweet

More Decks by Elin Nilsson

Other Decks in Technology

Transcript

  1. How we started Goal - one feature outside of the

    app Upfront work Tooling Align on basic structure
  2. :app :features :common :libs :http :logger :audio :video :artist :search

    :ui :library :feed :profile :radio :radio :android :uihelp :follow :share :exop :depinj
  3. How we started Goal - one feature outside of the

    app Upfront work Tooling Align on basic structure Pull out everything needed to make that feature compile
  4. How we started Goal - one feature outside of the

    app Upfront work Tooling Align on basic structure Pull out everything needed to make that feature compile Heads up! We ask your forgiveness!
  5. analyzeDependencies(); if (file.hasNoDependencies()) { move(file); } else if (file.hasSimpleDependency()) {

    breakDependency(file.getCode()); } else if (file.hasComplexDependency()) { boolean successful = refactorOrDependencyInversion(file.getCode()); if (!successful) { addModularizationTODO(“This depends on MainActivity, once that’s moved, revisit”); sobQuietlyInTheCorner(); } }
  6. analyzeDependencies(); if (file.hasNoDependencies()) { move(file); } else if (file.hasSimpleDependency()) {

    breakDependency(file.getCode()); } else if (file.hasComplexDependency()) { boolean successful = refactorOrDependencyInversion(file.getCode()); if (!successful) { addModularizationTODO(“This depends on MainActivity, once that’s moved, revisit”); sobQuietlyInTheCorner(); } }
  7. analyzeDependencies(); if (file.hasNoDependencies()) { move(file); } else if (file.hasSimpleDependency()) {

    breakDependency(file.getCode()); } else if (file.hasComplexDependency()) { boolean successful = refactorOrDependencyInversion(file.getCode()); if (!successful) { addModularizationTODO(“This depends on MainActivity, once that’s moved, revisit”); sobQuietlyInTheCorner(); } }
  8. analyzeDependencies(); if (file.hasNoDependencies()) { move(file); } else if (file.hasSimpleDependency()) {

    breakDependency(file.getCode()); } else if (file.hasComplexDependency()) { boolean successful = refactorOrDependencyInversion(file.getCode()); if (!successful) { addModularizationTODO(“This depends on MainActivity, once that’s moved, revisit”); sobQuietlyInTheCorner(); } }
  9. analyzeDependencies(); if (file.hasNoDependencies()) { move(file); } else if (file.hasSimpleDependency()) {

    breakDependency(file.getCode()); } else if (file.hasComplexDependency()) { boolean successful = refactorOrDependencyInversion(file.getCode()); if (!successful) { addModularizationTODO(“This depends on MainActivity, once that’s moved, revisit”); sobQuietlyInTheCorner(); } }
  10. analyzeDependencies(); if (file.hasNoDependencies()) { move(file); } else if (file.hasSimpleDependency()) {

    breakDependency(file.getCode()); } else if (file.hasComplexDependency()) { boolean successful = refactorOrDependencyInversion(file.getCode()); if (!successful) { addModularizationTODO(“This depends on MainActivity, once that’s moved, revisit”); sobQuietlyInTheCorner(); } }
  11. analyzeDependencies(); if (file.hasNoDependencies()) { move(file); } else if (file.hasSimpleDependency()) {

    breakDependency(file.getCode()); } else if (file.hasComplexDependency()) { boolean successful = refactorOrDependencyInversion(file.getCode()); if (!successful) { addModularizationTODO(“This depends on MainActivity, once that’s moved, revisit”); sobQuietlyInTheCorner(); } }
  12. If new code is written as if it was in

    a module, it will be easier to modularize
  13. Best practices in practice DRY - Removing dead code -

    increasing reuse Avoid parameter dependencies
  14. Best practices in practice DRY - Removing dead code -

    increasing reuse Avoid parameter dependencies Dependency Injection
  15. Best practices in practice DRY - Removing dead code -

    increasing reuse Avoid parameter dependencies Dependency Injection Structure the code
  16. Best practices in practice DRY - Removing dead code -

    increasing reuse Avoid parameter dependencies Dependency Injection Structure the code Avoiding utility classes and static methods
  17. Best practices in practice DRY - Removing dead code -

    increasing reuse Avoid parameter dependencies Dependency Injection Structure the code Avoiding utility classes and static methods SOLID principles
  18. SOLID S - Don’t do a lot of things in

    one class O - Design the API of the class so that it can be used and extended without being modified L - Don’t let implementations of the same interface behave differently I - Don’t design big interfaces D - Depend on abstractions, not on implementations
  19. SOLID S - Don’t do a lot of things in

    one class O - Design the API of the class so that it serves the consumers’ needs without modifying it L - Don’t let implementations of the same interface behave differently I - Don’t design big interfaces D - Depend on abstractions, not on implementations
  20. “Single modules are easier to deal with; there are no

    complex dependency graphs to account for and some details of how the app is managed, such as how testing is implemented, are simpler” - Yelp
  21. “Single modules appear to be easier to deal with; there

    are no complex dependency graphs to account for and some details of how the app is managed, such as how testing is implemented, are simpler” - Yelp (revised by Elin)
  22. Words of wisdom Invest in tooling up front Creating modules

    Dependency versioning Static analysis
  23. (remember the tests!) Words of wisdom Invest in tooling up

    front Creating modules Dependency versioning Static analysis
  24. Words of wisdom Invest in tooling up front Creating modules

    Dependency versioning Static analysis DON’T CHANGE ANYTHING as you go Avoid rabbit holes
  25. Words of wisdom Invest in tooling up front Creating modules

    Dependency versioning Static analysis DON’T CHANGE ANYTHING as you go Avoid rabbit holes Inventory your app
  26. Words of wisdom Invest in tooling up front Creating modules

    Dependency versioning Static analysis DON’T CHANGE ANYTHING as you go Avoid rabbit holes Inventory your app Collect metrics, graphs are fun!