It's a Kotlin, Kotlin, Kotlin World

A presentation at Londroid in July 2017 in London, UK by Jake Wharton

Slide 1

Slide 1

IT'S A KOTLIN, KOTLIN, KOTLIN WORLD! JAKE WHARTON PRESENTS

Slide 2

Slide 2

Slide 3

Slide 3

X

Slide 4

Slide 4

X
O
X X X O O O

X

Slide 5

Slide 5

X
O
X

X X O O O
X

Slide 6

Slide 6

X O Player XO Player X X X O O O X

Slide 7

Slide 7

iOS Web Server / API Android

Slide 8

Slide 8

app/

Slide 9

Slide 9

app/ wear/

Slide 10

Slide 10

app/ wear/ common/

Slide 11

Slide 11

app/ wear/ common/

Slide 12

Slide 12

wear/ common/ app/

Slide 13

Slide 13

app/ wear/ common/

Slide 14

Slide 14

app/ wear/ common/

Slide 15

Slide 15

app/ wear/ util/ common/

Slide 16

Slide 16

app/ wear/ common/ util/ models/

Slide 17

Slide 17

Slide 18

Slide 18

package xo; public enum Mark {

X , O ; }

Slide 19

Slide 19

package xo; import java.util.Arrays; public final class Board {

private static final int SIZE

3 ;

private final Mark[][] cells ;

public Board() {

this . cells

new Mark[ 3 ][ 3 ]; }

// TODO mutator methods...

@Override public boolean equals(Object o) {

if ( this == o) return true ;

if (!(o instanceof Board)) return false ; Board other = (Board) o;

return Arrays. deepEquals ( cells , other. cells ); }

@Override public int hashCode() {

return Arrays. deepHashCode ( cells ); }

Slide 20

Slide 20

package xo; import static java.util.Objects. requireNonNull ; public final class Player {

public final String name ;

public final Mark mark ;

public Player(String name, Mark mark) {

this . name

requireNonNull (name, "name == null" );

this . mark

requireNonNull (mark, "mark == null" ); }

@Override public boolean equals(Object o) {

if ( this == o) return true ;

if (!(o instanceof Player)) return false ; Player other = (Player) o;

return name .equals(other. name ) && mark == other. mark ; }

@Override public int hashCode() {

return 31 * name .hashCode() + mark .hashCode(); }

@Override public String toString() {

Slide 21

Slide 21

package xo; public enum State {

PLAYER_1_MOVE ,

PLAYER_2_MOVE ,

PLAYER_1_WIN ,

PLAYER_2_WIN ,

DRAW , }

Slide 22

Slide 22

package xo; import static java.util.Objects. requireNonNull ; public final class Game {

private final Board board ;

private final Player player1 ;

private final Player player2 ;

private State state = State. PLAYER_1_MOVE ;

public Game(Board board, Player player1, Player player2) {

this . board

requireNonNull (board, "board == null" );

this . player1

requireNonNull (player1, "player1 == null" );

this . player2

requireNonNull (player2, "player2 == null" ); }

// TODO mutator methods...

@Override public boolean equals(Object o) {

if ( this == o) return true ;

if (!(o instanceof Game)) return false ; Game other = (Game) o;

return board .equals(other. board ) && player1 .equals(other. player1 ) && player2 .equals(other. player2 )

Slide 23

Slide 23

Game Board Mark State Player

Slide 24

Slide 24

public final class Player {

public final String name ;

public final Mark mark ;

public Player(String name, Mark mark) {

this . name

requireNonNull (name, "name == null" );

this . mark

requireNonNull (mark, "mark == null" ); } A

@Override public boolean equals(Object o) {

if ( this == o) return true ;

if (!(o instanceof Player)) return false ; Player other = (Player) o;

return name .equals(other. name ) && mark == other. mark ; } B

@Override public int hashCode() {

return 31 * name .hashCode() + mark .hashCode(); } C

@Override public String toString() {

return "Player{name='" + name + ", mark=" + mark + '}' ; } D

} E

Slide 25

Slide 25

data class Player( val name : String, val mark : Mark) public final { public final ; public final ; public Player(String name, Mark mark) { this . name = requireNonNull (name, "name == null" ); this . mark = requireNonNull (mark, "mark == null" ); } A @Override public boolean equals(Object o) { if ( this == o) return true ; if (!(o instanceof Player)) return false ; Player other = (Player) o; return name .equals(other. name ) && mark == other. mark ; } B @Override public int hashCode() { return 31 * name .hashCode() + mark .hashCode(); } C @Override public String toString() { return "Player{name='" + name + ", mark=" + mark + '}' ; } D } E

Slide 26

Slide 26

Game Mark State Board Player

Slide 27

Slide 27

State Board Game Mark Player

Slide 28

Slide 28

Game Mark State Board *.java *.kt Player

Slide 29

Slide 29

*.kt Game Mark State *.java

Slide 30

Slide 30

kotlinc *.kt Game Mark State *.java

Slide 31

Slide 31

*.kt Game Mark State *.java kotlinc

Slide 32

Slide 32

javac *.kt Game Mark State *.java kotlinc

Slide 33

Slide 33

javac *.kt Game Mark State *.java kotlinc

Slide 34

Slide 34

kotlinc javac *.kt Game Mark State *.java

Slide 35

Slide 35

kotlin-stdlib kotlinc javac *.kt Game Mark State *.java

Slide 36

Slide 36

kotlin-stdlib kotlinc javac *.kt Game Mark State *.java models/

Slide 37

Slide 37

kotlin-stdlib kotlinc javac *.kt Game Mark State *.java models/

Slide 38

Slide 38

kotlin-stdlib kotlinc javac *.kt Game Mark State *.java models/

Slide 39

Slide 39

kotlin-stdlib kotlinc javac *.kt Game Mark State *.java

Slide 40

Slide 40

kotlin-stdlib kotlinc Game Mark State javac *.kt *.java

Slide 41

Slide 41

kotlin-stdlib kotlinc Game Mark State javac *.kt *.java

Slide 42

Slide 42

kotlin-stdlib kotlinc State Mark Game javac *.kt *.java

Slide 43

Slide 43

kotlin-stdlib kotlinc State *.java Mark Game javac *.kt

Slide 44

Slide 44

kotlin-stdlib kotlinc *.java State Mark Game *.kt

Slide 45

Slide 45

app/ wear/ common/ util/ models/ kotlin-stdlib kotlinc *.java State Mark Game *.kt

Slide 46

Slide 46

app/ wear/ common/ util/ models/

Slide 47

Slide 47

Server / API iOS Web Android app/ wear/ common/ util/ models/

Slide 48

Slide 48

Server / API iOS Web Android app/ wear/ util/ models/ common/

Slide 49

Slide 49

Server / API iOS Web Android app/ wear/ util/ models/ common/

Slide 50

Slide 50

Server / API iOS Web Android app/ wear/ util/ models/ common/

Slide 51

Slide 51

Server / API iOS Web Android app/ wear/ util/ models/ common/ protos

Slide 52

Slide 52

iOS Web Server / API Android

Slide 53

Slide 53

iOS Android Web Server / API

Slide 54

Slide 54

iOS Android View Models Web Server / API

Slide 55

Slide 55

iOS Android View Models Presenters Web Server / API

Slide 56

Slide 56

iOS Web Android View Models Presenters Server / API

Slide 57

Slide 57

iOS Web Android View Models Presenters Client Backend Server / API

Slide 58

Slide 58

iOS Web Server / API Android View Models Presenters Client Backend

Slide 59

Slide 59

iOS Web Server / API Android View Models Presenters Client Backend Business Logic

Slide 60

Slide 60

iOS Web Server / API Android View Models Presenters Client Backend Business Logic Models

Slide 61

Slide 61

iOS Android View Models Web Server / API Presenters Client Backend Business Logic Models

Slide 62

Slide 62

data class NewGameUi Model(

val winTotal : Long,

val lossTotal : Long )

Slide 63

Slide 63

data class NewGameUi Model(

val winTotal : Long,

val lossTotal : Long )

data class GameUi Model(

val game : Game )

Slide 64

Slide 64

data class NewGameUi Model(

val winTotal : Long,

val lossTotal : Long )

data class GameUi Model( )

val game : Game

Slide 65

Slide 65

data class NewGameUiM odel(

val winTotal : Long,

val lossTotal : Long )

data class GameUi Model(

val game : Game )

Slide 66

Slide 66

iOS Android View Models Web Server / API Presenters Client Backend Business Logic Models

Slide 67

Slide 67

iOS Android View Models Web Server / API Presenters Client Backend Business Logic Models

Slide 68

Slide 68

iOS Android View Models Presenters Web Server / API Client Backend Business Logic Models

Slide 69

Slide 69

class NewGamePresenter { C

fun model(): NewGameUi Model { } B

} A

Slide 70

Slide 70

class NewGamePresenter( private val gameStore : GameStore) { C

fun model(): NewGameUi Model { } B

} A

Slide 71

Slide 71

class NewGamePresenter( private val gameStore : GameStore) { C

fun model(): NewGameUi Model {

val totals = gameStore .totals()

return NewGameUiModel(totals. wins , totals. losses ) } B

} A

Slide 72

Slide 72

class GamePresenter

{ D

fun model(): GameUiModel { C

} B

} A

Slide 73

Slide 73

class GamePresenter( private val gameId : Long) { D

fun model(): GameUiModel { C

} B

} A

Slide 74

Slide 74

class GamePresenter(

private val gameId : Long,

private val gameStore : GameStore ) { D

fun model(): GameUiModel { C

} B

} A

Slide 75

Slide 75

class GamePresenter(

private val gameId : Long,

private val gameStore : GameStore ) { D

fun models(): Observable<GameUiModel> { C

} B

} A

Slide 76

Slide 76

class GamePresenter(

private val gameId : Long,

private val gameStore : GameStore ) { D

fun move(row: Int, col: Int ) Z { C

} G

fun models(): Observable<GameUiModel> { C

} B

} A

Slide 77

Slide 77

class GamePresenter(

private val gameId : Long,

private val gameStore : GameStore ) { D

fun models(events: Observable<UiEvent>): Observable<GameUiModel> { C

} B

sealed class UiEvent {

data class Move( val

row : Int, val

col : Int): UiEvent() // ... }

} A fun move( ) Z { C } G

Slide 78

Slide 78

iOS Android View Models Presenters Web Server / API Client Backend Business Logic Models

Slide 79

Slide 79

iOS Android View Models Presenters Web Server / API Client Backend Business Logic Models

Slide 80

Slide 80

iOS Web Android View Models Presenters Server / API Client Backend Business Logic Models

Slide 81

Slide 81

iOS Web Android View Models Presenters Client Backend Server / API Business Logic Models

Slide 82

Slide 82

interface GameStore {

} A

Slide 83

Slide 83

interface GameStore {

fun totals(): Single<Totals>

data class Totals( val wins : Long, val losses : Long) } A

Slide 84

Slide 84

interface GameStore {

fun totals(): Single<Totals>

fun game(id: Long): Observable<Game>

data class Totals( val wins : Long, val losses : Long) } A

Slide 85

Slide 85

interface GameStore {

fun totals(): Single<Totals>

fun game(id: Long): Observable<Game>

fun move(id: Long, row: Int, col: Int): Completable

data class Totals( val wins : Long, val losses : Long) } A

Slide 86

Slide 86

iOS Web Android View Models Presenters Client Backend Server / API Business Logic Models

Slide 87

Slide 87

iOS Web Android View Models Presenters Client Backend Server / API Business Logic Models

Slide 88

Slide 88

Android iOS Web Client Backend iOS Web Server / API Android View Models Presenters Business Logic Models

Slide 89

Slide 89

class SqliteGameStore( private val

db : SQLiteDatabase) : GameStore {

override fun totals() = TODO ()

override fun game(id: Long) = TODO ()

override fun move(id: Long, row: Int, col: Int) = TODO ()

}

Slide 90

Slide 90

class IosGameStore( private val

db : CoreDataGameStore) : GameStore {

override fun totals() = TODO ()

override fun game(id: Long) = TODO ()

override fun move(id: Long, row: Int, col: Int) = TODO ()

}

Slide 91

Slide 91

class IosGameStore(

) : GameStore {

override fun totals() = TODO ()

override fun game(id: Long) = TODO ()

override fun move(id: Long, row: Int, col: Int) = TODO ()

}

private val

db : CoreDataGameStore

Slide 92

Slide 92

class IosGameStore(

) : GameStore {

override fun totals() = TODO ()

override fun game(id: Long) = TODO ()

override fun move(id: Long, row: Int, col: Int) = TODO ()

}

private val

db : CoreDataGameStore // tictactoe.def headers = game_store.h

Slide 93

Slide 93

class StorageGameStore( private val

store : Storage) : GameStore {

override fun totals() = TODO ()

override fun game(id: Long) = TODO ()

override fun move(id: Long, row: Int, col: Int) = TODO ()

} A

Slide 94

Slide 94

import org.w3c.dom.Storage class StorageGameStore(

    )

: GameStore {

override fun totals() = TODO ()

override fun game(id: Long) = TODO ()

override fun move(id: Long, row: Int, col: Int) = TODO ()

} A

              private val

store : Storage

Slide 95

Slide 95

Android iOS Web Client Backend iOS Web Server / API

Android View Models Presenters Business Logic Models

Slide 96

Slide 96

Android iOS Web iOS Web Android View Models Presenters Client Backend Server / API Business Logic Models

Slide 97

Slide 97

Android iOS Web iOS Web Server / API Android View Models Presenters Client Backend Business Logic Models

Slide 98

Slide 98

Android iOS Web iOS Web Server / API Android View Models Presenters Client Backend Business Logic Models

Slide 99

Slide 99

object TicTacToeLogic {

fun validateMove(

game: Game, player: Player, row: Int, col: Int): Boolean {

when (game. state ) { State. PLAYER_1_MOVE -> require (game. player1 == player)

State. PLAYER_2_MOVE -> require (game. player2 == player)

else -> error ( "Game is over" ) }

return game. board [row][col] == null

}

fun nextState(game: Game): State { findWinner(game. board )?. let {

return if (game. player1 . mark

it ) State. PLAYER_1_WIN

else State. PLAYER_2_WIN

}

if (game. board . isComplete ()) {

return State. DRAW

}

return if (game. state == State. PLAYER_1_MOVE ) State. PLAYER_2_MOVE

else State. PLAYER_1_MOVE

}

fun findWinner(board: Board): Mark? = TODO ()

fun Board.isComplete(): Boolean = TODO ()

}

Slide 100

Slide 100

Android iOS Web iOS Web Server / API Android View Models Presenters Client Backend Business Logic Models

Slide 101

Slide 101

Android iOS Web iOS Web Server / API Android View Models Presenters Client Backend Business Logic Models

Slide 102

Slide 102

Android iOS Web iOS Web Server / API Android View Models Presenters Client Backend Business Logic Models

Slide 103

Slide 103

iOS Web Server / API Android Android iOS Web View Models Presenters Client Backend Business Logic Models

Slide 104

Slide 104

class GameView(context: Context, attrs: AttributeSet)

: Consumer<GamePresenter.UiModel> {

fun accept(model: GamePresenter.UiModel) {

// TODO bind to view...

} }

Slide 105

Slide 105

iOS ???

Slide 106

Slide 106

function update(model) {

// TODO bind to DOM/template/JSX/whatever...

}

Slide 107

Slide 107

@POST @Path ( "/api/move" ) fun Game move( @QueryParam( "id" ) id: Long, @QueryParam( "row" ) row: Int, @QueryParam( "col" ) col: Int) {

// TODO check business logic, persist, return udpated game ... }

Slide 108

Slide 108

Android iOS Web iOS Web Server / API Android View Models Presenters Client Backend Business Logic Models

Slide 109

Slide 109

X
O
X

X X O O O
X

Slide 110

Slide 110

IT'S A KOTLIN, KOTLIN, KOTLIN WORLD! @JAKEWHARTON