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

Poniendo Kotlin en producción a palos

129b5ff44f5d43b6e7cf6703211abe7e?s=47 Tuenti
November 25, 2017

Poniendo Kotlin en producción a palos

129b5ff44f5d43b6e7cf6703211abe7e?s=128

Tuenti

November 25, 2017
Tweet

Transcript

  1. Poniendo by @andres_viedma en producción A palos MAD · NOV

    24-25 · 2017
  2. Andrés Viedma Andrés Viedma @andres_viedma @andres_viedma

  3. 01 KOTLIN

  4. None
  5. Null safety fun printStringLength(maybeString: String?) { // maybeString.length would not

    compile if (maybeString != null) { // maybeString cannot be null now, it's a String println(maybeString.length) } else { println("<empty>") } } ”My billion dollars mistake” Tony Hoare
  6. fun printStringLength1(maybeString: String?) { maybeString?.let { s -> println(s) }

    } fun printStringLengthOrEmpty(maybeString: String?) { println(maybeString?.length ?: "<empty>") } Null safety
  7. A small immutable Kotlin class data class TokenInfo( val tokenType:

    String = “auth”, val identity: String val expiration: Int? = null )
  8. Constructor with Properties class TokenInfo( val tokenType: String, val identity:

    String (…) ) public final class TokenInfo { private final String tokenType; private final String identity; (…) public TokenInfo( String tokenType, String identity, (…)) { this.tokenType = tokenType; this.identity = identity; (…) } public final String getTokenType() { return tokenType; } public final String getIdentity() { return identity; } }
  9. Getters and Setters class TokenInfo( val tokenType: String, val identity:

    String (…) ) public final class TokenInfo { private final String tokenType; private final String identity; (…) public TokenInfo( String tokenType, String identity, (…)) { this.tokenType = tokenType; this.identity = identity; (…) } public final String getTokenType() { return tokenType; } public final String getIdentity() { return identity; } }
  10. Named arguments and optional values class TokenInfo( val tokenType: String

    = "auth", val identity: String, val expiration: Int? = null ) val token = TokenInfo(identity = "xxx") Immutable classes with optional fields? Constructors with lots of parameters Builder object
  11. Data classes data class TokenInfo( val tokenType: String, val identity:

    String (…) ) public final class TokenInfo { (…) public String toString() { (…) } public int hashCode() { (…) } public boolean equals(Object var1) { (…) } public final TokenInfoId copy(String tokenType, String identity) { (…) } public final String component1() { (…) } public final String component2() { (…) } } Immutability made easier
  12. Collections improvements List<Person> persons = Arrays.asList( new Person("Sansa", "Stark"), new

    Person("Jon", "Snow")); List<String> personNames = persons.stream() .map(p -> p.getName() + " " + p.getSurname()) .collect(Collectors.toList()); val persons = listOf( Person("Sansa", "Stark"), Person("Jon", "Snow")) val personNames = persons .map { p -> "${p.name} ${p.surname}" } Extension functions
  13. Collections improvements List<Integer> result = list.stream() .flatMap(o -> o.isPresent() ?

    Stream.of(o.get()) : Stream.empty()) .collect(Collectors.toList()); val result = list.filter { it != null } List<Integer> result = list.stream() .flatMap(o → o.map(Stream::of) .orElseGet(Stream::empty)) .collect(Collectors.toList()); List<Integer> result = list.stream() .flatMap(Optional::stream) .collect(Collectors.toList());
  14. String Interpolation List<Person> persons = Arrays.asList( new Person("Sansa", "Stark"), new

    Person("Jon", "Snow")); List<String> personNames = persons.stream() .map(p -> p.getName() + " " + p.getSurname()) .collect(Collectors.toList()); val persons = listOf( Person("Sansa", "Stark"), Person("Jon", "Snow")) val personNames = persons .map { p -> "${p.name} ${p.surname}" }
  15. Type Inference val persons = listOf( Person("Sansa", "Stark"), Person("Jon", "Snow"))

    val personNames = persons .map { p -> "${p.name} ${p.surname}" } List<Person> persons = Arrays.asList( new Person("Sansa", "Stark"), new Person("Jon", "Snow")); List<String> personNames = persons.stream() .map(p -> p.getName() + " " + p.getSurname()) .collect(Collectors.toList());
  16. Gotcha! Now the idea is trapped inside your head

  17. Gotcha! Now the idea is trapped inside your head

  18. Gotcha! Now the idea is trapped inside your head

  19. 02 LET'S DO IT!

  20. Tell the team! The conformist

  21. Tell the team! The conformist The idealist

  22. Tell the team! The conformist The idealist The responsible

  23. Tell the team! The conformist The idealist The responsible AGGG

    ROOO RAGG AGGG ROOO RAGG ROOOOOOOGHH! ROOOOOOOGHH!
  24. What about the rest of the company?

  25. Option 1...

  26. Option 2: Talk to them

  27. • Can affect development time • Misunderstandings can increase bug

    rate • Service responsibility is not fixed Not just YOUR team Learning cost
  28. • Learning curve very smooth • On doubt, use Java

    style and methods • Not a real paradigm change • Same libraries and concepts Learning cost ® BUT...
  29. • Good documentation • Short library • Is there a

    general interest in Kotlin in the company? Kotlin community Android devs pushing for a change Learning cost ® BUT... (2)
  30. • It's production! • New technology, may have bugs •

    Adds code “behind the courtains” • Any weird behaviour affecting memory, garbage collection... Can affect Performance
  31. • Same Java VM • You can see compiled bytecode

    • Decompile problematic code to Java and tune it • Start a component in Java and then convert it to Kotlin Can affect Performance ® BUT...
  32. • Extension functions are just a trick, no overhead •

    Null checks are a small runtime overhead • Platform and base libraries are the sane • Kotlin library overhead not important for backend Can affect Performance ® BUT... (2)
  33. • Increased build time • Find equivalent tools • Adaptation

    to those tools Tooling problems
  34. • Same IDE: IntelliJ, Eclipse... • Same build tools: Maven,

    Gradle... • In a microservices architecture build time not so critical Seconds? Tooling problems ® BUT...
  35. • What if Kotlin stops being “cool”? • What if

    nobody uses it anymore? • What if it just dissapears? Supported / created by Jetbrains Long-term vision
  36. Long-term vision ® BUT...

  37. 03 10 MONTHS LATER...

  38. • Development time basically the same • Code Reviews more

    interesting! • Our Java platform was 100% compatible Learning cost?
  39. • Rest of the company? 4 teams doing services in

    Kotlin Kotlin now official in the company for Android Learning cost?
  40. final vs. open Some Java libraries rely on dinamically creating

    subclasses • Interceptors and other injection “black magic” Spring, Guice… • Mocks: Mockito, Spock
  41. Compiler plugins • All-open: Make classes open Shortcut: Spring •

    No-args: Create a no-args constructor Shortcut: JPA Beware!: only by annotations
  42. Compiler plugins ® All-open not enough • @Transactional problem (if

    no class annotation) Explicit open class and methods • Mocks? Mockito 2.1.0 “inline mocks”: “incubating” Kotlin-runner library: explicit packages
  43. Compiler plugins ® No-args not enough • Object Mapper libraries

    Explicit no-args constructor • Spock tests Named parameters don’t work from Java / Groovy
  44. const val ONE = 1 // MyObject(1) NO OBJECTS ALLOWED

    // Translated to: public static final class Constants { companion object { const val TWO = 2 // MyObject(2) NO OBJECTS ALLOWED // Translated to: inlined val THREE = MyObject(3) // Translated to private static // + Companion class with getter @JvmField val FOUR = MyObject(4) // Translated to public static final } } Constants: too many options? https://blog.egorand.me/where-do-i-put-my-constants-in-kotlin/
  45. val description: String (type after identifier)

  46. val description: String (type after identifier)

  47. Can affect Performance?

  48. • Eclipse with Kotlin and Groovy tests just don’t work

    • Eclipse incremental compilation a bit slow • Some crashes when updating IntelliJ plugin • Incremental build disabled by default in some versions Maven+Gradle • Checkstyle, Findbugs… Tooling problems?
  49. • Eclipse with Kotlin and Groovy tests just don’t work

    • Eclipse incremental compilation a bit slow • Some crashes when updating IntelliJ plugin • Incremental build disabled by default in some versions Maven+Gradle • Checkstyle, Findbugs… Tooling problems?
  50. 04 Beyond the basics

  51. Functional features fun processPersonName(person: Person?, processor: (String) -> Boolean) =

    processor( when(person) { null -> "null" is AnonymousPerson -> "anonymous" else -> when { person.isBoss -> "a boss" else -> "the simple ${person.name}" } } )
  52. • Not 100% functional • Higher kind types • Typeclasses

    • Proposal (KEEP) in discussion to add them, by @raulraja • Kategory library - http://kategory.io/ Functional paradigm?
  53. Black magic companion { [constants: USER_ID, PRODUCTS, OK_RESULT...) } val

    storeCatalogStub = Stub<StoreCatalog> { getProductsForUserId(USER_ID) <= PRODUCTS } val storeMock = Mock<ProductStore>() val purchaseHistoryMock: PurchaseHistory = Mock() fun `Purchase correct product available in the store`() { given("A valid user") { userService.isValidUser(USER_ID) <= true } `when`("The user tries to do the purchase") { purchaseOperation.perform(USER_ID, PRODUCT_ID) } then("Product is purchased") { 1 * storeMock.purchaseProduct(USER_ID, PRODUCT_ID, null.not()) <= OK_RESULT } and("Operation is logged") { (1..any) * purchaseHistoryMock.logProductPurchased(USER_ID, PRODUCT_ID, any()) } and("No more interactions") { 0 * any } }
  54. Black magic companion { [constants: USER_ID, PRODUCTS, OK_RESULT...) } val

    storeCatalogStub = Stub<StoreCatalog> { getProductsForUserId(USER_ID) <= PRODUCTS } val storeMock = Mock<ProductStore>() val purchaseHistoryMock: PurchaseHistory = Mock() fun `Purchase correct product available in the store`() { given("A valid user") { userService.isValidUser(USER_ID) <= true } `when`("The user tries to do the purchase") { purchaseOperation.perform(USER_ID, PRODUCT_ID) } then("Product is purchased") { 1 * storeMock.purchaseProduct(USER_ID, PRODUCT_ID, null.not()) <= OK_RESULT } and("Operation is logged") { (1..any) * purchaseHistoryMock.logProductPurchased(USER_ID, PRODUCT_ID, any()) } and("No more interactions") { 0 * any } } Lambda param after parenthesis Code generation (compiler plugin)
  55. Black magic companion { [constants: USER_ID, PRODUCTS, OK_RESULT...) } val

    storeCatalogStub = Stub<StoreCatalog> { getProductsForUserId(USER_ID) <= PRODUCTS } val storeMock = Mock<ProductStore>() val purchaseHistoryMock: PurchaseHistory = Mock() fun `Purchase correct product available in the store`() { given("A valid user") { userService.isValidUser(USER_ID) <= true } `when`("The user tries to do the purchase") { purchaseOperation.perform(USER_ID, PRODUCT_ID) } then("Product is purchased") { 1 * storeMock.purchaseProduct(USER_ID, PRODUCT_ID, null.not()) <= OK_RESULT } and("Operation is logged") { (1..any) * purchaseHistoryMock.logProductPurchased(USER_ID, PRODUCT_ID, any()) } and("No more interactions") { 0 * any } } Operator overloading Reified generics Extension functions https://github.com/Koxalen
  56. More... • Coroutines • Type aliases • Sealed classes •

    Delegated properties • Inline functions
  57. Android • Anko library • Consider performance and limits 7k

    methods (65k methods limit): 10% 380 KB Compilation slower
  58. Multi-platform • Javascript Kotlin wrapper for ReactJS • Native Kotlin

    plugin for CLion Kotlin/Native iOS support Not only the JVM! KotlinConf app fully made with Kotlin
  59. SO WHAT??? 05

  60. Yay or Nay? • Controlled risk, but… worth it? •

    What’s the benefit? Mostly syntatic sugar Productivity really improved???
  61. Yay or Nay? • Controlled risk, but… worth it? •

    What’s the benefit? Mostly syntatic sugar Productivity really improved??? How about thinking about PEOPLE instead of PRODUCTS?
  62. It’s all about LEARNING and MOTIVATION

  63. None
  64. Questions? Andrés Viedma · @andres_viedma