Talk presented at Codemotion Madrid 2017. Kotlin in a live production environment from early 2017, in microservices using a Java platform in Tuenti, Discussions on risks and experiences months after.
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());
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)
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
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/
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?
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?