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

CQRS Architecture on Android

CQRS Architecture on Android

LT @ shibuya.apk #23

Keita Kagurazaka

March 20, 2018
Tweet

More Decks by Keita Kagurazaka

Other Decks in Programming

Transcript

  1. Command Query Separation (CQS) principle • Design concept devised by

    Bertrand Meyer • We should divide an object’s methods into either Command or Query ◦ Commands change the state but return no value ◦ Queries return a value but never change the state
  2. Command Query Separation principle fun getCount(): Int { return this.count

    } fun incrementCount() { this.count++ } fun incrementCount(): Int { return ++this.count } Do. Don’t.
  3. Command Query Separation principle fun getCount(): Int { return this.count

    } fun incrementCount() { this.count++ } fun incrementCount(): Int { return ++this.count } Do. Don’t. Apply the concept to Architecture level
  4. CQRS Architecture Presentation Layer Application Layer Domain Layer Infrastructure Layer

    Command Stack Query Stack Application Layer Domain Layer Command Model Query Model c Infrastructure Layer
  5. Command Stack / Query Stack • Command Stack ◦ Change

    the system state ◦ Does not return the state to presentation layer • Query Stack ◦ Never change the system state ◦ Returns the presentation models to presentation layer
  6. Command Stack ≠ Objects that have only command methods Command

    Stack’s objects can have query methods to achieve changing the system state
  7. Complexity is coming by unifying Domain Model • We have

    justified ourselves that Domain Model is complex because of Domain’s complexity • Segregation of Command and Query makes it easier to express Domain in Domain Model • CQRS lights up a new aspect of Domain
  8. Simple example: Conference app • User can show sessions, speakers

    and rooms info • User can make favorite sessions • All info are fetched by API • Use cache for improving user experience
  9. How to construct repositories? class SessionRepository { fun findAll(): List<Session>

    = if (isInvalid) { isInvalid = false sessionApi.getAll().also(sessionDb::store) } else { sessionDb.findAll() } fun invalidate() { isInvald = true } ...
  10. How to construct repositories? class SessionRepository { fun findAll(): List<Session>

    = sessionDb.findAll() fun refresh() { sessionApi.getAll().also(sessionDb::store) } ...
  11. invalidate() or refresh() problem • Repository exposes the concern to

    API ◦ Against to “Collection-like interface for accessing entities” • Repository is going to have the domain logic
  12. Is it really problem? • Maybe no if in the

    small project • However the bad feeling implies that we still have room for improving
  13. Segregate models into Command and Query • Command Models -

    update the local storage ◦ Fetch data from API ◦ Write fetched data to the local storage • Query Models - show the latest info ◦ Retrieve the local storage ◦ Re-query when the local storage is changed
  14. UseCase as a TransactionScript class RefreshSessions { operator fun invoke()

    { val newSessions = sessionApi.getAll() sessionDb.store(newSessions) } ...
  15. Query Models as Domain Models data class Session( val startTime:

    Date, val endTime: Date, … ) { fun getPeriodText(context: Context): String = context.getString(...) ...
  16. Query Models as Domain Models data class Session( val startTime:

    Date, val endTime: Date, … ) { fun getPeriodText(context: Context): String = context.getString(...) ... Can take Android Context since Query Domain Models concern presentation
  17. Query Models as Domain Models data class Session( val startTime:

    Date, val endTime: Date, … ) { fun getPeriodText(context: Context): String = context.getString(...) ... Can take Android Context since Query Domain Models concern presentation Avoid PresentationUtils class
  18. Re-query by observing Database changes • Some ORMs support observable

    queries ◦ Room - LiveData, RxJava ◦ Realm - Callback, RxJava ◦ Orma - RxJava, LiveData (in the plan) • Room also supports to use original classes instead of @Entity class in @Query
  19. CQRS Architecture on Android ViewModel UseCase CommandRepository Command Stack Query

    Stack Query Domain Models Change event QueryRepository
  20. CQRS vs Flux • Flux is a derivation of CQRS

    to optimize JavaScript world ◦ Non-complex command models ◦ No Database • Main difference is that the app state is stored on either database or memory (Store)
  21. Summary • CQRS is an architecture that segregate models into

    Command Stack and Query Stack • The separation makes it easier to construct models since understanding of Domain is definitely changed • CQRS and Flux are relatives