A presentation at Londroid in in London, UK by Jake Wharton
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 {
3 ;
private final Mark[][] cells ;
public Board() {
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) {
requireNonNull (name, "name == null" );
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) {
requireNonNull (board, "board == null" );
requireNonNull (player1, "player1 == null" );
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) {
requireNonNull (name, "name == null" );
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 {
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
Kotlin’s popularity has exploded in the past year and Google’s announcement of first-party support at I/O means it’s only going to keep increasing. Now is the perfect time to jump on the language as its future in mobile and beyond is very bright.
This talk will take a look at where the language is headed and see if it can deliver on a promise of cross-platform use.