Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Kotlin: MAX PAYNE (Voxxed Days Minsk, May 2018)

Kotlin: MAX PAYNE (Voxxed Days Minsk, May 2018)

Kotlin gives us a lot of neat features and just general developer satisfaction, but little is known about its hidden costs and pain it causes. This talk is a almost a 3 year combination of small (and no so small) issues we encountered when developing a full-Kotlin application started from the scratch. Bugs, features, performance, testing — it’s all there with our answers, conclusions and advises.

Presented at Voxxed Days Minsk conference on May 26, 2018.

Artur Dryomov

May 26, 2018
Tweet

More Decks by Artur Dryomov

Other Decks in Programming

Transcript

  1. Juno Rider 3 years 100 % Kotlin Kotlin EAP in

    production 1.1-EAP — 6 months 1.2-EAP — 3 months 99.9 % crash‑free 2 week sprints 4 developers, 1 QA
  2. Juno Rider cloc main/kotlin — 56 K cloc test/kotlin —

    49 K cloc androidTest/kotlin — 17 K
  3. Checkstyle Checkstyle works only with AST as we depend on

    ANTLR and Java grammar. https://github.com/checkstyle/checkstyle/issues/4369
  4. Kotlin Tools IntelliJ IDEA detekt + ktlint android/lint kotlinc --force

    tasks.withType<KotlinCompile> { kotlinOptions { allWarningsAsErrors = true } }
  5. Destructuring val (first, second) = Pair(1, 2) val (first, second,

    third) = Triple(1, 2, 3) listOf(1 to "one", 2 to "two").map { (number, text) -> println("number is $number, text is $text") }
  6. Destructuring data class Person(val firstName: String, val lastName: String) val

    (firstName, lastName) = Person("f", "l") data class Person(val lastName: String, val firstName: String) val (firstName, lastName) = Person("f", "l") // It works!
  7. Destructuring data class Person(val firstName: String, val lastName: String) {

    operator fun component1() = firstName operator fun component2() = lastName }
  8. null safety? Observable.just(null) public static <T> Observable<T> just(T item) {

    ObjectHelper.requireNonNull(item, "The item is null"); ...
  9. RxJava 2 val o: Observable<Int?> = Observable.just(null) // Runtime: NullPointerException

    public static <T> Observable<T> just(T item) { ObjectHelper.requireNonNull(item, "The item is null"); ...
  10. Koptional https://github.com/gojuno/koptional val some = Some(value) val none = None

    val optional = nullableValue.toOptional() val nullable = o.toNullable()
  11. Mockito interface Api { fun call(id: String) } class Service(private

    val api: Api) { fun call() = api.call(generateId()) } @Test fun test() { val api = Mockito.mock<Api>() Service(api).call() verify(api).call(Mockito.any()) } // Runtime: NullPointerException
  12. Mockito fun <T> anything(): T = Mockito.any<T>() @Test fun test()

    { val api = Mockito.mock<Api>() Service(api).call() verify(api).call(anything()) }
  13. Mockito fun <T> eq(value: T): T = Mockito.eq<T>(obj) fun <T>

    anything(): T = Mockito.any<T>() fun <T> whenever(call: T) = Mockito.`when`(call)
  14. Gson data class Model { @SerializedName("model_field") val field: String }

    val model = Gson().fromJson("{}", Model::javaClass) // Runtime: OK model.field.toString() // Runtime: NullPointerException
  15. Gson data class Model { @SerializedName("model_field") val field: String }

    : Validatable { override fun validate() { if (field == null) throw ParseException() } }
  16. const companion object { private val NUMBER = 42 }

    public static final class Companion { private final int NUMBER = 42; private final int getNUMBER() { return NUMBER; } }
  17. const companion object { private const val NUMBER = 42

    } public static final class Companion { private static final int NUMBER = 42; }
  18. Kotlin versions Gradle 4.2 — 1.1.4‑3 Project — 1.2.0‑beta‑31 Runtime

    files in the classpath should have the same version. These files were found in the classpath: .../dists/.../kotlin-stdlib-1.1.4-3.jar (version 1.1) .../caches/.../kotlin-stdlib-1.2.0-beta-31.jar (version 1.2)
  19. JUnit class SystemTest { lateinit var system: System @BeforeEach fun

    create() { system = System() } @BeforeEach fun start() { system.boot() } @Test fun `has boot status`() { assertThat(system.status()).isEqualTo(BOOTED) } @Test fun `has positive uptime`() { assertThat(system.uptime()).isNotZero() } }
  20. Spek class SystemSpec : Spek({ val system by memoized {

    System() } context("boot") { beforeEachTest { system.boot() } it("has boot status") { assertThat(system.status()).isEqualTo(BOOTED) } it("has positive uptime") { assertThat(system.uptime()).isNotZero() } } })
  21. memoized before and after class JustSpec : Spek({ val system

    by memoized { System() } beforeEachTest { println("before $system") // system_before } afterEachTest { println("after $system") // system_after } }) // system_before != system_after
  22. ... Kotlin is a thin layer on top of Java,

    and so it perpetuates through a lot of the Javaisms in its model. ... Chris Lattner (Swift, LLVM, Clang)
  23. Java — Executive Committee Oracle, Red Hat, Intel, IBM, Eclipse,

    Twitter, JetBrains... 24 members Kotlin — Language Committee JetBrains, Google 3 members