Share
Embed
Tips and tricks for adopting Kotlin
Kotlin is the new cool kid in town, but there is not a lot of information out there on the process of adopting it as a company.
In this talk we are going to show why and how we started using Kotlin in N26, focusing on a service written from scratch by the Barcelona team, and discussing some of the lessons learned in the process.
At the end we are going to close with a quick 5 step guide on how your Kotlin migration can be successful and a Q&A.
Uriel Salischiker
May 02, 2019
Transcript
208 slides
-
Tips and tricks for adopting Kotlin Uriel Salischiker - @urielsalis
N26, Barcelona - May 2019 -
Tips and tricks for adopting Kotlin Share your own at
[email protected] This is my own experience -
Why Kotlin? Null safety 一 Aimed at removing null references
Tips and tricks for adopting Kotlin -
Why Kotlin? Null safety 一 Aimed at removing null references
一 Avoiding The Billion Dollar Mistake Tips and tricks for adopting Kotlin -
Why Kotlin? Null safety 一 Aimed at removing null references
一 Avoiding The Billion Dollar Mistake 一 Clearer APIs Tips and tricks for adopting Kotlin -
Why Kotlin? Null safety var str: String = "I’m a
string!" str = null // Fails to compile var str2: String? = "I’m a nullable string!" str2 = null // Works! Tips and tricks for adopting Kotlin -
Why Kotlin? Null safety var str: String = "I’m a
string!" str = null // Fails to compile var str2: String? = "I’m a nullable string!" str2 = null // Works! Tips and tricks for adopting Kotlin Optional<String> strOptional = Optional.of("I’m a string!"); Optional<String> strOptional = Optional.ofNullable("I’m a string!"); String contents = strOptional.orElse("I was null :c"); String contents2 = strOptional2.orElse("I was null :c"); -
Why Kotlin? Immutability 一 Immutability by default Tips and tricks
for adopting Kotlin -
Why Kotlin? Immutability 一 Immutability by default Tips and tricks
for adopting Kotlin 一 Clear mutability on properties -
Why Kotlin? Immutability Tips and tricks for adopting Kotlin val
immutableList = List<String>() val mutableList = MutableList<String>() Collections -
Why Kotlin? Immutability Tips and tricks for adopting Kotlin val
immutableList = List<String>() val mutableList = MutableList<String>() immutableList.add("string") //Fails mutableList.add("string") //Works Collections -
Why Kotlin? Immutability Tips and tricks for adopting Kotlin val
finalStr = "string" var mutableStr = "string" Properties -
Why Kotlin? Immutability Tips and tricks for adopting Kotlin val
finalStr = "string" var mutableStr = "string" finalStr = "something else" //Fails mutableStr = "something else" // Works Properties -
Why Kotlin? Data classes Tips and tricks for adopting Kotlin
一 Reducing boilerplate 一 Human comprehension is the key -
Why Kotlin? Data classes Tips and tricks for adopting Kotlin
public class VideoGame { private String name; private String publisher; private int reviewScore; public VideoGame(String name, String publisher, int reviewScore) { this.name = name; this.publisher = publisher; this.reviewScore = reviewScore; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPublisher() { return publisher; } public void setPublisher(String publisher) { this.publisher = publisher; } public int getReviewScore() { return reviewScore; } public void setReviewScore(int reviewScore) { this.reviewScore = reviewScore; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; VideoGame that = (VideoGame) o; if (reviewScore != that.reviewScore) return false; if (name != null ? !name.equals(that.name) : that.name != null) { return false; } return publisher != null ? publisher.equals(that.publisher) : that.publisher == null; } @Override public int hashCode() { int result = name != null ? name.hashCode() : 0; result = 31 * result + (publisher != null ? publisher.hashCode() : 0); result = 31 * result + reviewScore; return result; } @Override public String toString() { return "VideoGame{" + "name='" + name + '\'' + ", publisher='" + publisher + '\'' + ", reviewScore=" + reviewScore + '}'; } Java data class VideoGame( val name: String, val publisher: String, var reviewScore: Int ) Kotlin -
Why Kotlin? Data classes Tips and tricks for adopting Kotlin
public class VideoGame { private String name; private String publisher; private int reviewScore; public VideoGame(String name, String publisher, int reviewScore) { this.name = name; this.publisher = publisher; this.reviewScore = reviewScore; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPublisher() { return publisher; } public void setPublisher(String publisher) { this.publisher = publisher; } public int getReviewScore() { return reviewScore; } public void setReviewScore(int reviewScore) { this.reviewScore = reviewScore; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; VideoGame that = (VideoGame) o; if (reviewScore != that.reviewScore) return false; if (name != null ? !name.equals(that.name) : that.name != null) { return false; } return publisher != null ? publisher.equals(that.publisher) : that.publisher == null; } @Override public int hashCode() { int result = name != null ? name.hashCode() : 0; result = 31 * result + (publisher != null ? publisher.hashCode() : 0); result = 31 * result + reviewScore; return result; } @Override public String toString() { return "VideoGame{" + "name='" + name + '\'' + ", publisher='" + publisher + '\'' + ", reviewScore=" + reviewScore + '}'; } Java data class VideoGame( val name: String, val publisher: String, var reviewScore: Int ) Kotlin • Getters -
Why Kotlin? Data classes Tips and tricks for adopting Kotlin
public class VideoGame { private String name; private String publisher; private int reviewScore; public VideoGame(String name, String publisher, int reviewScore) { this.name = name; this.publisher = publisher; this.reviewScore = reviewScore; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPublisher() { return publisher; } public void setPublisher(String publisher) { this.publisher = publisher; } public int getReviewScore() { return reviewScore; } public void setReviewScore(int reviewScore) { this.reviewScore = reviewScore; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; VideoGame that = (VideoGame) o; if (reviewScore != that.reviewScore) return false; if (name != null ? !name.equals(that.name) : that.name != null) { return false; } return publisher != null ? publisher.equals(that.publisher) : that.publisher == null; } @Override public int hashCode() { int result = name != null ? name.hashCode() : 0; result = 31 * result + (publisher != null ? publisher.hashCode() : 0); result = 31 * result + reviewScore; return result; } @Override public String toString() { return "VideoGame{" + "name='" + name + '\'' + ", publisher='" + publisher + '\'' + ", reviewScore=" + reviewScore + '}'; } Java data class VideoGame( val name: String, val publisher: String, var reviewScore: Int ) Kotlin • Getters • Setters -
Why Kotlin? Data classes Tips and tricks for adopting Kotlin
public class VideoGame { private String name; private String publisher; private int reviewScore; public VideoGame(String name, String publisher, int reviewScore) { this.name = name; this.publisher = publisher; this.reviewScore = reviewScore; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPublisher() { return publisher; } public void setPublisher(String publisher) { this.publisher = publisher; } public int getReviewScore() { return reviewScore; } public void setReviewScore(int reviewScore) { this.reviewScore = reviewScore; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; VideoGame that = (VideoGame) o; if (reviewScore != that.reviewScore) return false; if (name != null ? !name.equals(that.name) : that.name != null) { return false; } return publisher != null ? publisher.equals(that.publisher) : that.publisher == null; } @Override public int hashCode() { int result = name != null ? name.hashCode() : 0; result = 31 * result + (publisher != null ? publisher.hashCode() : 0); result = 31 * result + reviewScore; return result; } @Override public String toString() { return "VideoGame{" + "name='" + name + '\'' + ", publisher='" + publisher + '\'' + ", reviewScore=" + reviewScore + '}'; } Java data class VideoGame( val name: String, val publisher: String, var reviewScore: Int ) Kotlin • Getters • Setters • Constructor -
Why Kotlin? Data classes Tips and tricks for adopting Kotlin
public class VideoGame { private String name; private String publisher; private int reviewScore; public VideoGame(String name, String publisher, int reviewScore) { this.name = name; this.publisher = publisher; this.reviewScore = reviewScore; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPublisher() { return publisher; } public void setPublisher(String publisher) { this.publisher = publisher; } public int getReviewScore() { return reviewScore; } public void setReviewScore(int reviewScore) { this.reviewScore = reviewScore; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; VideoGame that = (VideoGame) o; if (reviewScore != that.reviewScore) return false; if (name != null ? !name.equals(that.name) : that.name != null) { return false; } return publisher != null ? publisher.equals(that.publisher) : that.publisher == null; } @Override public int hashCode() { int result = name != null ? name.hashCode() : 0; result = 31 * result + (publisher != null ? publisher.hashCode() : 0); result = 31 * result + reviewScore; return result; } @Override public String toString() { return "VideoGame{" + "name='" + name + '\'' + ", publisher='" + publisher + '\'' + ", reviewScore=" + reviewScore + '}'; } Java data class VideoGame( val name: String, val publisher: String, var reviewScore: Int ) Kotlin • Getters • Setters • Constructor • Equals -
Why Kotlin? Data classes Tips and tricks for adopting Kotlin
public class VideoGame { private String name; private String publisher; private int reviewScore; public VideoGame(String name, String publisher, int reviewScore) { this.name = name; this.publisher = publisher; this.reviewScore = reviewScore; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPublisher() { return publisher; } public void setPublisher(String publisher) { this.publisher = publisher; } public int getReviewScore() { return reviewScore; } public void setReviewScore(int reviewScore) { this.reviewScore = reviewScore; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; VideoGame that = (VideoGame) o; if (reviewScore != that.reviewScore) return false; if (name != null ? !name.equals(that.name) : that.name != null) { return false; } return publisher != null ? publisher.equals(that.publisher) : that.publisher == null; } @Override public int hashCode() { int result = name != null ? name.hashCode() : 0; result = 31 * result + (publisher != null ? publisher.hashCode() : 0); result = 31 * result + reviewScore; return result; } @Override public String toString() { return "VideoGame{" + "name='" + name + '\'' + ", publisher='" + publisher + '\'' + ", reviewScore=" + reviewScore + '}'; } Java data class VideoGame( val name: String, val publisher: String, var reviewScore: Int ) Kotlin • Getters • Setters • Constructor • Equals • Hashcode -
Why Kotlin? Data classes Tips and tricks for adopting Kotlin
public class VideoGame { private String name; private String publisher; private int reviewScore; public VideoGame(String name, String publisher, int reviewScore) { this.name = name; this.publisher = publisher; this.reviewScore = reviewScore; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPublisher() { return publisher; } public void setPublisher(String publisher) { this.publisher = publisher; } public int getReviewScore() { return reviewScore; } public void setReviewScore(int reviewScore) { this.reviewScore = reviewScore; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; VideoGame that = (VideoGame) o; if (reviewScore != that.reviewScore) return false; if (name != null ? !name.equals(that.name) : that.name != null) { return false; } return publisher != null ? publisher.equals(that.publisher) : that.publisher == null; } @Override public int hashCode() { int result = name != null ? name.hashCode() : 0; result = 31 * result + (publisher != null ? publisher.hashCode() : 0); result = 31 * result + reviewScore; return result; } @Override public String toString() { return "VideoGame{" + "name='" + name + '\'' + ", publisher='" + publisher + '\'' + ", reviewScore=" + reviewScore + '}'; } Java data class VideoGame( val name: String, val publisher: String, var reviewScore: Int ) Kotlin • Getters • Setters • Constructor • Equals • Hashcode • ToString -
Why Kotlin? Data classes Tips and tricks for adopting Kotlin
public class VideoGame { private String name; private String publisher; private int reviewScore; public VideoGame(String name, String publisher, int reviewScore) { this.name = name; this.publisher = publisher; this.reviewScore = reviewScore; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPublisher() { return publisher; } public void setPublisher(String publisher) { this.publisher = publisher; } public int getReviewScore() { return reviewScore; } public void setReviewScore(int reviewScore) { this.reviewScore = reviewScore; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; VideoGame that = (VideoGame) o; if (reviewScore != that.reviewScore) return false; if (name != null ? !name.equals(that.name) : that.name != null) { return false; } return publisher != null ? publisher.equals(that.publisher) : that.publisher == null; } @Override public int hashCode() { int result = name != null ? name.hashCode() : 0; result = 31 * result + (publisher != null ? publisher.hashCode() : 0); result = 31 * result + reviewScore; return result; } @Override public String toString() { return "VideoGame{" + "name='" + name + '\'' + ", publisher='" + publisher + '\'' + ", reviewScore=" + reviewScore + '}'; } Java data class VideoGame( val name: String, val publisher: String, var reviewScore: Int ) Kotlin • Getters • Setters • Constructor • Equals • Hashcode • ToString • Builder -
Why Kotlin? Data classes Tips and tricks for adopting Kotlin
public class VideoGame { private String name; private String publisher; private int reviewScore; public VideoGame(String name, String publisher, int reviewScore) { this.name = name; this.publisher = publisher; this.reviewScore = reviewScore; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPublisher() { return publisher; } public void setPublisher(String publisher) { this.publisher = publisher; } public int getReviewScore() { return reviewScore; } public void setReviewScore(int reviewScore) { this.reviewScore = reviewScore; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; VideoGame that = (VideoGame) o; if (reviewScore != that.reviewScore) return false; if (name != null ? !name.equals(that.name) : that.name != null) { return false; } return publisher != null ? publisher.equals(that.publisher) : that.publisher == null; } @Override public int hashCode() { int result = name != null ? name.hashCode() : 0; result = 31 * result + (publisher != null ? publisher.hashCode() : 0); result = 31 * result + reviewScore; return result; } @Override public String toString() { return "VideoGame{" + "name='" + name + '\'' + ", publisher='" + publisher + '\'' + ", reviewScore=" + reviewScore + '}'; } Java data class VideoGame( val name: String, val publisher: String, var reviewScore: Int ) Kotlin • Getters • Setters • Constructor • Equals • Hashcode • ToString • Builder • Copy -
Why Kotlin? Data classes Tips and tricks for adopting Kotlin
public class VideoGame { private String name; private String publisher; private int reviewScore; public VideoGame(String name, String publisher, int reviewScore) { this.name = name; this.publisher = publisher; this.reviewScore = reviewScore; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPublisher() { return publisher; } public void setPublisher(String publisher) { this.publisher = publisher; } public int getReviewScore() { return reviewScore; } public void setReviewScore(int reviewScore) { this.reviewScore = reviewScore; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; VideoGame that = (VideoGame) o; if (reviewScore != that.reviewScore) return false; if (name != null ? !name.equals(that.name) : that.name != null) { return false; } return publisher != null ? publisher.equals(that.publisher) : that.publisher == null; } @Override public int hashCode() { int result = name != null ? name.hashCode() : 0; result = 31 * result + (publisher != null ? publisher.hashCode() : 0); result = 31 * result + reviewScore; return result; } @Override public String toString() { return "VideoGame{" + "name='" + name + '\'' + ", publisher='" + publisher + '\'' + ", reviewScore=" + reviewScore + '}'; } Java data class VideoGame( val name: String, val publisher: String, var reviewScore: Int ) Kotlin • Getters • Setters • Constructor • Equals • Hashcode • ToString • Builder • Copy • ComponentN -
Why Kotlin? Data classes data class Pet( val name: String,
var office: String? = “Berlin” ) Tips and tricks for adopting Kotlin -
Why Kotlin? Data classes data class Pet( val name: String,
var office: String? = “Berlin” ) Tips and tricks for adopting Kotlin @Data @AllArgsConstructor public class Pet { @NonNull private final String name; private boolean office = "Berlin"; @Builder @SuppressWarnings("unused") private Pet(String name) { this.name = name; } } -
Why Kotlin? Data classes Tips and tricks for adopting Kotlin
data class Fee(val amount: Int, val country: String) -
Why Kotlin? Data classes Tips and tricks for adopting Kotlin
data class Fee(val amount: Int, val country: String) -
Why Kotlin? Data classes Tips and tricks for adopting Kotlin
data class Fee(val amount: Int, val country: String) val ukFee = Fee(10, "GBR") -
Why Kotlin? Data classes Tips and tricks for adopting Kotlin
data class Fee(val amount: Int, val country: String) val ukFee = Fee(10, "GBR") val usaFee = ukFee.copy(country = "USA") -
Why Kotlin? Data classes Tips and tricks for adopting Kotlin
data class Fee(val amount: Int, val country: String) val ukFee = Fee(10, "GBR") val usaFee = ukFee.copy(country = "USA") val fees = listOf(ukFee, usaFee) -
Why Kotlin? Data classes Tips and tricks for adopting Kotlin
data class Fee(val amount: Int, val country: String) val ukFee = Fee(10, "GBR") val usaFee = ukFee.copy(country = "USA") val fees = listOf(ukFee, usaFee) -
Why Kotlin? Data classes Tips and tricks for adopting Kotlin
data class Fee(val amount: Int, val country: String) val ukFee = Fee(10, "GBR") val usaFee = ukFee.copy(country = "USA") val fees = listOf(ukFee, usaFee) for ((amount, country) in fees) { -
Why Kotlin? Data classes Tips and tricks for adopting Kotlin
data class Fee(val amount: Int, val country: String) val ukFee = Fee(10, "GBR") val usaFee = ukFee.copy(country = "USA") val fees = listOf(ukFee, usaFee) for ((amount, country) in fees) { // This is also done automatically for maps -
Why Kotlin? Data classes Tips and tricks for adopting Kotlin
data class Fee(val amount: Int, val country: String) val ukFee = Fee(10, "GBR") val usaFee = ukFee.copy(country = "USA") val fees = listOf(ukFee, usaFee) for ((amount, country) in fees) { // This is also done automatically for maps // No need to do something like -
Why Kotlin? Data classes Tips and tricks for adopting Kotlin
data class Fee(val amount: Int, val country: String) val ukFee = Fee(10, "GBR") val usaFee = ukFee.copy(country = "USA") val fees = listOf(ukFee, usaFee) for ((amount, country) in fees) { // This is also done automatically for maps // No need to do something like // Map.Entry<Key, Value> entry: map.entries() -
Why Kotlin? Data classes Tips and tricks for adopting Kotlin
data class Fee(val amount: Int, val country: String) val ukFee = Fee(10, "GBR") val usaFee = ukFee.copy(country = "USA") val fees = listOf(ukFee, usaFee) for ((amount, country) in fees) { // This is also done automatically for maps // No need to do something like // Map.Entry<Key, Value> entry: map.entries() } -
Why Kotlin? Data classes Tips and tricks for adopting Kotlin
data class Fee(val amount: Int, val country: String) val ukFee = Fee(10, "GBR") val usaFee = ukFee.copy(country = "USA") val fees = listOf(ukFee, usaFee) for ((amount, country) in fees) { // This is also done automatically for maps // No need to do something like // Map.Entry<Key, Value> entry: map.entries() } -
Why Kotlin? Data classes Tips and tricks for adopting Kotlin
data class Fee(val amount: Int, val country: String) val ukFee = Fee(10, "GBR") val usaFee = ukFee.copy(country = "USA") val fees = listOf(ukFee, usaFee) for ((amount, country) in fees) { // This is also done automatically for maps // No need to do something like // Map.Entry<Key, Value> entry: map.entries() } -
Why Kotlin? Data classes Tips and tricks for adopting Kotlin
data class Fee(val amount: Int, val country: String) val ukFee = Fee(10, "GBR") val usaFee = ukFee.copy(country = "USA") val fees = listOf(ukFee, usaFee) for ((amount, country) in fees) { // This is also done automatically for maps // No need to do something like // Map.Entry<Key, Value> entry: map.entries() } data class Result(val result: Int, val status: Status) -
Why Kotlin? Data classes Tips and tricks for adopting Kotlin
data class Fee(val amount: Int, val country: String) val ukFee = Fee(10, "GBR") val usaFee = ukFee.copy(country = "USA") val fees = listOf(ukFee, usaFee) for ((amount, country) in fees) { // This is also done automatically for maps // No need to do something like // Map.Entry<Key, Value> entry: map.entries() } data class Result(val result: Int, val status: Status) val (result, status) = ... -
Why Kotlin? One language Multiple platforms Tips and tricks for
adopting Kotlin -
Why Kotlin? One language Multiple platforms 一 Compiles to native
code, javascript, JVM Tips and tricks for adopting Kotlin -
Why Kotlin? One language Multiple platforms 一 Compiles to native
code, javascript, JVM 一 Client and Server can share code Tips and tricks for adopting Kotlin -
Why Kotlin? One language Multiple platforms 一 Compiles to native
code, javascript, JVM 一 Client and Server can share code 一 Official Android language Tips and tricks for adopting Kotlin -
Why Kotlin? One language Multiple platforms 一 Compiles to native
code, javascript, JVM 一 Client and Server can share code 一 Official Android language 一 Supports iOS (more targets in the future) Tips and tricks for adopting Kotlin -
Why Kotlin? Open source 一 Fully open source Tips and
tricks for adopting Kotlin -
Why Kotlin? Open source 一 Fully open source 一 Backed
by Jetbrains Tips and tricks for adopting Kotlin -
Why Kotlin? Open source 一 Fully open source 一 Backed
by Jetbrains 一 Language proposals KEEP Tips and tricks for adopting Kotlin -
“Adoption of a language depends more of its ecosystem than
its features” Empirical analysis of programming languages adoption Meyerovich LA, Rabkin AS November 2013 Tips and tricks for adopting Kotlin -
Why Kotlin? Interoperability with Java 一 100% compatible with Java
Tips and tricks for adopting Kotlin -
Why Kotlin? Interoperability with Java 一 100% compatible with Java
一 Easier to migrate in steps Tips and tricks for adopting Kotlin -
Why Kotlin? Interoperability with Java 一 100% compatible with Java
一 Easier to migrate in steps Tips and tricks for adopting Kotlin Note This doesn’t work as well with code generators like Lombok -
Why Kotlin? Cleaner functional programming 一 Extensive base library Tips
and tricks for adopting Kotlin -
Why Kotlin? Cleaner functional programming 一 Extensive base library 一
Collection processing Tips and tricks for adopting Kotlin -
Why Kotlin? Cleaner functional programming 一 Extensive base library 一
Collection processing 一 Sequences: Better streams Tips and tricks for adopting Kotlin -
Why Kotlin? Cleaner functional programming 一 Extensive base library 一
Collection processing 一 Sequences: Better streams 一 Ranges Tips and tricks for adopting Kotlin -
Why Kotlin? Cleaner functional programming 一 Extensive base library 一
Collection processing 一 Sequences: Better streams 一 Ranges Tips and tricks for adopting Kotlin Tip Libraries like Arrow make this even better -
一 Lombok 一 KAPT Tips and tricks for adopting Kotlin
Why NOT Kotlin? -
一 Lombok 一 KAPT 一 Change of mentality and way
of coding Tips and tricks for adopting Kotlin Why NOT Kotlin? -
一 Lombok 一 KAPT 一 Change of mentality and way
of coding 一 Patterns and Anti-Patterns are not set Tips and tricks for adopting Kotlin Why NOT Kotlin? -
“I’m just playing with Kotlin as a kid with a
new game, so I find a lot of possibilities of writing the same code in different ways, but no opinions yet” - Pull request comment Yesterday Tips and tricks for adopting Kotlin -
Why Not Kotlin? Tips and tricks for adopting Kotlin -
Developers are not as experienced -
Why Not Kotlin? Tips and tricks for adopting Kotlin -
Developers are not as experienced - Bad Kotlin code is uglier than Java -
Talks 一 Lighting talks 一 Get Stuff Done Days projects
Tips and tricks for adopting Kotlin -
Talks 一 Lighting talks 一 Get Stuff Done Days projects
一 Initial gotchas Tips and tricks for adopting Kotlin -
Tests 一 Migrating tests to kotlin 一 Kotlin Junit &
mockito-kotlin Tips and tricks for adopting Kotlin -
Tests 一 Migrating tests to kotlin 一 Kotlin Junit &
mockito-kotlin Tips and tricks for adopting Kotlin Tip Check KotlinTest and MockK! -
Migrating services 一 Small services: Transaction Notifications Tips and tricks
for adopting Kotlin -
Migrating services 一 Small services: Transaction Notifications 一 Automatic conversion
using Intellij IDEA Tips and tricks for adopting Kotlin -
Migrating services 一 Small services: Transaction Notifications 一 Automatic conversion
using Intellij IDEA 一 Manual changes to make it more idiomatic Tips and tricks for adopting Kotlin -
New services 一 New architecture 一 Shared libraries Tips and
tricks for adopting Kotlin -
New services 一 New architecture 一 Shared libraries 一 New
problems Tips and tricks for adopting Kotlin -
Final by default 一 Lots of open everywhere Tips and
tricks for adopting Kotlin -
Final by default 一 Lots of open everywhere 一 “all-open”
plugin Tips and tricks for adopting Kotlin -
Codestyle 一 No set code style Tips and tricks for
adopting Kotlin -
Codestyle 一 No set code style 一 Java Static analysis
tools Tips and tricks for adopting Kotlin -
Codestyle 一 No set code style 一 Java Static analysis
tools 一 Kotlin Static analysis tools Tips and tricks for adopting Kotlin -
Codestyle 一 No set code style 一 Java Static analysis
tools 一 Kotlin Static analysis tools 一 Team conventions Tips and tricks for adopting Kotlin -
Jooq 一 Custom converters 一 Runs after kotlin Tips and
tricks for adopting Kotlin -
Jooq 一 Custom converters 一 Runs after kotlin 一 Requires
code to compile Tips and tricks for adopting Kotlin -
Jooq table("pet") { "pet_id" withTinyType CatId::class "owner_id" withTinyType OwnerId::class "price"
withCustomConverter CurrencyConverter::class "purchase_date" withInstantTinyType PurchaseDate::class "branch" withEnum Branch::class } Tips and tricks for adopting Kotlin -
Sealed classes 一 State machines defined on the domain Tips
and tricks for adopting Kotlin -
Sealed classes sealed class RegisterResponse() object SuccessfulResponse: RegisterResponse() class FailedResponse(val
e: Exception): RegisterResponse() return when(response) { is SuccessfulResponse -> "All good!" is FailedResponse-> "All bad :C. $e" } Tips and tricks for adopting Kotlin -
Sealed classes sealed class Fee( val id: FeeId Tips and
tricks for adopting Kotlin -
Sealed classes sealed class Fee( val id: FeeId ) Tips
and tricks for adopting Kotlin -
Sealed classes sealed class Fee( val id: FeeId ) Tips
and tricks for adopting Kotlin -
Sealed classes sealed class Fee( val id: FeeId ) data
class ActiveFee(val id: FeeId): Fee(id) Tips and tricks for adopting Kotlin -
Sealed classes sealed class Fee( val id: FeeId ) data
class ActiveFee(val id: FeeId): Fee(id) data class DeactivatedFee(val id: FeeId): Fee(id) Tips and tricks for adopting Kotlin -
Sealed classes sealed class Fee( val id: FeeId ) data
class ActiveFee(val id: FeeId): Fee(id) data class DeactivatedFee(val id: FeeId): Fee(id) data class ProcessingFee(val id: FeeId): Fee(id) Tips and tricks for adopting Kotlin -
Sealed classes sealed class Fee( val id: FeeId ) data
class ActiveFee(val id: FeeId): Fee(id) data class DeactivatedFee(val id: FeeId): Fee(id) data class ProcessingFee(val id: FeeId): Fee(id) data class CompletedFee( val id: FeeId, val completed: Instant ): Fee(id) Tips and tricks for adopting Kotlin -
Builders 一 Named builders 一 Tests Tips and tricks for
adopting Kotlin -
Builders data class Pet( val name: String, val office: String?
= null ) val ramon = Pet("Ramon", "BCN") val benno = Pet("Benno") val nala = Pet(name = "Nala", office = "BLN") Tips and tricks for adopting Kotlin -
Generics inline val <reified T> T.log: Logger get() = LoggerFactory.getLogger(T::class.java)
class Foo { fun bar() { log.info("No need to create instances, only import") } } -
Generics interface Source<out T> { //Covariant fun nextT(): T }
fun demo(strs: Source<String>) { val objects: Source<Any> = strs // This is OK, since T is an out-parameter // ... } -
Generics interface Comparable<in T> { //Contravariant operator fun compareTo(other: T):
Int } fun demo(x: Comparable<Number>) { x.compareTo(1.0) // 1.0 has type Double, which is a subtype of Number // Thus, we can assign x to a variable of type Comparable<Double> val y: Comparable<Double> = x // OK! } -
Delegated properties class Example(var p: String by Delegate()) class Delegate
{ operator fun getValue(thisRef: Any?, property: KProperty<*>): String { return "$thisRef, delegating '${property.name}'" } operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) { println("$value, '${property.name}' in $thisRef.") } } val e = Example() println(e.p) //Example@33a17727, delegating ‘p’ -
Delegated properties val lazyValue: String by lazy { println("computed!") "Hello"
} fun main() { println(lazyValue) println(lazyValue) } //computed //Hello //Hello -
Delegated properties class User { var name: String by Delegates.observable("<no
name>") { prop, old, new -> println("$old -> $new") } } fun main() { val user = User() user.name = "first" user.name = "second" } -
Delegated properties class User(val map: Map<String, Any?>) { val name:
String by map val age: Int by map } val user = User(mapOf( "name" to "John Doe", "age" to 25 )) println(user.name) // Prints "John Doe" println(user.age) // Prints 25 -
Delegated properties //Since Kotlin 1.1 fun example(computeFoo: () -> Foo)
{ val memoizedFoo by lazy(computeFoo) if (someCondition && memoizedFoo.isValid()) { //if someCondition is false, // memoizedFoo is never computed memoizedFoo.doSomething() } } -
Constants 一 Java -> static final 一 Kotlin -> ?
Tips and tricks for adopting Kotlin -
Constants 一 Java -> static final 一 Kotlin -> ?
const val FOO = "foo" Tips and tricks for adopting Kotlin -
Companion objects 一 Extra boilerplate 一 Performance penalty 一 Uglier
code on Java Tips and tricks for adopting Kotlin -
Companion objects Tips and tricks for adopting Kotlin class C
{ companion object { @JvmStatic fun foo() {} fun bar() {} } } C.foo(); // works fine C.bar(); // error: not a static method C.Companion.foo(); // instance method remains C.Companion.bar(); // the only way it works -
DSL and Extension functions abuse 一 Leads to god objects
一 DSL for everything might not be as readable Tips and tricks for adopting Kotlin -
DSL and Extension functions abuse val helloWorldInBrainf_ck = s[s {
7 }.r.a.l].r.s.o //-[------->+<]>-. .s[s.r.a { 5 }.l].r.a.a.o //-[->+++++<]>++. .a { 7 }.o.o //+++++++.. .a { 3 }.o[s.r.a { 5 }.l].r.a.o //+++.[->+++++<]>+. .s { 12 }.o //------------. .s { 3 }[s.r.a { 3 }.l].r.o //---[->+++<]>. .s[s { 3 }.r.a.l].r.s { 3 }.o //-[--->+<]>---. .a { 3 }.o //+++. .s { 6 }.o //------. .s { 8 }.o //--------. .s[s { 3 }.r.a.l].r.o //-[--->+<]>. Tips and tricks for adopting Kotlin -
DSL and Extension functions abuse val v = village {
house { "Alice" age 31 "Bob" age 45 500.gold } house { sword with strength value 24.2 sword with strength level 16.7 shield with defense value 15.3 } house() house { "Charles" age 52 2500.gold sword shield } } Tips and tricks for adopting Kotlin -
DSL and Extension functions abuse class HouseBuilder { internal val
people = mutableListOf<Person>() internal val items = mutableListOf<Item>() fun build(): House { return House(people, items) } infix fun String.age(age: Int) { people.add(Person(this, age)) } val Int.gold: Unit get() { items += Gold(this) return Unit } } class VillageBuilder { private val houses = mutableListOf<House>() operator fun House.unaryPlus() { houses += this } fun house(setup: HouseBuilder.() -> Unit = {}) { val houseBuilder = HouseBuilder() houseBuilder.setup() houses += houseBuilder.build() } fun build(): Village { return Village(houses) } } fun village(setup: VillageBuilder.() -> Unit): Village { val villageBuilder = VillageBuilder() villageBuilder.setup() return villageBuilder.build() } Tips and tricks for adopting Kotlin class ShieldContinuation(val house: HouseBuilder) object defense val HouseBuilder.shield: ShieldContinuation get() { this.items += Shield(0.0) return ShieldContinuation(this) } infix fun ShieldContinuation.with(d: defense): ShieldBuilder { house.items.removeAt(house.items.lastIndex) return ShieldBuilder(house) } class ShieldBuilder(val house: HouseBuilder) infix fun ShieldBuilder.value(defense: Double) { house.items += Shield(defense) } class SwordContinuation(val house: HouseBuilder) object strength val HouseBuilder.sword: SwordContinuation get() { this.items += Sword(0.0) return SwordContinuation(this) } infix fun SwordContinuation.with(d: strength): SwordBuilder { house.items.removeAt(house.items.lastIndex) return SwordBuilder(house) } class SwordBuilder(val house: HouseBuilder) infix fun SwordBuilder.value(strength: Double) { house.items += Sword(strength) } infix fun SwordBuilder.level(strength: Double) = value(strength) -
Generics 一 Difficult to change mindset 一 * everywhere 一
out vs in confusion Tips and tricks for adopting Kotlin -
Testing libraries 一 All classes are final by default Tips
and tricks for adopting Kotlin -
Testing libraries 一 All classes are final by default 一
Used mockito Tips and tricks for adopting Kotlin -
Testing libraries 一 All classes are final by default 一
Used mockito Tips and tricks for adopting Kotlin Tip Check MockK and KotlinTest! -
Jackson - Can’t serialize without a default constructor - Jackson-module-kotlin
Tips and tricks for adopting Kotlin -
Getters as properties 一 Might hide performance bugs Tips and
tricks for adopting Kotlin -
Reflection abuse 一 Easy reflection hides the performance penalty Tips
and tricks for adopting Kotlin -
Reflection abuse class A(val p: Int) fun main() { //
prints "public final int A.getP()" println(A::p.javaGetter) // prints "private final int A.p" println(A::p.javaField) } Tips and tricks for adopting Kotlin -
Reflection abuse val numberRegex = "\\d+".toRegex() println(numberRegex.matches("29")) val isNumber =
numberRegex::matches println(isNumber("29")) Tips and tricks for adopting Kotlin -
Immutability 一 We shouldn’t just use Mutable everywhere 一 Change
of mindset Tips and tricks for adopting Kotlin -
Performance cost 一 Hidden cost of lambdas • Inline to
the rescue! 一 Local functions 一 Nullable primitives 一 Ranges(when there is indirection) Tips and tricks for adopting Kotlin -
Code style - No set code style - Intellij doesn’t
follow Kotlin guidelines completely by default(!) Tips and tricks for adopting Kotlin -
Kotlin champion 一 Designate a Kotlin champion Tips and tricks
for adopting Kotlin -
Kotlin champion 一 Designate a Kotlin champion 一 Kotlin Koans
Tips and tricks for adopting Kotlin -
Learn the basics 一 Base concepts Tips and tricks for
adopting Kotlin -
Learn the basics 一 Base concepts 一 Common patterns Tips
and tricks for adopting Kotlin -
Learn the basics 一 Base concepts 一 Common patterns 一
Open source code Tips and tricks for adopting Kotlin -
Tests 一 Start writing tests in Kotlin Tips and tricks
for adopting Kotlin -
Tests 一 Start writing tests in Kotlin 一 Migrate small
services Tips and tricks for adopting Kotlin -
Convincing Management 一 The team is more productive with Kotlin
Tips and tricks for adopting Kotlin -
Convincing Management 一 The team is more productive with Kotlin
一 Increases app quality Tips and tricks for adopting Kotlin -
Convincing Management 一 The team is more productive with Kotlin
一 Increases app quality 一 Team happiness! Tips and tricks for adopting Kotlin -
Convincing Management 一 The team is more productive with Kotlin
一 Increases app quality 一 Team happiness! 一 The industry is moving to it Tips and tricks for adopting Kotlin -
Convincing Management 一 The team is more productive with Kotlin
一 Increases app quality 一 Team happiness! 一 The industry is moving to it 一 Official Spring, Android & Gradle support Tips and tricks for adopting Kotlin -
Effective Kotlin 一 Team needs to agree on patterns 一
With great flexibility comes great responsibility https://medium.com/@appmattus/effective-kotlin- 31215a6cf847 Tips and tricks for adopting Kotlin