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. CQRS Architecture
    on Android
    Keita Kagurazaka

    View full-size slide

  2. What is CQRS?

    View full-size slide

  3. CQRS
    ● Command and Query Responsibility Segregation
    ● Architecture extending CQS principle

    View full-size slide

  4. CQRS
    ● Command and Query Responsibility Segregation
    ● Architecture extending CQS principle

    View full-size slide

  5. 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

    View full-size slide

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

    View full-size slide

  7. 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

    View full-size slide

  8. Traditional Layered Architecture
    Presentation Layer
    Application Layer
    Domain Layer
    Infrastructure Layer

    View full-size slide

  9. 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

    View full-size slide

  10. 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

    View full-size slide

  11. Command Stack

    Objects that have only
    command methods

    View full-size slide

  12. Command Stack

    Objects that have only
    command methods
    Command Stack’s objects can have query
    methods to achieve changing the system state

    View full-size slide

  13. Query Stack

    Objects that have only
    query methods

    View full-size slide

  14. Why should we segregate
    Command stack and Query stack?

    View full-size slide

  15. 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

    View full-size slide

  16. 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

    View full-size slide

  17. What is Domain Model?
    Session Speaker
    Room
    Entities

    View full-size slide

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

    View full-size slide

  19. How to construct repositories?
    class SessionRepository {
    fun findAll(): List =
    sessionDb.findAll()
    fun refresh() {
    sessionApi.getAll().also(sessionDb::store)
    }
    ...

    View full-size slide

  20. 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

    View full-size slide

  21. Is it really problem?
    ● Maybe no if in the small project
    ● However the bad feeling implies that we still have room for
    improving

    View full-size slide

  22. 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

    View full-size slide

  23. Command Models
    Session
    DAO
    ApiClient
    Session is just a Value Object
    UseCase
    Domain

    View full-size slide

  24. UseCase as a TransactionScript
    class RefreshSessions {
    operator fun invoke() {
    val newSessions = sessionApi.getAll()
    sessionDb.store(newSessions)
    }
    ...

    View full-size slide

  25. Query Models
    Session Speaker
    Room
    Entities

    View full-size slide

  26. Query Models as Domain Models
    data class Session(
    val startTime: Date,
    val endTime: Date,

    ) {
    fun getPeriodText(context: Context): String =
    context.getString(...)
    ...

    View full-size slide

  27. 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

    View full-size slide

  28. 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

    View full-size slide

  29. 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

    View full-size slide

  30. CQRS Architecture on Android
    ViewModel
    UseCase
    CommandRepository
    Command Stack Query Stack
    Query Domain Models
    Change event
    QueryRepository

    View full-size slide

  31. Flux?
    View
    ActionCreators
    State
    Store
    Action

    View full-size slide

  32. 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)

    View full-size slide

  33. 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

    View full-size slide