Travelling across Asia - Our journey from Java to Kotlin

Travelling across Asia - Our journey from Java to Kotlin

Kotlin has established itself in the Android development community since v1.0 last year, and with official support announced at I/O this year, it’s an exciting time to get started with this language in your work.

This talk will take you through Deliveroo’s journey from a full Java codebase to using Kotlin across the project. Learn how to get your colleagues involved and convert them to Kotlin supporters. You will also learn how they got started, the problems they ran into and how Kotlin can improve your codebase, your app and your sanity.

A3fcd5fb62ede9161d6327592424dcb4?s=128

Maria Neumayer

October 27, 2017
Tweet

Transcript

  1. TRAVELLING ACROSS ASIA OUR JOURNEY FROM JAVA TO KOTLIN Amal

    Kakaiya @K4KYA Maria Neumayer @marianeum
  2. None
  3. DISCLAIMER: COULD TAKE MORE THAN 20 HOURS

  4. None
  5. Java Kotlin AutoValue/Lombok Data classes Streams support Standard lib functions

    Retrolambda Built in lambda support Butterknife Kotterknife/delegate properties
  6. ADOPTING A NEW LANGUAGE IS A HUGE STEP

  7. TESTS ARE AN EASY WAY TO GET STARTED

  8. TESTS ARE AN EASY WAY TO GET STARTED BUT NOT

    VERY EXCITING
  9. HOW MUCH COULD WE IMPROVE THE MAIN APP?

  10. None
  11. KOTLIN HOUR - GET FAMILIAR WITH THE LANGUAGE

  12. YOU CAN’T START USING A LANGUAGE WITHOUT EVERYBODY KNOWING IT

  13. DO WE REALLY WANT TO ADD ANOTHER DEPENDENCY?

  14. None
  15. None
  16. FIND YOUR OWN PACE

  17. None
  18. IT WASN’T A SMOOTH RIDE

  19. LEARN FROM EACH OTHER

  20. WE REVIEW CODE EVERY DAY

  21. None
  22. ANDROID STUDIO IS YOUR FRIEND

  23. private fun mapToIds(items: List<Item>): List<String> { val ids = mutableListOf<String>()

    for (item in items) { ids.add(item.id) } return ids }
  24. private fun mapToIds(items: List<Item>): List<String> { val ids = items.map

    { it.id } return ids }
  25. private fun mapToIds(items: List<Item>): List<String> { return items.map { it.id

    } }
  26. private fun mapToIds(items: List<Item>): List<String> = items.map { it.id }

  27. WHAT’S THIS CODE DOING?

  28. private final mapToId(Ljava/util/List;)Ljava/ util/List; L0 LINENUMBER 2 L0 ALOAD 1

    CHECKCAST java/lang/Iterable ASTORE 2 ———————— 75 more lines ————————
  29. private final List mapToId(List items) { Iterable $receiver$iv = (Iterable)items;

    Collection destination$iv$iv = (Collection)(new ArrayList(CollectionsKt.collectionSizeOrDefault($receiver $iv, 10))); Iterator var5 = $receiver$iv.iterator(); while(var5.hasNext()) { Object item$iv$iv = var5.next(); Item it = (Item)item$iv$iv; String var12 = it.id; destination$iv$iv.add(var12); } return (List)destination$iv$iv; }
  30. GETTING STARTED WITH TESTS

  31. MOCKS Intent expectedIntent = mock(Intent.class);

  32. MOCKS val expectedIntent = mock(Intent::java.class)

  33. MOCKS val expectedIntent = mock<Intent>()

  34. MOCKS OR val expectedIntent = mock<Intent>() val expectedIntent: Intent =

    mock()
  35. MOCKS @Mock RouteService routeService; MockitoAnnotations.initMocks(this);

  36. MOCKS @Mock lateinit var routeService: RouteService MockitoAnnotations.initMocks(this)

  37. SIMULATING when(preferences.hasSession()).thenReturn(loggedIn);

  38. SIMULATING `when`(preferences.hasSession()).thenReturn(loggedIn)

  39. SIMULATING whenever(preferences.hasSession()).thenReturn(loggedIn)

  40. VERIFY WITH CAPTORS verify(screen).updateScreen(captor.capture()); ScreenUpdate update = captor.getValue();

  41. VERIFY WITH CAPTORS verify(screen).updateScreen(capture(captor)) val update = captor.value

  42. VERIFY WITH CAPTORS @Captor lateinit var captor: KArgumentCaptor<ScreenUpdate>

  43. VERIFY WITH CAPTORS @Captor lateinit var captor: KArgumentCaptor<ScreenUpdate> verify(screen).updateScreen(captor.capture()) val

    update = captor.lastValue
  44. VERIFY WITH CAPTORS TOTALLY SHOULD HAVE BEEN ARGUMENTKAPTOR… JUS’ SAYIN’

    @Captor lateinit var captor: KArgumentCaptor<ScreenUpdate> verify(screen).updateScreen(captor.capture()) val update = captor.lastValue
  45. MOCKS AND NULLABLE /** Matches any object, excluding nulls. */

    inline fun <reified T : Any> any() = Mockito.any(T::class.java) ?: createInstance<T>() /** Matches anything, including nulls. */ inline fun <reified T : Any> anyOrNull(): T = Mockito.any<T>() ?: createInstance<T>()
  46. CONVERTING CODE

  47. CONVERTING CODE ⌘⌥⇧K Ctrl+Alt+⇧+K

  48. CONVERTING CODE

  49. CONVERTING CODE

  50. CONVERSION CREEP

  51. NULLPOINTEREXCEPTION

  52. KOTLINNULLPOINTEREXCEPTION

  53. CONSIDER NULLABILITY WHEN IMPLEMENTING A JAVA INTERFACE private val passwordActionListener

    = TextView.OnEditorActionListener { _: TextView, _: Int, _: KeyEvent -> login(password()) }
  54. CONSIDER NULLABILITY WHEN IMPLEMENTING A JAVA INTERFACE private val passwordActionListener

    = TextView.OnEditorActionListener { _: TextView, _: Int, _: KeyEvent -> login(password()) }
  55. CONSIDER NULLABILITY WHEN IMPLEMENTING A JAVA INTERFACE private val passwordActionListener

    = TextView.OnEditorActionListener { _: TextView, _: Int, _: KeyEvent -> login(password()) }
  56. CONSIDER NULLABILITY WHEN IMPLEMENTING A JAVA INTERFACE ! ! !

    ! ! ! ! ! private val passwordActionListener = TextView.OnEditorActionListener { _: TextView, _: Int, _: KeyEvent -> login(password()) }
  57. CONSIDER NULLABILITY WHEN IMPLEMENTING A JAVA INTERFACE private val passwordActionListener

    = TextView.OnEditorActionListener { _: TextView, _: Int, _: KeyEvent? -> login(password()) } "
  58. CONVERTING CODE class VerifyActivity: BaseActivity<VerifyPresenter>, VerifyScreen { override val message:

    String = getString(R.string.verify_error)
  59. CONVERTING CODE class VerifyActivity: BaseActivity<VerifyPresenter>, VerifyScreen { override val message:

    String get() = getString(R.string.verify_error)
  60. USE VERSION CONTROL EFFECTIVELY AND YOUR TEAM WILL ❤ YOU

  61. $ VERSION HISTORY

  62. VERSION CONTROL CONVERSION AS ONE COMMIT

  63. VERSION CONTROL MERGE CONVERSIONS QUICKLY

  64. VERSION CONTROL SHARE WHAT YOU LEARNED

  65. SHARE WHAT YOU LEARNED VERSION CONTROL

  66. SHARE WHAT YOU LEARNED VERSION CONTROL

  67. VERSION CONTROL LEAVE IN RETURN TYPES WHEN IT MAKES SENSE

  68. VERSION CONTROL private fun showPrompt(confirmed: Boolean) = zip(flipper().confirmDrinkingAgeEnabled(), just(confirmed) {

    enabled, confirmed -> enabled && (!confirmed) }
  69. VERSION CONTROL private fun showPrompt(confirmed: Boolean): Observable<Boolean> = zip(flipper().confirmDrinkingAgeEnabled(), just(confirmed)

    { enabled, confirmed -> enabled && (!confirmed) }
  70. ANDROIDANNOTATIONS AUTOVALUE BUTTERKNIFE LOMBOK DAGGER CUSTOM ANNOTATION PROCESSOR

  71. KAPT KAY - AY - PEE - TEE

  72. KAPT VS LOMBOK A TRUE STORY

  73. IMMUTABILITY? private Item addNameToItem(Item item, Name other) { ItemBuilder builder

    = item.toBuilder() builder.name(other.getName()); return builder.build() }
  74. IMMUTABILITY? private Item addNameToItem(Item item, Name other) { ItemBuilder builder

    = item.toBuilder() builder.name(other.getName()); return builder.build() } private fun addNameToItem(item: Item, other: Name): Item { return item.copy(name = other.name) }
  75. WHAT WOULD WE CHANGE?

  76. DON’T JUST START WITH TESTS

  77. CONVERT UTIL CLASSES EARLY

  78. @file:JvmName("ViewUtil") @JvmName("showView") fun View.show(visible: Boolean) { visibility = if (visible)

    VISIBLE else GONE }
  79. DO WHAT WORKS FOR YOUR TEAM

  80. None
  81. None
  82. THANK YOU WE’RE HIRING Amal Kakaiya @K4KYA Maria Neumayer @marianeum

  83. LINKS ▸ Christina Lee & Jake Wharton - Kotlin is

    here, Life is great and everything will be OK: https://youtu.be/fPzxfeDJDzY ▸ Mockito Kotlin: https://github.com/nhaarman/mockito-kotlin ▸ Kotlin Koans: https://kotlinlang.org/docs/tutorials/koans.html