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

X

X
O
X X X O O O

X

X
O
X

X X O O O
X

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

iOS Web Server / API Android

app/

app/ wear/

app/ wear/ common/

app/ wear/ common/

wear/ common/ app/

app/ wear/ common/

app/ wear/ common/

app/ wear/ util/ common/

app/ wear/ common/ util/ models/

package xo; public enum Mark {

X , O ; }

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 ); }

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() {

package xo; public enum State {

PLAYER_1_MOVE ,

PLAYER_2_MOVE ,

PLAYER_1_WIN ,

PLAYER_2_WIN ,

DRAW , }

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 )

Game Board Mark State Player

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

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

Game Mark State Board Player

State Board Game Mark Player

Game Mark State Board *.java *.kt Player

*.kt Game Mark State *.java

kotlinc *.kt Game Mark State *.java

*.kt Game Mark State *.java kotlinc

javac *.kt Game Mark State *.java kotlinc

javac *.kt Game Mark State *.java kotlinc

kotlinc javac *.kt Game Mark State *.java

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

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

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

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

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

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

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

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

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

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

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

app/ wear/ common/ util/ models/

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

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

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

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

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

iOS Web Server / API Android

iOS Android Web Server / API

iOS Android View Models Web Server / API

iOS Android View Models Presenters Web Server / API

iOS Web Android View Models Presenters Server / API

iOS Web Android View Models Presenters Client Backend Server / API

iOS Web Server / API Android View Models Presenters Client Backend

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

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

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

data class NewGameUi Model(

val winTotal : Long,

val lossTotal : Long )

data class NewGameUi Model(

val winTotal : Long,

val lossTotal : Long )

data class GameUi Model(

val game : Game )

data class NewGameUi Model(

val winTotal : Long,

val lossTotal : Long )

data class GameUi Model( )

val game : Game

data class NewGameUiM odel(

val winTotal : Long,

val lossTotal : Long )

data class GameUi Model(

val game : Game )

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

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

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

class NewGamePresenter { C

fun model(): NewGameUi Model { } B

} A

class NewGamePresenter( private val gameStore : GameStore) { C

fun model(): NewGameUi Model { } B

} A

class NewGamePresenter( private val gameStore : GameStore) { C

fun model(): NewGameUi Model {

val totals = gameStore .totals()

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

} A

class GamePresenter

{ D

fun model(): GameUiModel { C

} B

} A

class GamePresenter( private val gameId : Long) { D

fun model(): GameUiModel { C

} B

} A

class GamePresenter(

private val gameId : Long,

private val gameStore : GameStore ) { D

fun model(): GameUiModel { C

} B

} A

class GamePresenter(

private val gameId : Long,

private val gameStore : GameStore ) { D

fun models(): Observable<GameUiModel> { C

} B

} A

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

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

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

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

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

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

interface GameStore {

} A

interface GameStore {

fun totals(): Single<Totals>

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

interface GameStore {

fun totals(): Single<Totals>

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

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

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

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

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

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

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 ()

}

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 ()

}

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

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

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

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

Android iOS Web Client Backend iOS Web Server / API

Android View Models Presenters Business Logic Models

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

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

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

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 ()

}

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

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

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

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

class GameView(context: Context, attrs: AttributeSet)

: Consumer<GamePresenter.UiModel> {

fun accept(model: GamePresenter.UiModel) {

// TODO bind to view...

} }

iOS ???

function update(model) {

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

}

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

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

X
O
X

X X O O O
X

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