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

Fighting against Android for the Right to Use Composition

GDG SPb
November 22, 2017

Fighting against Android for the Right to Use Composition

Поговорим о том, что не так с MVP и его старшим братом MVC. И разберем как обойти ошибки проектирования Android и писать (хотя бы немного) повторно используемый объектно-ориентированный код.

GDG SPb

November 22, 2017
Tweet

More Decks by GDG SPb

Other Decks in Programming

Transcript

  1. Who am I? • 2+ years Android code monkey •

    1+ year JVM back-end dev javanese.online @Miha-x64 @miha_x64 @Harmonizr at @kotlin_mobile and @javanese_questions ❤️OOP, FP, composition
  2. Procedural, object-oriented, functional switch-case if-else val mode: Int if (mode

    == MODE_X) performX(); else preformDefault(); object polymorphism val mode: Mode mode.perform() functional polymorphism val perform: () → Unit perform()
  3. The most of Android code is boilerplate • Create a

    Fragment • Inflate a View • Show/Hide ProgressBar • Show data How many times have you done it?
  4. Monolithic Fragment • View — inflate layout, find views, set

    adapters; • State — onSaveInstanceState, onViewStateRestored
  5. Monolithic Fragment • View — inflate layout, find views, set

    adapters; • State — onSaveInstanceState, onViewStateRestored; • Context — Activity, Resources, getSystemService
  6. Monolithic Fragment • View — inflate layout, find views, set

    adapters; • State — onSaveInstanceState, onViewStateRestored; • Context — Activity, Resources, getSystemService; • Lifecycle — attach/create/start/resume/pause/stop/destroy/detach
  7. Monolithic Fragment • View — inflate layout, find views, set

    adapters; • State — onSaveInstanceState, onViewStateRestored; • Context — Activity, Resources, getSystemService; • Lifecycle — attach/create/start/resume/pause/stop/destroy/detach; • userVisibleHint — visibility in ViewPager
  8. Monolithic Fragment • View — inflate layout, find views, set

    adapters; • State — onSaveInstanceState, onViewStateRestored; • Context — Activity, Resources, getSystemService; • Lifecycle — attach/create/start/resume/pause/stop/destroy/detach; • userVisibleHint — visibility in ViewPager; • targetFragment, onActivityResult, onRequestPermissionResult.
  9. Controller vs. SOLID • Is not single-responsible; • No interfaces

    — cannot be decorated or substituted; • Not segregated
  10. Controller vs. SOLID • Is not single-responsible; • No interfaces

    — cannot be decorated or substituted; • Not segregated; • Implementation dependency
  11. Controller vs. SOLID • Is not single-responsible; • No interfaces

    — cannot be decorated or substituted; • Not segregated; • Implementation dependency; • Does not represent a solid object, its behaviour and state
  12. Controller vs. SOLID • Is not single-responsible; • No interfaces

    — cannot be decorated or substituted; • Not segregated; • Implementation dependency; • Does not represent a solid object, its behaviour and state. Is just a bunch of procedures.
  13. MVP: to Decompose Undecomposable A Fragment delegates to Presenter the

    following items: • View; • State; • Context; • Lifecycle; • userVisibleHint; • targetFragment, onActivityResult, onRequestPermissionResult.
  14. MVP • View is dumb and has got broken encapsulation;

    • View-Presenter abstraction has leaked
  15. MVP • View is dumb and has got broken encapsulation;

    • View-Presenter abstraction has leaked; • View and Presenter are separated by means of interfaces but without any code reuse and polymorphism
  16. MVP • View is dumb and has got broken encapsulation;

    • View-Presenter abstraction has leaked; • View and Presenter are separated by means of interfaces but without any code reuse and polymorphism; • Presenter is a bunch of procedures, like a Controller
  17. MVP • View is dumb and has got broken encapsulation;

    • View-Presenter abstraction has leaked; • View and Presenter are separated by means of interfaces but without any code reuse and polymorphism; • Presenter is a bunch of procedures, like a Controller; • View and Presenter hold links to each other which is very strange and discouraged practice
  18. MVP • View is dumb and has got broken encapsulation;

    • View-Presenter abstraction has leaked; • View and Presenter are separated by means of interfaces but without any code reuse and polymorphism; • Presenter is a bunch of procedures, like a Controller; • View and Presenter hold links to each other which is very strange and discouraged practice; • Presenter is logically tied to Android platform.
  19. Presenter implementation inheritance What about extending existing Presenter for similar

    use-case? Inheritance is a procedural technique for code reuse. Yegor Bugayenko Favor composition over inheritance. Joshua Bloch
  20. Interactor / Use Case • No concrete and focused purpose

    — responsible for nothing and everything
  21. Interactor / Use Case • No concrete and focused purpose

    — responsible for nothing and everything; • Not a solid object, similarly to Controller.
  22. CLEAN or VIPER Each feature is scattered through these layers.

    • Many files with many LOC; • Hard to modify
  23. CLEAN or VIPER Each feature is scattered through these layers.

    • Many files with many LOC; • Hard to modify; • Hard to trace changes
  24. CLEAN or VIPER Each feature is scattered through these layers.

    • Many files with many LOC; • Hard to modify; • Hard to trace changes; • Single layer itself is useless
  25. CLEAN or VIPER Each feature is scattered through these layers.

    • Many files with many LOC; • Hard to modify; • Hard to trace changes; • Single layer itself is useless. Typical sample of Baklava-code.
  26. Android The things are even worse because of Android rules:

    • Fragments forbid composition; • One Fragment + Presenter per use case — no code reuse!
  27. Android The things are even worse because of Android rules:

    • Fragments forbid composition; • One Fragment + Presenter per use case — no code reuse! • Fragment resolves its own dependencies, like singleton
  28. Android The things are even worse because of Android rules:

    • Fragments forbid composition; • One Fragment + Presenter per use case — no code reuse! • Fragment resolves its own dependencies, like singleton; • Passing an argument deeply through flow based on Fragment stack is painful and unmaintainable.
  29. DI containers • Just adding noise and indirection; • Inject

    different implementations of the same interfaces?
  30. DI containers • Just adding noise and indirection; • Inject

    different implementations of the same interfaces? • This is a dead end: we’ll get scopes and qualifiers, configs which can break something somewhere, dependencies on implementations instead of abstractions
  31. DI containers • Just adding noise and indirection; • Inject

    different implementations of the same interfaces? • This is a dead end: we’ll get scopes and qualifiers, configs which can break something somewhere, dependencies on implementations instead of abstractions; • This introduces semantics of dynamic weakly-typed languages.
  32. Android acts like a bad DI container Application Activity Activity

    Service Fragment Fragment Child Fragment Fragment Fragment Fragment Fragment Child Fragment He-he
  33. What we need • Reuse Fragments or Presenters for similar

    screens by means of object or functional composition Search books Effective Java, 3rd Edition by Joshua Bloch Java Generics FAQ by Angelika Langer Java Performance: The... by Scott Oaks Thinking in Java, 4th edit... by Bruce Eckel Kotlin in Action by D. Jemerov and S. Isakova Search books Effective Java, 3rd Edition by Joshua Bloch Java Generics FAQ by Angelika Langer Java Performance: The... by Scott Oaks Thinking in Java, 4th edit... by Bruce Eckel Kotlin in Action by D. Jemerov and S. Isakova Paradigms Books Websites Procedural Simple and Annoying Functional Fascinating and Crazy Train Procedural Old and digesting Object-Oriented Interfaces and Composition Procedural You can write it even in Java Amazon.com Expensive books GitHub.com My favourite social net Twitter.com Read programmers’ jokes StackOverflow.com Downvote stupid questions Javanese.online WTF is this? Search paradigms Search websites
  34. What we need • Reuse Fragments or Presenters for similar

    screens by means of object or functional composition; • Escape onActivityResult and onRequestPermissionResult hell
  35. What we need • Reuse Fragments or Presenters for similar

    screens by means of object or functional composition; • Escape onActivityResult and onRequestPermissionResult hell; • Allow hierarchical communication (parent-child)
  36. What we need • Reuse Fragments or Presenters for similar

    screens by means of object or functional composition; • Escape onActivityResult and onRequestPermissionResult hell; • Allow hierarchical communication (parent-child); • Transparent work with userVisibleHint
  37. What we need • Reuse Fragments or Presenters for similar

    screens by means of object or functional composition; • Escape onActivityResult and onRequestPermissionResult hell; • Allow hierarchical communication (parent-child); • Transparent work with userVisibleHint; • SOLID, reusable, cross-platform Presenters.
  38. route is an object endpoint is an object I am

    an object we are objects https://github.com/JavaneseOnline/KRUD/blob/master/krud-core/src/main/kotlin/online/javanese/krud/crud/Crud.kt Refactored Controller
  39. Previous solution: «Safe Fragments» • All arguments required to be

    Parcelable. OK for data and functional objects, not for Observables, DB or net connections
  40. Previous solution: «Safe Fragments» • All arguments required to be

    Parcelable. OK for data and functional objects, not for Observables, DB or net connections; • Ugly constructors
  41. Previous solution: «Safe Fragments» • All arguments required to be

    Parcelable. OK for data and functional objects, not for Observables, DB or net connections; • Ugly constructors; • Using Bundles
  42. Previous solution: «Safe Fragments» • All arguments required to be

    Parcelable. OK for data and functional objects, not for Observables, DB or net connections; • Ugly constructors; • Using Bundles • possible typos in keys
  43. Previous solution: «Safe Fragments» • All arguments required to be

    Parcelable. OK for data and functional objects, not for Observables, DB or net connections; • Ugly constructors; • Using Bundles • possible typos in keys; • possible heap pollution in getParcelable<T>
  44. Previous solution: «Safe Fragments» • All arguments required to be

    Parcelable. OK for data and functional objects, not for Observables, DB or net connections; • Ugly constructors; • Using Bundles • possible typos in keys; • possible heap pollution in getParcelable<T>; • custom Map and List storage surprises.
  45. Object graph: good architecture Application Activity Activity Service Fragment Fragment

    Child Fragment Fragment Fragment Fragment Fragment Child Fragment
  46. PresenterTag is a token for obtaining Presenter. Parcelable, can be

    passed anywhere. Similar to URL-based navigation, but type-safe.
  47. Passing data back and forth <- Argument <- result handler

    Handler functions survive config changes. Must be pure! Neither partial application nor capturing is allowed. optional cancellation handler ^
  48. What’s next? • Reuse Presenters; • Delegate tasks to small

    objects; • Write cross-platform delegates when you need it
  49. What’s next? • Reuse Presenters; • Delegate tasks to small

    objects; • Write cross-platform delegates when you need it; • Use ViewModels or whatever you want.