Pro Yearly is on sale from $80 to $50! »

Write Less Code with Kotlin and Spring Boot

Write Less Code with Kotlin and Spring Boot

As software developers, we aren't getting paid to write code; we're getting paid to deliver business value. Think of the last time you opened a codebase you weren't familiar with and had to wade through all of the boilerplate just to understand the core business logic or hunt down a critical bug. Less code means easier comprehension, quicker development, fewer bugs, and easier testing. Spring Boot is already very good at allowing us to deliver business quickly—why not take it to the next level with Kotlin? Kotlin has been described as a re-imagined Java. It's as if you took Java, fixed all of the things you didn't like about it, modernized the API, and made the result work seamlessly with your existing Java codebase. Combined with Spring Boot, Kotlin is a force multiplier for productivity and understanding.

This talk is aimed at Java and Spring Boot developers who might have heard of Kotlin but haven't tried it. You'll learn the basics of Kotlin and the features that make it compelling.

2777430c1f9869e411ab5d8b17d8ba2a?s=128

Todd Ginsberg

October 08, 2019
Tweet

Transcript

  1. @ToddGinsberg Write Less Code with Kotlin and Spring Boot October

    7, 2019 Austin Convention Center Todd Ginsberg Principal Software Developer, Netspend
  2. @ToddGinsberg Kotlin and Spring Boot in 30 Minutes?!

  3. @ToddGinsberg Kotlin and Spring Boot in 30 Minutes?! No, that’s

    crazy!
  4. @ToddGinsberg Kotlin and Spring Boot in 30 Minutes?! No, that’s

    crazy! But stick around after!
  5. @ToddGinsberg Agenda - What Is Kotlin?

  6. @ToddGinsberg Agenda - What Is Kotlin? - Why Kotlin with

    Spring Boot?
  7. @ToddGinsberg Agenda - What Is Kotlin? - Why Kotlin with

    Spring Boot? - Syntax & Features
  8. @ToddGinsberg Agenda - What Is Kotlin? - Why Kotlin with

    Spring Boot? - Syntax & Features - Summary
  9. @ToddGinsberg Agenda - What Is Kotlin? - Why Kotlin with

    Spring Boot? - Syntax & Features - Summary - Questions?
  10. @ToddGinsberg Who is this Guy? Todd Ginsberg

  11. @ToddGinsberg Who is this Guy? Todd Ginsberg Just moved to

    Dallas from Chicago
  12. @ToddGinsberg Who is this Guy? Todd Ginsberg Just moved to

    Dallas from Chicago Principal Developer at Netspend - A payments company here in Austin! - We love Kotlin and Java!
  13. @ToddGinsberg What Is Kotlin?

  14. @ToddGinsberg What Is Kotlin? Statically typed language, developed by JetBrains

  15. @ToddGinsberg What Is Kotlin? Statically typed language, developed by JetBrains

    Released under Apache 2.0 license
  16. @ToddGinsberg What Is Kotlin? Statically typed language, developed by JetBrains

    Released under Apache 2.0 license Designed as a general purpose language
  17. @ToddGinsberg What Is Kotlin? Statically typed language, developed by JetBrains

    Released under Apache 2.0 license Designed as a general purpose language • Targets JVM 6 or 8 bytecode
  18. @ToddGinsberg What Is Kotlin? Statically typed language, developed by JetBrains

    Released under Apache 2.0 license Designed as a general purpose language • Targets JVM 6 or 8 bytecode • Targets ECMAScript 5.1
  19. @ToddGinsberg What Is Kotlin? Statically typed language, developed by JetBrains

    Released under Apache 2.0 license Designed as a general purpose language • Targets JVM 6 or 8 bytecode • Targets ECMAScript 5.1 • Targets other native platforms thanks to LLVM
  20. @ToddGinsberg Major Features 100% Interoperable with Java

  21. @ToddGinsberg Major Features 100% Interoperable with Java Designed to avoid

    entire classes of defects
  22. @ToddGinsberg Major Features 100% Interoperable with Java Designed to avoid

    entire classes of defects Lots of small improvements that add up
  23. @ToddGinsberg Major Features 100% Interoperable with Java Designed to avoid

    entire classes of defects Lots of small improvements that add up Far less code to accomplish the same task in Java
  24. @ToddGinsberg Major Features Null-safe

  25. @ToddGinsberg Major Features Null-safe 189,000+ issues on GitHub!

  26. @ToddGinsberg Major Features Null-safe 189,000+ issues on GitHub! 14,548 duplicates

    on Stack Overflow!
  27. @ToddGinsberg Major Features Pragmatic Improvements No shame in copying language

    features that make developers more productive
  28. @ToddGinsberg Major Features Positive Community

  29. @ToddGinsberg Major Features Positive Community Even on Stack Overflow!

  30. @ToddGinsberg Major Features Positive Community Even on Stack Overflow! RTFM

  31. @ToddGinsberg Why Kotlin with Spring Boot?

  32. @ToddGinsberg The Hard Work is Already Done! - Kotlin Support

    since Spring Framework 5.0
  33. @ToddGinsberg The Hard Work is Already Done! - Kotlin Support

    since Spring Framework 5.0 - Nullability support between Java and Kotlin
  34. @ToddGinsberg The Hard Work is Already Done! - Kotlin Support

    since Spring Framework 5.0 - Nullability support between Java and Kotlin - Excellent documentation
  35. @ToddGinsberg The Hard Work is Already Done! - Kotlin Support

    since Spring Framework 5.0 - Nullability support between Java and Kotlin - Excellent documentation - Thorough examples
  36. @ToddGinsberg The Hard Work is Already Done! - Kotlin Support

    since Spring Framework 5.0 - Nullability support between Java and Kotlin - Excellent documentation - Thorough examples - Even better support being added for Spring Boot 2.2
  37. @ToddGinsberg Similar Philosophies “The goal of library design is to

    give application developers ready-to-use tools that cover their most frequent use-cases and solve the most popular problems. If something is needed all the time by any kind of application, it should be simple and straightforward to code. The correct code shall be the easiest one to write, while advanced, rarely needed corner-cases can and should take longer.”
  38. @ToddGinsberg Similar Philosophies “The goal of library design is to

    give application developers ready-to-use tools that cover their most frequent use-cases and solve the most popular problems. If something is needed all the time by any kind of application, it should be simple and straightforward to code. The correct code shall be the easiest one to write, while advanced, rarely needed corner-cases can and should take longer.” -- Roman Elizarov (JetBrains)
  39. @ToddGinsberg Less Code == More Room For Business Value -

    Less code means less cognitive load
  40. @ToddGinsberg Less Code == More Room For Business Value -

    Less code means less cognitive load - The most common case is the default
  41. @ToddGinsberg Less Code == More Room For Business Value -

    Less code means less cognitive load - The most common case is the default - Fewer places for bugs to hide
  42. @ToddGinsberg Less Code == More Room For Business Value -

    Less code means less cognitive load - The most common case is the default - Fewer places for bugs to hide - Work that you once had to do is a top level concern of the language / framework
  43. @ToddGinsberg Less Code == More Room For Business Value -

    Less code means less cognitive load - The most common case is the default - Fewer places for bugs to hide - Work that you once had to do is a top level concern of the language / framework - These effects stack
  44. @ToddGinsberg Syntax

  45. @ToddGinsberg Variables and Values var place: String = "Austin"

  46. @ToddGinsberg Variables and Values var place: String = "Austin" place

    = "Texas" // OK!
  47. @ToddGinsberg Variables and Values var place: String = "Austin" place

    = "Texas" // OK! val name: String = "Todd"
  48. @ToddGinsberg Variables and Values var place: String = "Austin" place

    = "Texas" // OK! val name: String = "Todd" name = "Emma" // Compile Error!
  49. @ToddGinsberg Type Inference val d: Int = 2 val text:

    String = "Todd has $d doughnuts"
  50. @ToddGinsberg Type Inference val d: Int = 2 val text:

    String = "Todd has $d doughnuts"
  51. @ToddGinsberg Type Inference val d = 2 val text =

    "Todd has $d doughnuts"
  52. @ToddGinsberg Equality val name1 = "EXAMPLE" val name2 = "example"

  53. @ToddGinsberg Equality val name1 = "EXAMPLE" val name2 = "example"

    // Structural Equality name1 == name2.toUpperCase() // True!
  54. @ToddGinsberg Equality val name1 = "EXAMPLE" val name2 = "example"

    // Structural Equality name1 == name2.toUpperCase() // True! // Referential Equality name1 === name2 // False!
  55. @ToddGinsberg Raw Strings val json = "{\n\"name\": \"Todd\"\n}"

  56. @ToddGinsberg Raw Strings val json = "{\n\"name\": \"Todd\"\n}" val json

    = """{ "name": "Todd" }"""
  57. @ToddGinsberg Raw Strings val json = "{\n\"name\": \"Todd\"\n}" val json

    = """ { "name": "Todd" } """
  58. @ToddGinsberg Null Safety // Guaranteed to never be null var

    name: String = "Todd"
  59. @ToddGinsberg Null Safety // Guaranteed to never be null var

    name: String = "Todd" // May be null var salary: Int? = null
  60. @ToddGinsberg Null-Safe Traversal var city: String? = "Austin"

  61. @ToddGinsberg Null-Safe Traversal var city: String? = "Austin" // Not

    allowed, might be null! city.toUpperCase()
  62. @ToddGinsberg Null-Safe Traversal var city: String? = "Austin" // Not

    allowed, might be null! city.toUpperCase() // Safe traversal city?.toUpperCase()
  63. @ToddGinsberg Elvis val lowest : Int? = listOf(1, 2, 3).min()

  64. @ToddGinsberg Elvis val lowest : Int? = listOf(1, 2, 3).min()

    val lowest : Int = listOf(1, 2, 3).min() ?: 0
  65. @ToddGinsberg Combine Safe-Traversal and Elvis println( city?.toUpperCase() ?: ”UNKNOWN” )

  66. @ToddGinsberg Manual Override val lowest: Int? = listOf(1, 2, 3).min()

  67. @ToddGinsberg Hey Kotlin, Hold My Beer! val lowest: Int? =

    listOf(1, 2, 3).min() val lowest: Int = listOf(1, 2, 3).min()!!
  68. @ToddGinsberg Hey Kotlin, Hold My Beer! val lowest: Int? =

    listOf(1, 2, 3).min() val lowest: Int = listOf(1, 2, 3).min()!! val lowest: Int = emptyList<Int>().min()!!
  69. @ToddGinsberg Hey Kotlin, Hold My Beer! val lowest: Int? =

    listOf(1, 2, 3).min() val lowest: Int = listOf(1, 2, 3).min()!! val lowest: Int = emptyList<Int>().min()!! // NullPointerException!
  70. @ToddGinsberg Expressions - if val status = if (code ==

    42) { "Success" } else { "Fail" }
  71. @ToddGinsberg Expressions - try/catch val number = try { code.toInt()

    } catch (e: NumberFormatException) { 0 }
  72. @ToddGinsberg Expressions - when val result = when (x) {

    0 -> "x is 0” in 1..10 -> "x is between 1 and 10" in someSet -> "x is in someSet" is SomeType -> "x is an instance of SomeType" parseString(s) -> "the same as parseString" else -> "x doesn't match anything" }
  73. @ToddGinsberg Smart Casting when (x) { is Int -> print(x

    % 2 == 0) is String -> print(x.length + 1) is IntArray -> print(x.sum()) }
  74. @ToddGinsberg Smart Casting when (x) { is Int -> print(x

    % 2 == 0) is String -> print(x.length + 1) is IntArray -> print(x.sum()) }
  75. @ToddGinsberg Smart Casting if(x != null) { println(x.toString()) }

  76. @ToddGinsberg Classes class Entity : SomeInterface { // ... }

  77. @ToddGinsberg Classes - Inheritance open class Entity : SomeInterface {

    // ... } class Customer : Entity() { // ... }
  78. @ToddGinsberg Properties public class Customer { private String name; public

    String getName() { return name; } public void setName(final String name) { this.name = name; } }
  79. @ToddGinsberg Properties class Customer { var name: String? = null

    }
  80. @ToddGinsberg Properties class Customer { var name: String? = null

    } val c = Customer()
  81. @ToddGinsberg Properties class Customer { var name: String? = null

    } val c = Customer() c.name = "Todd"
  82. @ToddGinsberg Properties class Customer { var name: String? = null

    } val c = Customer() c.name = "Todd" println("My name is ${c.name}")
  83. @ToddGinsberg Properties class Customer { var name: String? = null

    }
  84. @ToddGinsberg Properties class Customer { var name: String? = null

    set(value) { field = value?.toUpperCase() } }
  85. @ToddGinsberg Properties class Customer { var name: String? = null

    private set(value) { field = value?.toUpperCase() } }
  86. @ToddGinsberg Properties class Customer { var name: String? = null

    get() { return field?.toUpperCase() } }
  87. @ToddGinsberg Let’s Write a POJO! public class Person { public

    String firstName; public String lastName; }
  88. @ToddGinsberg Let’s Write a POJO! public class Person { private

    String firstName; private String lastName; public String getFirstName() { return firstName; } public void setFirstName(final String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(final String lastName) { this.lastName = lastName; } }
  89. @ToddGinsberg Let’s Write a POJO! public class Person { private

    String firstName; private String lastName; public Person() { } public Person(final String firstName, final String lastName) { this.firstName = firstName; this.lastName = lastName; } public String getFirstName() { return firstName; } public void setFirstName(final String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(final String lastName) { this.lastName = lastName; } }
  90. @ToddGinsberg Let’s Write a POJO! import java.util.Objects; public class Person

    { private String firstName; private String lastName; public Person() { } public Person(final String firstName, final String lastName) { this.firstName = firstName; this.lastName = lastName; } public String getFirstName() { return firstName; } public void setFirstName(final String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(final String lastName) { this.lastName = lastName; } @Override public boolean equals(final Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; final Person person = (Person) o; return Objects.equals(firstName, person.firstName) && Objects.equals(lastName, person.lastName); } @Override public int hashCode() { return Objects.hash(firstName, lastName); } }
  91. @ToddGinsberg Let’s Write a POJO! import java.util.Objects; public class Person

    { private String firstName; private String lastName; public Person() { } public Person(final String firstName, final String lastName) { this.firstName = firstName; this.lastName = lastName; } public String getFirstName() { return firstName; } public void setFirstName(final String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(final String lastName) { this.lastName = lastName; } @Override public boolean equals(final Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; final Person person = (Person) o; return Objects.equals(firstName, person.firstName) && Objects.equals(lastName, person.lastName); } @Override public int hashCode() { return Objects.hash(firstName, lastName); } @Override public String toString() { return "Person{" + "firstName='" + firstName + '\'' + ", lastName='" + lastName + '\'' + '}'; } }
  92. @ToddGinsberg Data Classes to the Rescue! data class Person(val firstName:

    String, val lastName: String)
  93. @ToddGinsberg Data Classes to the Rescue! data class Person(val firstName:

    String, val lastName: String) • Getters (and Setters for vars) as Properties
  94. @ToddGinsberg Data Classes to the Rescue! data class Person(val firstName:

    String, val lastName: String) • Getters (and Setters for vars) as Properties • toString()
  95. @ToddGinsberg Data Classes to the Rescue! data class Person(val firstName:

    String, val lastName: String) • Getters (and Setters for vars) as Properties • toString() • hashCode() and equals()
  96. @ToddGinsberg Data Classes to the Rescue! data class Person(val firstName:

    String, val lastName: String) • Getters (and Setters for vars) as Properties • toString() • hashCode() and equals() • And…
  97. @ToddGinsberg Copying Data Classes val me = Person("Todd", "Ginsberg")

  98. @ToddGinsberg Copying Data Classes val me = Person("Todd", "Ginsberg") val

    emma = me.copy(firstName = "Emma") // Person(”Emma", "Ginsberg")
  99. @ToddGinsberg Data Classes as @ConfigurationProperties @ConfigurationProperties("example.kotlin") data class KotlinExampleProperties( val

    name: String, val description: String = "Defaults Supported!", val myService: MyService ) data class MyService( val apiToken: String, val uri: URI )
  100. @ToddGinsberg Data Classes as @ConfigurationProperties @ConfigurationProperties("example.kotlin") data class KotlinExampleProperties( val

    name: String, val description: String = "Defaults Supported!", val myService: MyService ) data class MyService( val apiToken: String, val uri: URI ) Boot 2.2!
  101. @ToddGinsberg FUNctions! fun generateRandomNumber(): Int { return 4 }

  102. @ToddGinsberg FUNctions! fun generateRandomNumber(): Int { return 4 } fun

    generateRandomNumber(): Int = 4
  103. @ToddGinsberg FUNctions! fun generateRandomNumber(): Int { return 4 } fun

    generateRandomNumber(): Int = 4 fun generateRandomNumber() = 4
  104. @ToddGinsberg FUNctions - Default Values fun random(offset: Int = 0):

    Int = offset + 4
  105. @ToddGinsberg FUNctions - Default Values fun random(offset: Int = 0):

    Int = offset + 4 random() // 4
  106. @ToddGinsberg FUNctions - Default Values fun random(offset: Int = 0):

    Int = offset + 4 random() // 4 random(1) // 5
  107. @ToddGinsberg FUNctions - Adding Parameters fun combine(first: Int, second: Int):

    Int = first + second
  108. @ToddGinsberg FUNctions - Adding Parameters fun combine(first: Int, second: Int,

    third: Int = 0): Int = first + second + third
  109. @ToddGinsberg FUNctions - Adding Parameters fun combine(first: Int, second: Int,

    third: Int = 0): Int = first + second + third combine(1, 2) combine(1, 2, 3)
  110. @ToddGinsberg FUNctions - Named Parameters fun combine(first: Int, second: Int):

    Int = first + second
  111. @ToddGinsberg FUNctions - Named Parameters fun combine(first: Int, second: Int):

    Int = first + second combine(1, 2) // 3
  112. @ToddGinsberg FUNctions - Named Parameters fun combine(first: Int, second: Int):

    Int = first + second combine(first = 1, second = 2) // 3
  113. @ToddGinsberg FUNctions - Named Parameters fun combine(first: Int, second: Int):

    Int = first + second combine(second = 2, first = 1) // 3
  114. @ToddGinsberg Extension FUNctions // Java public static boolean isEven(int i)

    { return i % 2 == 0; }
  115. @ToddGinsberg Extension FUNctions // Kotlin fun Int.isEven(): Boolean = this

    % 2 == 0
  116. @ToddGinsberg Extension FUNctions // Kotlin fun Int.isEven(): Boolean = this

    % 2 == 0 2.isEven() // True!
  117. @ToddGinsberg The use Extension // Java try (Connection conn =

    getConnection()) { // ... }
  118. @ToddGinsberg The use Extension // Kotlin getConnection().use { conn ->

    // ... }
  119. @ToddGinsberg The apply Extension // Expression and Statements val p

    = Person() p.name = "Todd" p.age = 21
  120. @ToddGinsberg The apply Extension // Single Expression val p =

    Person().apply { name = "Todd" age = 21 }
  121. @ToddGinsberg The apply Extension // Single Expression val p =

    Person().apply { name = "Todd" age = 21 address = Address().apply { line1 = "5 Tall Cedar Rd." … } }
  122. @ToddGinsberg One More Thing on FUNctions • Functions are final

    by default.
  123. @ToddGinsberg One More Thing on FUNctions • Functions are final

    by default. • Arguments are always final.
  124. @ToddGinsberg One More Thing on FUNctions • Functions are final

    by default. • Arguments are always final. • Functions can be defined in a file, outside of a class.
  125. @ToddGinsberg One More Thing on FUNctions • Functions are final

    by default. • Arguments are always final. • Functions can be defined in a file, outside of a class. • Functions can be defined within another function.
  126. @ToddGinsberg One More Thing on FUNctions • Functions are final

    by default. • Arguments are always final. • Functions can be defined in a file, outside of a class. • Functions can be defined within another function. • Kotlin supports tail recursive functions.
  127. @ToddGinsberg What About Checked Exceptions? ?

  128. @ToddGinsberg What About Checked Exceptions? NO

  129. @ToddGinsberg Lambdas listOf(1, 2, 3, 4) .filter { x ->

    x % 2 == 0 } .map { y -> y * 2 } // List[4, 8]
  130. @ToddGinsberg Lambdas listOf(1, 2, 3, 4) .filter { x ->

    x % 2 == 0 } .map { y -> y * 2 } // List[4, 8]
  131. @ToddGinsberg Lambdas listOf(1, 2, 3, 4) .filter { it %

    2 == 0 } .map { it * 2 } // List[4, 8]
  132. @ToddGinsberg So Many Things Left Out! :( - Property delegation

    - Class delegation - Operator overloading - Destructuring - Higher-order functions - Companion objects - Import aliases - Type aliases - Unsigned integer types - Coroutines - Massive STDLIB replaces your util classes - Reified generics - Inline classes - Infix functions - Sealed classes - Scoping functions - DSL support
  133. @ToddGinsberg Summary

  134. @ToddGinsberg Why Do I Use Kotlin? • I write far

    less code.
  135. @ToddGinsberg Why Do I Use Kotlin? • I write far

    less code. • The code I write is more expressive and clear.
  136. @ToddGinsberg Why Do I Use Kotlin? • I write far

    less code. • The code I write is more expressive and clear. • I avoid whole classes of defects.
  137. @ToddGinsberg Why Do I Use Kotlin? • I write far

    less code. • The code I write is more expressive and clear. • I avoid whole classes of defects. • Plays well with the tools I use (Spring, IDEA, Gradle)
  138. @ToddGinsberg Why Do I Use Kotlin? • I write far

    less code. • The code I write is more expressive and clear. • I avoid whole classes of defects. • Plays well with the tools I use (Spring, IDEA, Gradle) • Writing Kotlin, for me, is more fun.
  139. @ToddGinsberg Fun == Fun % of developers who are developing

    with the language or technology but have not expressed interest in continuing to do so (Stack Overflow Developer Survey 2019)
  140. @ToddGinsberg Fun == Fun % of developers who are developing

    with the language or technology but have not expressed interest in continuing to do so (Stack Overflow Developer Survey 2019) Kotlin
  141. @ToddGinsberg Make “Bad” Choices Explicit or Impossible Fixed in Kotlin:

    -Singleton support built in -Override keyword mandatory -Properties over fields with getter/setter -Mutability is minimized (val + collections) -Inheritance prohibited by default -Builders are easy with default values -No checked exceptions -Structural equality is the same everywhere -Delegation support makes composition easier
  142. @ToddGinsberg Want to Learn More? https://play.kotlinlang.org

  143. @ToddGinsberg Want to Learn More? The State of Kotlin Support

    in Spring Go back in time for this (or check it out on YouTube next week!)
  144. @ToddGinsberg Want to Learn More? Fully Reactive: Spring, Kotlin, and

    JavaFX Playing Together Today from 4:20pm–5:30pm In this room!
  145. @ToddGinsberg Want to Learn More? Klingon Kotlin (in Anger, er,

    Passion) with Project Reactor and Spring Boot: Ha' HIja'! Tomorrow from 11:30am–12:40pm In this room!
  146. #springone @s1p @ToddGinsberg todd@ginsberg.com https://todd.ginsberg.com http://bit.ly/S1P2019-Kotlin Thank You!