Slide 1

Slide 1 text

Effective Kotlin LIGHTNING TALK

Slide 2

Slide 2 text

loves

Slide 3

Slide 3 text

Let’s talk about… Singleton

Slide 4

Slide 4 text

// Kotlin object Singleton // Java public class Singleton { private Singleton INSTANCE; private Singleton() { } public Singleton getInstance() { if (INSTANCE != null) { INSTANCE = new Singleton(); } return INSTANCE; } }

Slide 5

Slide 5 text

Let’s talk about… Primitive Obsession

Slide 6

Slide 6 text

public class Api { public List doSearch( String deviceToken // other parameters ) { String customerId = getCustomerIdFromSessionToken(deviceToken); // Do something and returns the search return ArrayList(); } private String getCustomerIdFromSessionToken(String authToken) { // Retrieve the customer through the user session return "CustomerId"; } }

Slide 7

Slide 7 text

public class Api { public List doSearch( String deviceToken // other parameters ) { String customerId = getCustomerIdFromSessionToken(deviceToken); // Do something and returns the search return ArrayList(); } private String getCustomerIdFromSessionToken(String authToken) { // Retrieve the customer through the user session return "CustomerId"; } }

Slide 8

Slide 8 text

public class Api { public List doSearch( String deviceToken // other parameters ) { String customerId = getCustomerIdFromSessionToken(deviceToken); // Do something and returns the search return ArrayList(); } private String getCustomerIdFromSessionToken(String authToken) { // Retrieve the customer through the user session return "CustomerId"; } }

Slide 9

Slide 9 text

public class Api { public List doSearch( String deviceToken // other parameters ) { String customerId = getCustomerIdFromSessionToken(deviceToken); // Do something and returns the search return ArrayList(); } private String getCustomerIdFromSessionToken(String authToken) { // Retrieve the customer through the user session return "CustomerId"; } }

Slide 10

Slide 10 text

public class Api { public List doSearch( String deviceToken // other parameters ) { String customerId = getCustomerIdFromSessionToken(deviceToken); // Do something and returns the search return ArrayList(); } private String getCustomerIdFromSessionToken(String authToken) { // Retrieve the customer through the user session return "CustomerId"; } }

Slide 11

Slide 11 text

IllegalArgumentException: Invalid UUID

Slide 12

Slide 12 text

class Api { fun doSearch( deviceToken: String // other parameters ): List { val customerId = getCustomerIdFromSessionToken(deviceToken) // Do something and returns the search return ArrayList() } private fun getCustomerIdFromSessionToken(authToken: String): String { // Retrieve the customer through the user session return "CustomerId" } }

Slide 13

Slide 13 text

class Api { fun doSearch( deviceToken: String // other parameters ): List { val customerId = getCustomerIdFromSessionToken(deviceToken) // Do something and returns the search return ArrayList() } private fun getCustomerIdFromSessionToken(authToken: String): String { // Retrieve the customer through the user session return "CustomerId" } }

Slide 14

Slide 14 text

class Api { fun doSearch( sessionToken: String // other parameters ): List { val customerId = getCustomerIdFromSessionToken(sessionToken) // Do something and returns the search return ArrayList() } private fun getCustomerIdFromSessionToken(sessionToken: String): String { // Retrieve the customer through the user session return "CustomerId" } }

Slide 15

Slide 15 text

class Api { fun doSearch( sessionToken: SessionToken // other parameters ): List { val customerId = getCustomerIdFromSessionToken(sessionToken) // Do something and returns the search return ArrayList() } private fun getCustomerIdFromSessionToken(sessionToken: SessionToken): String { // Retrieve the customer through the user session return "CustomerId" } }

Slide 16

Slide 16 text

class SessionToken(val token: UUID) { constructor(token: String): this(UUID.fromString(token)) }

Slide 17

Slide 17 text

class SessionToken(val token: UUID) { constructor(token: String): this(UUID.fromString(token)) }

Slide 18

Slide 18 text

class SessionToken(val token: UUID) { constructor(token: String): this(UUID.fromString(token)) }

Slide 19

Slide 19 text

inline class SessionToken(val token: UUID) { constructor(token: String): this(UUID.fromString(token)) }

Slide 20

Slide 20 text

Let’s talk about… Composition over Inheritance

Slide 21

Slide 21 text

// Kotlin class Foo open class Foo // Java public final class Foo {} public class Foo {}

Slide 22

Slide 22 text

data class CustomerList( val customers: List ) { {…} }

Slide 23

Slide 23 text

data class CustomerList( val customers: List ) : Collection { {…} }

Slide 24

Slide 24 text

Class 'CustomerList' is not abstract and does not implement abstract member

Slide 25

Slide 25 text

public interface Collection : Iterable { public val size: Int public fun isEmpty(): Boolean public fun contains(element: E): Boolean public fun containsAll(elements: Collection): Boolean }

Slide 26

Slide 26 text

data class CustomerList( val customers: List ) : Collection { {…} }

Slide 27

Slide 27 text

data class CustomerList( val customers: List ) : Collection by customers { {…} }

Slide 28

Slide 28 text

Let’s talk about… State Handling

Slide 29

Slide 29 text

sealed class ViewState { object Started: ViewState() object EditMode: ViewState() object ViewMode: ViewState() } fun verifyState(state: ViewState) { when (state) { is ViewState.Started -> println("Started") is ViewState.EditMode -> println("EditMode") is ViewState.ViewMode -> println("ViewMode") } }

Slide 30

Slide 30 text

sealed class ViewState { object Started: ViewState() object EditMode: ViewState() object ViewMode: ViewState() class Error(val message: String = "Unknown error"): ViewState() } fun verifyState(state: ViewState) { when (state) { is ViewState.Started -> println("Started") is ViewState.EditMode -> println("EditMode") is ViewState.ViewMode -> println("ViewMode") } }

Slide 31

Slide 31 text

sealed class ViewState { object Started: ViewState() object EditMode: ViewState() object ViewMode: ViewState() class Error(val message: String = "Unknown error"): ViewState() } fun verifyState(state: ViewState) { when (state) { is ViewState.Started -> println("Started") is ViewState.EditMode -> println("EditMode") is ViewState.ViewMode -> println("ViewMode") } } when expressions guarantee that their branches exhaustively check the possible subclasses of a sealed class.

Slide 32

Slide 32 text

'when' expression on sealed classes is recommended to be exhaustive, add 'Error' branch or 'else' branch instead

Slide 33

Slide 33 text

sealed class ViewState { object Started: ViewState() object EditMode: ViewState() object ViewMode: ViewState() class Error(val message: String = "Unknown error"): ViewState() } fun verifyState(state: ViewState) { when (state) { is ViewState.Started -> println("Started") is ViewState.EditMode -> println("EditMode") is ViewState.ViewMode -> println(“ViewMode") is ViewState.Error -> println(state.message) } }

Slide 34

Slide 34 text

Let’s talk about… Contracts

Slide 35

Slide 35 text

fun requireNotNull(any: Any?) { if (any == null) throw IllegalArgumentException() }

Slide 36

Slide 36 text

fun requireNotNull(any: Any?) { if (any == null) throw IllegalArgumentException() } fun foo(s: String?) { requireNotNull(s) s.length }

Slide 37

Slide 37 text

Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type String?

Slide 38

Slide 38 text

fun requireNotNull(any: Any?) { contract { returns() implies (any != null) } if (any == null) throw IllegalArgumentException() } fun foo(s: String?) { requireNotNull(s) s.length }

Slide 39

Slide 39 text

Questions?