Slide 1

Slide 1 text

Unidirectional data flow on Android … using Kotlin @CesarValiente @CesarValiente

Slide 2

Slide 2 text

Unidirectional? A B C D

Slide 3

Slide 3 text

Unidirectional? A B C D

Slide 4

Slide 4 text

Unidirectional? A B C D

Slide 5

Slide 5 text

Unidirectional? A B C D

Slide 6

Slide 6 text

Unidirectional? A B C D

Slide 7

Slide 7 text

Global app state Current Value = 0 Next Value = 0 State is immutable.

Slide 8

Slide 8 text

Global app state Current Value = 0 Next Value = 0 +1 State is immutable.

Slide 9

Slide 9 text

Global app state Current Value = 0 +1 Next Value = 1 State is immutable.

Slide 10

Slide 10 text

Global app state +1 State = 1 Next Value = 1 Current Value = 1 State is immutable.

Slide 11

Slide 11 text

Global app state Next Value = 1 Current Value = 1 State is immutable.

Slide 12

Slide 12 text

Global app state Next Value = 1 +1 Current Value = 1 State is immutable.

Slide 13

Slide 13 text

Global app state +1 Current Value = 1 Next Value = 2 State is immutable.

Slide 14

Slide 14 text

Global app state +1 Next Value = 2 State = 2 Current Value = 2 State is immutable.

Slide 15

Slide 15 text

Global app state Next Value = 2 Current Value = 2 State is immutable.

Slide 16

Slide 16 text

Global app state Next Value = 2 Current Value = 2 +1 State is immutable.

Slide 17

Slide 17 text

Global app state Current Value = 2 +1 Next Value = 3 State is immutable.

Slide 18

Slide 18 text

Global app state +1 Next Value = 3 State = 3 Current Value = 3 State is immutable.

Slide 19

Slide 19 text

Flux Redux

Slide 20

Slide 20 text

Flux Redux STATE

Slide 21

Slide 21 text

VIEW Flux Redux STATE

Slide 22

Slide 22 text

VIEW ACTION Flux Redux STATE

Slide 23

Slide 23 text

VIEW ACTION DISPATCHER Flux Redux STATE

Slide 24

Slide 24 text

VIEW ACTION DISPATCHER REDUCER STORE Flux Redux STATE

Slide 25

Slide 25 text

KUnidirectional https://github.com/CesarValiente/KUnidirectional

Slide 26

Slide 26 text

KUnidirectional OSS sample app which shows this architecture. https://github.com/CesarValiente/KUnidirectional

Slide 27

Slide 27 text

KUnidirectional OSS sample app which shows this architecture. A simple item list app. https://github.com/CesarValiente/KUnidirectional

Slide 28

Slide 28 text

KUnidirectional OSS sample app which shows this architecture. A simple item list app. Everything is unidirectional. https://github.com/CesarValiente/KUnidirectional

Slide 29

Slide 29 text

KUnidirectional OSS sample app which shows this architecture. A simple item list app. Everything is unidirectional. Without external libraries, just Kotlin + Android. https://github.com/CesarValiente/KUnidirectional

Slide 30

Slide 30 text

ACTION REDUCER VIEW CONTROLLER-VIEW SIDE EFFECT 1 STORE Action State User interaction UI Data Optional Action SIDE EFFECT N

Slide 31

Slide 31 text

ACTION REDUCER VIEW CONTROLLER-VIEW SIDE EFFECT 1 STORE Action State User interaction UI Data Optional Action SIDE EFFECT N

Slide 32

Slide 32 text

ACTION REDUCER VIEW CONTROLLER-VIEW SIDE EFFECT 1 STORE Action State User interaction UI Data Optional Action SIDE EFFECT N

Slide 33

Slide 33 text

ACTION REDUCER VIEW CONTROLLER-VIEW SIDE EFFECT 1 STORE Action State User interaction UI Data Optional Action SIDE EFFECT N

Slide 34

Slide 34 text

ACTION REDUCER VIEW CONTROLLER-VIEW SIDE EFFECT 1 STORE Action State User interaction UI Data Optional Action SIDE EFFECT N

Slide 35

Slide 35 text

ACTION REDUCER VIEW CONTROLLER-VIEW SIDE EFFECT 1 STORE Action State User interaction UI Data Optional Action SIDE EFFECT N

Slide 36

Slide 36 text

ACTION REDUCER VIEW CONTROLLER-VIEW SIDE EFFECT 1 STORE Action State User interaction UI Data Optional Action SIDE EFFECT N

Slide 37

Slide 37 text

ACTION REDUCER VIEW CONTROLLER-VIEW SIDE EFFECT 1 STORE Action State User interaction UI Data Optional Action SIDE EFFECT N

Slide 38

Slide 38 text

Dependencies

Slide 39

Slide 39 text

Dependencies VIEW ANDROID DEPENDENCIES

Slide 40

Slide 40 text

Dependencies VIEW ANDROID DEPENDENCIES NO FRAMEWORK DEPENDENCIES ACTION REDUCER CONTROLLER-VIEW STORE

Slide 41

Slide 41 text

Dependencies VIEW ANDROID DEPENDENCIES NO FRAMEWORK DEPENDENCIES SIDE EFFECT 1 ANDROID DEPENDENCIES SIDE EFFECT N NO FRAMEWORK DEPENDENCIES ACTION REDUCER CONTROLLER-VIEW STORE

Slide 42

Slide 42 text

VIEW View CONTROLLER-VIEW

Slide 43

Slide 43 text

VIEW View CONTROLLER-VIEW ACTIVITY / FRAGMENT

Slide 44

Slide 44 text

VIEW User interaction View CONTROLLER-VIEW ACTIVITY / FRAGMENT

Slide 45

Slide 45 text

VIEW User interaction User interaction View CONTROLLER-VIEW ACTIVITY / FRAGMENT

Slide 46

Slide 46 text

VIEW User interaction User interaction New UI data to render View CONTROLLER-VIEW ACTIVITY / FRAGMENT

Slide 47

Slide 47 text

VIEW User interaction User interaction New UI data to render User result View CONTROLLER-VIEW ACTIVITY / FRAGMENT

Slide 48

Slide 48 text

ControllerView CONTROLLER-VIEW Store

Slide 49

Slide 49 text

ControllerView CONTROLLER-VIEW User interaction Store

Slide 50

Slide 50 text

ControllerView CONTROLLER-VIEW User interaction ACTION create Store

Slide 51

Slide 51 text

ControllerView CONTROLLER-VIEW User interaction ACTION create dispatch Store

Slide 52

Slide 52 text

ControllerView CONTROLLER-VIEW User interaction ACTION create State dispatch Store

Slide 53

Slide 53 text

ControllerView CONTROLLER-VIEW User interaction New UI data to render ACTION create State dispatch Store

Slide 54

Slide 54 text

abstract class ControllerView(
 val store: Store,
 mainThread: ThreadExecutor? = null): LifecycleCallbacks, StateHandler(mainThread) {

Slide 55

Slide 55 text

protected fun dispatch(action: T) {
 store.dispatch(action)
 } abstract class ControllerView(
 val store: Store,
 mainThread: ThreadExecutor? = null): LifecycleCallbacks, StateHandler(mainThread) {

Slide 56

Slide 56 text

protected fun dispatch(action: T) {
 store.dispatch(action)
 } abstract class ControllerView(
 val store: Store,
 mainThread: ThreadExecutor? = null): LifecycleCallbacks, StateHandler(mainThread) { abstract fun handleState(state: State) 
 }

Slide 57

Slide 57 text

Action ACTION

Slide 58

Slide 58 text

Action ACTION CREATE DELETE FETCH UPDATE

Slide 59

Slide 59 text

Action ACTION CREATE DELETE FETCH UPDATE NAVIGATE OTHERS

Slide 60

Slide 60 text

sealed class Action

Slide 61

Slide 61 text

sealed class Action sealed class UpdateAction : Action() {
 data class ReorderItemsAction(val items: List) : UpdateAction()
 
 data class UpdateItemAction(val localId: String,
 val text: String?,
 val color: Color) : UpdateAction()
 
 data class UpdateFavoriteAction( val localId: String, val favorite: Boolean) : UpdateAction()
 
 data class UpdateColorAction( val localId: String, val color: Color) : UpdateAction()
 }

Slide 62

Slide 62 text

sealed class Action sealed class UpdateAction : Action() {
 data class ReorderItemsAction(val items: List) : UpdateAction()
 
 data class UpdateItemAction(val localId: String,
 val text: String?,
 val color: Color) : UpdateAction()
 
 data class UpdateFavoriteAction( val localId: String, val favorite: Boolean) : UpdateAction()
 
 data class UpdateColorAction( val localId: String, val color: Color) : UpdateAction()
 } sealed class ReadAction : Action() {
 class FetchItemsAction : ReadAction()
 data class ItemsLoadedAction(val items: List) : ReadAction()
 }

Slide 63

Slide 63 text

STATE Reducer Store Store Remember, State is immutable.

Slide 64

Slide 64 text

STATE Reducer ACTION Store Action Store Remember, State is immutable.

Slide 65

Slide 65 text

STATE Reducer ACTION NEW STATE Store Action Store Remember, State is immutable.

Slide 66

Slide 66 text

STATE Reducer ACTION NEW STATE Store New state Action Action Action Store Remember, State is immutable.

Slide 67

Slide 67 text

State enum class Navigation {
 ITEMS_LIST,
 EDIT_ITEM
 }
 data class ItemsListScreen(
 val items: List = emptyList())
 
 data class EditItemScreen(val currentItem: Item = Item())
 
 data class State(
 val itemsListScreen: ItemsListScreen = ItemsListScreen(),
 val editItemScreen: EditItemScreen = EditItemScreen(),
 val navigation: Navigation = Navigation.ITEMS_LIST) Remember, State is immutable.

Slide 68

Slide 68 text

Store abstract class Store( val sideEffects: CopyOnWriteArrayList = CopyOnWriteArrayList(),
 val stateHandlers: CopyOnWriteArrayList = CopyOnWriteArrayList(),
 val storeThread: ThreadExecutor? = null) : Subscribers {

Slide 69

Slide 69 text

Store abstract class Store( val sideEffects: CopyOnWriteArrayList = CopyOnWriteArrayList(),
 val stateHandlers: CopyOnWriteArrayList = CopyOnWriteArrayList(),
 val storeThread: ThreadExecutor? = null) : Subscribers { private fun handle(action: Action) {
 val newState = reduce(action, state)
 dispatch(newState)
 sideEffects.dispatch(action)
 }

Slide 70

Slide 70 text

Store abstract class Store( val sideEffects: CopyOnWriteArrayList = CopyOnWriteArrayList(),
 val stateHandlers: CopyOnWriteArrayList = CopyOnWriteArrayList(),
 val storeThread: ThreadExecutor? = null) : Subscribers { private fun handle(action: Action) {
 val newState = reduce(action, state)
 dispatch(newState)
 sideEffects.dispatch(action)
 } fun dispatch(newState: State) {
 state = newState
 stateHandlers.dispatch(state)
 } 
 . . .

Slide 71

Slide 71 text

Reducer . . . private fun reduce(action: Action, currentState: State): State =
 when (action) {
 is CreationAction -> CreationReducer.reduce(action, currentState)
 is UpdateAction -> UpdateReducer.reduce(action, currentState)
 is ReadAction -> ReadReducer.reduce(action, currentState)
 is DeleteAction -> DeleteReducer.reduce(action, currentState)
 is NavigationAction -> NavigationReducer.reduce(action, currentState)
 } }

Slide 72

Slide 72 text

abstract class Reducer {
 
 open fun reduce(action: T, currentState: State) : State =
 with(currentState) {
 currentState.copy(
 itemsListScreen = reduceItemsListScreen(action, itemsListScreen),
 editItemScreen = reduceEditItemScreen(action, editItemScreen),
 navigation = reduceNavigation(action, navigation)
 )
 } . . . } Reducer

Slide 73

Slide 73 text

Models

Slide 74

Slide 74 text

STORE STORE MODELS Models

Slide 75

Slide 75 text

STORE STORE MODELS PRESENTATION STORE MODELS + EXTENSIONS Models

Slide 76

Slide 76 text

STORE STORE MODELS PRESENTATION STORE MODELS + EXTENSIONS Models PERSISTENCE PERSISTENCE MODELS MAPPER

Slide 77

Slide 77 text

enum class Color {
 RED, YELLOW, GREEN, BLUE, WHITE
 }
 
 data class Item(
 val localId: String = generateLocalId(),
 val text: String? = null,
 val favorite: Boolean = false,
 val color: Color = Color.WHITE,
 val position: Long = object : PositionsFactory {}.newPosition()) Store Models

Slide 78

Slide 78 text

import com.cesarvaliente.kunidirectional.persistence.Color as PersistenceColor
 import com.cesarvaliente.kunidirectional.persistence.Item as PersistenceItem
 import com.cesarvaliente.kunidirectional.store.Color as StoreColor
 import com.cesarvaliente.kunidirectional.store.Item as StoreItem Mapper fun StoreItem.toPersistenceItem(): PersistenceItem =
 with(this) {
 PersistenceItem(localId, text, favorite, color.toPersistenceColor(), position)
 }
 
 fun StoreColor.toPersistenceColor(): PersistenceColor =
 when (this) {
 StoreColor.BLUE -> PersistenceColor.BLUE
 StoreColor.GREEN -> PersistenceColor.GREEN
 StoreColor.RED -> PersistenceColor.RED
 StoreColor.WHITE -> PersistenceColor.WHITE
 StoreColor.YELLOW -> PersistenceColor.YELLOW
 }

Slide 79

Slide 79 text

Presentation models? fun Color.toColorResource(): Int =
 when (this) {
 RED -> R.color.red
 YELLOW -> R.color.yellow
 GREEN -> R.color.green
 BLUE -> R.color.blue
 WHITE -> R.color.white
 }
 
 fun Item.getStableId(): Long = this.localId.hashCode().toLong()

Slide 80

Slide 80 text

REDUCER Side Effect

Slide 81

Slide 81 text

SIDE EFFECT 1 REDUCER Side Effect

Slide 82

Slide 82 text

SIDE EFFECT 1 SIDE EFFECT 2 REDUCER Side Effect

Slide 83

Slide 83 text

SIDE EFFECT N SIDE EFFECT 1 SIDE EFFECT 2 REDUCER . . . Side Effect

Slide 84

Slide 84 text

SIDE EFFECT N SIDE EFFECT 1 SIDE EFFECT 2 REDUCER . . . Side Effect Action

Slide 85

Slide 85 text

SIDE EFFECT N SIDE EFFECT 1 SIDE EFFECT 2 REDUCER . . . Side Effect Action New action

Slide 86

Slide 86 text

Threading? VIEW STORE PERSISTENCE SIDE EFFECT

Slide 87

Slide 87 text

Threading? VIEW STORE PERSISTENCE SIDE EFFECT UI Thread

Slide 88

Slide 88 text

Threading? VIEW STORE PERSISTENCE SIDE EFFECT UI Thread Store Thread

Slide 89

Slide 89 text

Threading? VIEW STORE PERSISTENCE SIDE EFFECT UI Thread Store Thread Persistence Thread (Side Effect N Thread)

Slide 90

Slide 90 text

Testing?

Slide 91

Slide 91 text

Testing? UI tests on Presentation layer (View).

Slide 92

Slide 92 text

Testing? UI tests on Presentation layer (View). Unit + Integration tests on our ControllerViews.

Slide 93

Slide 93 text

Testing? UI tests on Presentation layer (View). Unit + Integration tests on our ControllerViews. Unit + instrumentation tests in our Persistence layer (side effect).

Slide 94

Slide 94 text

Testing? UI tests on Presentation layer (View). Unit + Integration tests on our ControllerViews. Unit + instrumentation tests in our Persistence layer (side effect). Unit tests in our Store layer.

Slide 95

Slide 95 text

Demo 1!

Slide 96

Slide 96 text

Demo 1!

Slide 97

Slide 97 text

Demo 1! FETCH LIST ITEMS LIST ITEMS Action State

Slide 98

Slide 98 text

Demo 1! OPEN EDIT ITEM NAVIGATION UPDATED FETCH LIST ITEMS LIST ITEMS Action State

Slide 99

Slide 99 text

Demo 1! OPEN EDIT ITEM NAVIGATION UPDATED SAVE ITEM NEW ITEM FETCH LIST ITEMS LIST ITEMS Action State

Slide 100

Slide 100 text

Demo 1! OPEN EDIT ITEM NAVIGATION UPDATED SAVE ITEM NEW ITEM TO NOTE LIST NAVIGATION UPDATED FETCH LIST ITEMS LIST ITEMS Action State

Slide 101

Slide 101 text

Demo 1! OPEN EDIT ITEM NAVIGATION UPDATED SAVE ITEM NEW ITEM TO NOTE LIST NAVIGATION UPDATED FETCH LIST ITEMS LIST ITEMS FETCH LIST ITEMS LIST ITEMS Action State

Slide 102

Slide 102 text

Demo 2! Side effects are optional and decoupled elements.

Slide 103

Slide 103 text

Demo 2! Side effects are optional and decoupled elements.

Slide 104

Slide 104 text

Some thoughts

Slide 105

Slide 105 text

Some thoughts This is not the Philosopher Stone of the architectures.

Slide 106

Slide 106 text

Some thoughts Unidirectional makes your code easy to follow. This is not the Philosopher Stone of the architectures.

Slide 107

Slide 107 text

Some thoughts Decoupling elements in your app makes maintainability and testing easier. Unidirectional makes your code easy to follow. This is not the Philosopher Stone of the architectures.

Slide 108

Slide 108 text

Some thoughts Decoupling elements in your app makes maintainability and testing easier. Unidirectional makes your code easy to follow. This is not the Philosopher Stone of the architectures. Immutability makes your code safer.

Slide 109

Slide 109 text

Some thoughts Decoupling elements in your app makes maintainability and testing easier. Take advantage of the tools you have. Unidirectional makes your code easy to follow. This is not the Philosopher Stone of the architectures. Immutability makes your code safer.

Slide 110

Slide 110 text

Some thoughts Decoupling elements in your app makes maintainability and testing easier. Take advantage of the tools you have. What is good for our problem maybe is not good for yours. Unidirectional makes your code easy to follow. This is not the Philosopher Stone of the architectures. Immutability makes your code safer.

Slide 111

Slide 111 text

? @CesarValiente @CesarValiente

Slide 112

Slide 112 text

Thanks! @CesarValiente @CesarValiente

Slide 113

Slide 113 text

Useful Links KUnidirectional app KUnidirectional demo videos Flux Redux Luis G. Valle: Flux on Android André Staltz: Unidirectional data flow architectures Austin Mueller: Flux and Android Brian Egan and Guillaume Lung: Exploring the possibilities of Unidirectional Data Flow Architectures on Android

Slide 114

Slide 114 text

License (cc) 2017 César Valiente. Some rights reserved. This document is distributed under the Creative Commons Attribution-ShareAlike 3.0 license, available in http://creativecommons.org/licenses/by-sa/3.0/

Slide 115

Slide 115 text

Image licenses Flux and Redux images are property of Facebook. Emojis by Emoji One (CC-BY): http://emojione.com/