SlideShare a Scribd company logo
1 of 83
Transitioning Android Teams Into Kotlin
Garth Gilmour (@GarthGilmour)
Eamonn Boyle (@BoyleEamonn)
Me
Him
Us
2018 was a very significant year
• For developers on the JVM
We stopped asking:
• “Why aren’t you doing this in Java?”
We started asking:
• “Why are you doing this in Java?”
The revolution is actualised
• It’s a polyglot coding world now
• …and there’s no going back
This Talk Is (Maybe) Slightly Out Of Date
“You thought Android devs still used Java”
They still are? Inconceivable!
This talk assumes:
• You know Java and Android
• You have the scars to prove it
We will convince you that:
• There is a better way
• Kotlin is that way
A Veteran’s Guide To Moving Android Teams To Kotlin
Excellent interoperability
• Call legacy Java code easily
• Make calls into Kotlin from Java
Really clear, yet concise syntax
• Reduces the codebase by over 40%
Beloved by frameworks
• Spring Boot (esp. with Kofu)
• Services (Ktor and Http4k)
• User Interfaces (TornadoFx)
• Build tools (Gradle from V5)
• Dependency Injection (Koin)
Why Code In Kotlin? Null Safety
String Templates
Default parameters
Extensions
Free Functions
Coroutines
Single Expression
Functions
Reified generics
Data classes and
Properties
Type Inference
Smart Casts
Operator overloading
public class Program {
public static void main(String[] args) {
List<String> data = Arrays.asList(
"ab","cde","fghi","jklmn",
"op","qrs","tuvw","xyz");
data.stream()
.flatMapToInt(CharSequence::chars)
.mapToObj(num -> (char)num)
.forEach(c -> System.out.printf("%s ", c));
}
}
Let’s Print The Alphabet - In Java
a b c d e f g h i j k l m n o p q r s t u v w x y z
fun main() {
val data = listOf(
"ab","cde","fghi","jklmn",
"op","qrs","tuvw","xyz")
data.flatMap { it.toList() }
.forEach { print("$it ") }
}
Let’s Print The Alphabet - In Kotlin
a b c d e f g h i j k l m n o p q r s t u v w x y z
Why Use Kotlin On Android?
“Today we’re announcing another big step: Android
development will become increasingly Kotlin-first.
Many new Jetpack APIs and features will be offered
first in Kotlin. If you’re starting a new project, you
should write it in Kotlin;”
Google I/O 2019
Codebase reduction by 40% (JetBrains figure)
Simplify the remaining code
Plaster over Androids cracks
Access FP features / patterns (Java 8+)
Future proof your skill set
Developer happiness 
Why Use Kotlin On Android?
We’ve written an awful lot of code…
• Especially mobile applications with complex networking
• Also embedded systems, web applications etc...
For an awful lot of clients…
• Atlassian, Johnson Controls, Shopkeep, Cybersource
On every platform you’ve ever heard of
• Plus (if you were lucky) a few you managed to avoid
We switched to Kotlin four years ago
• For all applications built on top of the JVM
• Plus we are experimenting with Native and JS
Why Listen To Us?
Instil is a JetBrains training partner
• Written 3 Kotlin courses so far
We have delivered training for
• Household names (Europe and US)
• Brand new start-ups
We believe Kotlin will help you write better solutions
• Engineering Expertise is part of our ethos and Kotlin helps us
• We believe in improving development practices within our community
We started the Kotlin Belfast User Group
• We promote it to help people, not to make money
Why Listen To Us?
We don’t get royalties from JetBrains or Google
We’re placing a bet on Kotlin being the future
Why Listen To Us?
• What motivated us to switch?
• How did we make the move?
• Which features do we love?
• What problems did we face?
• Did we require new frameworks?
• What would we do differently?
• Are coroutines of any use? *
Questions To Answer
* we want to talk about coroutines because they're awesome…
Prior to Kotlin we had written:
• iOS mobile apps in Objective-C and Swift
• Cross-platform mobile apps in Xamarin
• Standard desktop apps in C / C++ / C#
• Web applications in just about everything
• JEE in all its incarnations (including EJB)
• Spring from the earliest days to WebFlux
We were tendering for some major Android jobs
• The developers didn’t want to use Java
• They really didn’t want to use Java
What Motivated Us?
Words From The Wise
“I do not like this Java lang
I do not like it, business man
It does not suit our software house
It makes me sad to click the mouse
I will not code it here or there
It sucks for Android anywhere”
David Robert Seuss, Software Engineer
(personal conversation with our CEO)
We had a problem on the Java Virtual Machine
• Kotlin was a pragmatic solution
By todays standards Java is not great
• But lots of great software is written in it
We still leverage our historical knowledge
• By remaining within the JVM ecosystem
What Motivated Us?
Java Kotlin
Words from the Wise
“Making the switch from Java to Kotlin was easy - being
able to use the same tools and libraries that we knew
and loved meant that we felt productive in Kotlin almost
immediately.
Over time, our code then became simpler, more stable
and more performant as we started to experiment with
the Kotlin functional toolkit and coroutines.”
Chris van Es, Head of Engineering, Instil
Words from the Wise
“Working in Java is a fantastic developer experience
because you can use Kotlin.”
Kelvin Harron, Software Engineer, Instil
“Kotlin negates the biggest weakness of the Java
Ecosystem, i.e. Java.”
Eoin Mullan, Principal Software Engineer, Instil
The Community Was Going That Way
We wanted an epic, heroic tale of a
warrior’s struggle to final victory
It was less Kill Bill, and more Kill Kenny – very easy
Features We
Love
Kotlin’s interop story is awesome
• @Throws (adds checked exception)
• @JvmOverloads (for default params)
• @JvmName (rename most things)
• @JvmWildcard (manage generics)
Interop never caused serious disruption
• But it was reassuring to know we had
low level control should it be needed
• Emotional Support Annotations 
In Case Of Interoperability Emergency…
Expressive
• Meaningful
• Telling
• Revealing
Basic Class Design
public class Movie {
private String title;
private String description;
private Rating rating;
private Genre genre;
}
Basic Class Design
public class Movie {
private String title;
private String description;
private Rating rating;
private Genre genre;
public Movie(String title, String description, Rating rating, Genre genre) {
this.title = title;
this.description = description;
this.rating = rating;
this.genre = genre;
}
}
Basic Class Design
public class Movie {
private String title;
private String description;
private Rating rating;
private Genre genre;
public Movie(String title, String description, Rating rating, Genre genre) {
this.title = title;
this.description = description;
this.rating = rating;
this.genre = genre;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
Basic Class Design
public class Movie {
private String title;
private String description;
private Rating rating;
private Genre genre;
public Movie(String title, String description, Rating rating, Genre genre) {
this.title = title;
this.description = description;
this.rating = rating;
this.genre = genre;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Rating getRating() {
return rating;
}
public void setRating(Rating rating) {
this.rating = rating;
}
public Genre getGenre() {
return genre;
}
public void setGenre(Genre genre) {
this.genre = genre;
}
}
class Movie(var title: String,
var description: String,
var rating: Rating,
var genre: Genre) {
}
Basic Class Design
import java.util.Objects;
public class Movie {
private String title;
private String description;
private Rating rating;
private Genre genre;
public Movie(String title, String description, Rating rating, Genre genre) {
this.title = title;
this.description = description;
this.rating = rating;
this.genre = genre;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Rating getRating() {
return rating;
}
public void setRating(Rating rating) {
this.rating = rating;
}
public Genre getGenre() {
return genre;
}
public void setGenre(Genre genre) {
this.genre = genre;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Movie movie = (Movie) o;
return Objects.equals(title, movie.title) &&
Objects.equals(description, movie.description) &&
Objects.equals(rating, movie.rating) &&
Objects.equals(genre, movie.genre);
}
@Override
public int hashCode() {
return Objects.hash(title, description, rating, genre);
}
@Override
public String toString() {
return "Movie{" +
"title='" + title + ''' +
", description='" + description + ''' +
", rating=" + rating +
", genre=" + genre +
'}';
}
}
data class Movie(var title: String,
var description: String,
var rating: Rating,
var genre: Genre) {
}
But what if we need:
• Equality
• Hashing
• Copying
• Decomposition
menu {
submenu(“Setup") {
item(“Edit Details", ::editDetails)
item(“Reset Password", ::resetPassword)
}
submenu(“Sessions") {
item(“Create New Session", ::createNewSession)
item(“View All Sessions", ::viewall)
item(“Synchronize", ::synchronize)
}
Lambda’s With Receivers
fun menu(builder: Menu.() -> Unit) = Menu(builder)
class Menu(builder: Menu.() -> Unit) {
init {
this.builder()
}
fun submenu(description: String, builder: Menu.() -> Unit) { ... }
fun item(description: String, action: Action) { ... }
. . .
}
Lambda’s With Receivers
fun welcome() = sendCommandsToDevice {
appendBootstrap()
appendSelfCheck()
appendBeep(BeepCode.WELCOME)
}
fun resetDevice() = sendCommandsToDevice {
appendReset()
appendFlush()
}
Lambda’s With Receivers
private fun sendCommandsToDevice(instructions: ICommandBuilder.() -> Unit) {
val commands = ioPortDelegate
.createDeviceCommandBuilder()
.apply(instructions)
.commands
sendDeviceCommands(commands)
}
Lambdas With Receivers
sourceSets {
create("integrationTest") {
withConvention(KotlinSourceSet::class) {
kotlin.srcDir("src/integrationTest/kotlin")
resources.srcDir("src/integrationTest/resources")
compileClasspath += sourceSets["main"].output + configurations["testRuntimeClasspath"]
runtimeClasspath += output + compileClasspath + sourceSets["test"].runtimeClasspath
}
}
}
Lambdas With Receivers
fun <T> with(obj: T, f: T.() -> Unit) = obj.f()
class Tank {
fun forward(distance: Int) = println("Going forward $distance")
fun backward(distance: Int) = println("Going backward $distance")
fun turn(degrees: Int) = println("Turning $degrees degrees")
fun fire() = println("Firing cannon")
}
fun main() {
val tank = Tank()
with(tank) {
forward(200)
turn(45)
backward(50)
fire()
}
}
Lambdas With Receivers  Standard Utility Functions
Going forward 200
Turning 45 degrees
Going backward 50
Firing cannon
@kotlin.internal.InlineOnly
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return receiver.block()
}
Standard Utility Functions
with(navigationBar) {
navigationBarTitle.visibility = View.GONE
searchBar.visibility = View.VISIBLE
searchBar.inputType = inputType
searchBar.transformationMethod = null
}
Standard Utility Functions
Standard Utility Functions
Current Object
passed as receiver
Current Object
Returned
Result Of Block
Returned
Current Object
passed via ‘it’
with apply run
also let
val toast = Toast.makeText(context, message, duration).apply {
this.duration = duration
this.view = buildToastView(view, message)
this.setGravity(CENTER_VERTICAL, 0, Y_AXIS_OFFSET)
}
Standard Utility Functions
leftSwipe.let {
it.translationX += delta
it.translationX = limitInDistance(it.translationX)
}
rightSwipe.let {
it.translationX += delta
it.translationX = limitInDistance(it.translationX)
}
Standard Utility Functions
class MyThing {
var firstProp: Int = 123
var secondProp: Int
get() = firstProp * 2
set(value) {
firstProp = value / 2
}
var thirdProp by Delegate()
}
Delegated Properties
class Delegate {
private var value: String = "Homer“
operator fun getValue(thisRef: Any?,
property: KProperty<*>) : String {
println("---> Getting $value")
return value
}
operator fun setValue(thisRef: Any?,
property: KProperty<*>, value: String) {
println("---> Setting $value")
this.value = value
}
}
Delegated Properties
val saveButtonText: String by lazy {
resourceService.getStringResource(R.string.save)
}
val addButtonText: String by lazy {
resourceService.getStringResource(R.string.add)
}
val cancelButtonText: String by lazy {
resourceService.getStringResource(R.string.cancel)
}
Delegated Properties
Note the type
A lazy object manages the initialisation but it
is consumed as a simple string
fun <T> weak(value: T? = null) = WeakReferenceDelegate(value)
class WeakReferenceDelegate<T>(value: T?) {
private var weakReference = WeakReference(value)
operator fun getValue(thisRef: Any,
prop: KProperty<*>): T? = weakReference.get()
operator fun setValue(thisRef: Any, prop: KProperty<*>, value: T) {
weakReference = WeakReference(value)
}
}
Delegated Properties
Delegated Properties
private var dialog: InProgressDialog? by weak()
Note the type
A WeakReferenceDelegate object manages the
WeakReference but it is read and written as the inner type
abstract class BaseActivity<ViewModelType : ActivityViewModel>
: AppCompatActivity(),
DisposableManager,
CoroutineScope by MainScope() {
. . .
}
Implementation by Delegation
Extensions allow us write more expressive code
They also help us create Domain Specific Languages
Extension Functions
deviceStatusStream()
.filterForErrors()
.collate().and()
.send()
private fun Observable<Long>.runningAverage(bufferSize: Int) =
this.buffer(bufferSize, 1)
.map { round(it.average()) }
Extension Functions
private val currentHardwareOffsets =
liveSession.hwTimeStamps
.timestamp(TimeUnit.MILLISECONDS, scheduler)
.map { it.time() - it.value().timestampMilliseconds }
.runningAverage(5)
Extension Functions
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAlignment="center"/>
TextView titleView = activity.findViewById<TextView>(R.id.title)
titleView.text = "Hello World!"
title.text = "Hello World!"
Extension Functions
Kotlin Android Extensions provides this
It most cases it will cache to avoid multiple calls to findViewById
Null Safety
private fun processUserPolicy(user: User) {
val policy = user.policy
if (policy.isComplete) {
policyProcessor.process(policy)
}
}
private static void processUserPolicy(User user) {
if (user != null && user.getPolicy() != null) {
Policy policy = user.getPolicy();
if (policy.isComplete()) {
policyProcessor.process(policy);
}
}
}
Java
Kotlin
Words from the Wise
“What's a null pointer exception?"
Aaron Finn, Associate Software Engineer, Instil
@BindingAdapter("onEnterKeyPressed")
fun onEnterKeyPressed(editText: EditText, runnable: Runnable?) {
editText.setOnKeyListener { view, keyCode, _ ->
if (keyCode == KeyEvent.KEYCODE_ENTER) {
view.hideKeyboard()
view.clearFocus()
runnable?.run()
true
} else {
false
}
}
}
Null Safety (Plus Friends)
Safe Call Operator
<androidx.appcompat.widget.AppCompatEditText
app:onEnterKeyPressed="@{() -> vm.activate()}"
@BindingAdapter("onEnterKeyPressed")
fun onEnterKeyPressed(editText: EditText, runnable: Runnable?) {
editText.setOnKeyListener { view, keyCode, _ ->
if (keyCode == KeyEvent.KEYCODE_ENTER) {
view.hideKeyboard()
view.clearFocus()
runnable?.run()
true
} else {
false
}
}
}
Null Safety (Plus Friends)
Top Level Function
<androidx.appcompat.widget.AppCompatEditText
app:onEnterKeyPressed="@{() -> vm.activate()}"
@BindingAdapter("onEnterKeyPressed")
fun onEnterKeyPressed(editText: EditText, runnable: Runnable?) {
editText.setOnKeyListener { view, keyCode, _ ->
if (keyCode == KeyEvent.KEYCODE_ENTER) {
view.hideKeyboard()
view.clearFocus()
runnable?.run()
true
} else {
false
}
}
}
Null Safety (Plus Friends)
<androidx.appcompat.widget.AppCompatEditText
app:onEnterKeyPressed="@{() -> vm.activate()}"
Extension Method
@BindingAdapter("onEnterKeyPressed")
fun onEnterKeyPressed(editText: EditText, runnable: Runnable?) {
editText.setOnKeyListener { view, keyCode, _ ->
if (keyCode == KeyEvent.KEYCODE_ENTER) {
view.hideKeyboard()
view.clearFocus()
runnable?.run()
true
} else {
false
}
}
}
Null Safety (Plus Friends)
If as an expression
<androidx.appcompat.widget.AppCompatEditText
app:onEnterKeyPressed="@{() -> vm.activate()}"
@BindingAdapter("onEnterKeyPressed")
fun onEnterKeyPressed(editText: EditText, runnable: Runnable?) {
editText.setOnKeyListener { view, keyCode, _ ->
if (keyCode == KeyEvent.KEYCODE_ENTER) {
view.hideKeyboard()
view.clearFocus()
runnable?.run()
true
} else {
false
}
}
}
Null Safety (Plus Friends)
If as an expression
<androidx.appcompat.widget.AppCompatEditText
app:onEnterKeyPressed="@{() -> vm.activate()}"
Extension Method
Top Level Function
Safe Call Operator
leftSwipe.let {
it.translationX += delta
it.translationX = limitInDistance(it.translationX)
}
rightSwipe.let {
it.translationX += delta
it.translationX = limitInDistance(it.translationX)
}
Standard Utility Functions
leftSwipe?.let {
it.translationX += delta
it.translationX = limitInDistance(it.translationX)
}
rightSwipe?.let {
it.translationX += delta
it.translationX = limitInDistance(it.translationX)
}
Standard Utility Functions
Null safety and immutability are great
Some scenarios are a little messier
• Reading in untyped JSON
• DI injected values
Kotlin has lots of ways of help
• Good tooling
• lateinit
• lazy
Null Safety in Reality
One is your locker. The other is a garbage dump in the
Philippines
This one’s the dump They’re both your locker
val saveButtonText: String by lazy {
resourceService.getStringResource(R.string.save)
}
@Inject lateinit var loginViewModel: LoginViewModel
@Inject lateinit var approvalViewModel: ApprovalViewModel
@Inject lateinit var transferViewModel: TransferViewModel
@Inject lateinit var resourceService: ResourceService
Null Safety in Reality
data class Reward(
@JsonProperty("type") val type: RewardType,
@JsonProperty("points") val points: Int,
@JsonProperty("name") val name: String,
@JsonProperty("eligible") val eligible: Boolean,
)
Null Safety in Reality
Non-nullable vals can be used when working with JSON
Retrofit uses Jackson Object Mapper (which has a Kotlin specific module)
Introducing Coroutines
suspend fun doWork() {
disableUI()
val exchangeRates = readExchangeRate()
val report = buildReport(exchangeRates)
saveReport(report)
enableUI()
}
fun doWork() {
disableUI()
val exchangeRates = readExchangeRate()
val report = buildReport(exchangeRates)
saveReport(report)
enableUI()
}
Introducing Coroutines
suspend fun doWork() {
disableUI()
val exchangeRates = readExchangeRate()
val report = buildReport(exchangeRates)
saveReport(report)
enableUI()
}
suspend
suspend
suspend
return
Introducing Coroutines
suspend fun doWorkWithThreadControl() {
disableUI()
withContext(Dispatchers.IO) {
val exchangeRates = readExchangeRate()
val report = buildReport(exchangeRates)
saveReport(report)
}
enableUI()
}
1 1 2 2 3 3 4 4 5 5 6 6 7 7
1
1
2
2
3
3
4
4
5
5
6
6
7
7
Historically we had used RxJava extensively
• To bypass standard features like AsyncTask
With Kotlin, we’ve used RxKotlin heavily too
We started using coroutines when they were experimental
• We’ve found lots of code can be simplified by coroutines
We still use Rx when what we’re modelling is intuitively a stream
Using Coroutines
private suspend fun processUpdateRequest(update: Update,
requestOptions: RequestOptions) {
val customer = customerService.customerDetails(update.customerId)
val transaction = transactionBuilder.build(requestOptions)
transaction.customer = customer
customerSaleService.updateTransactionWithCustomer(transaction)
val updateCopy = update.createCopy()
transactionDao.save(transaction)
eventBus.requestComplete(transaction, update)
}
Using Coroutines
Realm threading restrictions were painful
Required specific threads for work
Coroutines made the threading easier
Using Coroutines
private fun fetchAndPersistSettings() = async(networkDispatcher) {
val settings = fetchSettings()
realmWrite { realm ->
updateDao.overwrite(realm, settings)
}
}
We experimented with Kotlin Test but reverted to JUnit
• We were looking at Spek with Kotlin support but encountered issues
Some Java interop requires back ticking to avoid language clashes
What Were The Pain Points?
@Test
fun shouldConvertBytesHeldAsPositiveToPositiveIntegers() {
assertThat(1.toByte().toPositiveInt(), `is`(equalTo(1)))
assertThat(12.toByte().toPositiveInt(), `is`(equalTo(12)))
assertThat(123.toByte().toPositiveInt(), `is`(equalTo(123)))
assertThat(127.toByte().toPositiveInt(), `is`(equalTo(127)))
}
doReturn("$20.00").`when`(monetaryFormatter).format(Monetary.TWENTY)
doReturn("$5.00").`when`(monetaryFormatter).format(Monetary.FIVE)
Documentation in some areas are lacking
• When features are experimental or very new
• Requires trial and error
• Some best practices would be nice
• Only happy paths shown e.g. Kotlin Gradle DSL
• Internally, some teams use and others have avoided
We saw some collisions in some Java class names
• But Kotlin type aliases came to rescue here
What Were The Pain Points?
Not too much “caught” us out but some things we would do differently
Some of this and the pain points are simply timing
• Better libraries and library support came later
• Language features stabilised e.g. coroutines
More and more libraries are writing Kotlin wrappers or Kotlin first interfaces
• Android, Realm, Apache Beam, Spring etc
Modern development requires so many dependencies – constant evolution
What Would We Do Differently?
Dagger  Koin
Retrofit  Rx style migrated to coroutines
Realm  Room
Glide  Coil (coroutine support)
Junit  Kotlin Test and AssertJ
Espresso Spoon, Awaitility
• These are just nicer with Kotlin
Frameworks We Used Or Would Use
We write quite a few multi-platform apps using Xamarin
• This is a good, stable, cross platform solution for writing native apps
We are keeping an eye on Kotlin Native
• Still in beta but with a lot of potential
Could allow us to write more Kotlin (yeah!) making Android easier
• But leveraging the same code for iOS
Kotlin Native
One to watch
Your existing skills remain relevant
The learning curve is gentle and straightforward
Interns and grads pick it up in no time
Developers with Java, C# & Swift experience adopt it very easily
The only pain is when go back to Java 
In Summary
Words from the Wise
“As a services business we need to focus primarily on
our customers needs. Thankfully, it's not just our
developers that have grown to love the language. Our
customers are in turn getting more maintainable
software to market with lower lead times.”
Matt McComb, Director of Business Development, Instil
Questions?
Kotlin for Android - Goto Copenhagan 2019

More Related Content

Similar to Kotlin for Android - Goto Copenhagan 2019

Kotlin Native - C / Swift Interop - ACCU Autmn 2019
Kotlin Native - C / Swift Interop - ACCU Autmn 2019Kotlin Native - C / Swift Interop - ACCU Autmn 2019
Kotlin Native - C / Swift Interop - ACCU Autmn 2019Eamonn Boyle
 
Kotlin for all the Things
Kotlin for all the ThingsKotlin for all the Things
Kotlin for all the ThingsEamonn Boyle
 
MOOC_PRESENTATION_KOTLIN[1].pptx
MOOC_PRESENTATION_KOTLIN[1].pptxMOOC_PRESENTATION_KOTLIN[1].pptx
MOOC_PRESENTATION_KOTLIN[1].pptxkamalkantmaurya1
 
Kotlin Language powerpoint show file
Kotlin Language powerpoint show fileKotlin Language powerpoint show file
Kotlin Language powerpoint show fileSaurabh Tripathi
 
Programming with Kotlin
Programming with KotlinProgramming with Kotlin
Programming with KotlinDavid Gassner
 
DevNight #1 (Kotlin) @ The Brick Space
DevNight #1 (Kotlin) @ The Brick SpaceDevNight #1 (Kotlin) @ The Brick Space
DevNight #1 (Kotlin) @ The Brick SpaceJedsada Tiwongvokul
 
Down With JavaScript!
Down With JavaScript!Down With JavaScript!
Down With JavaScript!Garth Gilmour
 
Kotlin for Android Developers - 1
Kotlin for Android Developers - 1Kotlin for Android Developers - 1
Kotlin for Android Developers - 1Mohamed Nabil, MSc.
 
Developers’ mDay u Banjoj Luci - Duško Bajić, Kotlin User Group Bosnia – Kotl...
Developers’ mDay u Banjoj Luci - Duško Bajić, Kotlin User Group Bosnia – Kotl...Developers’ mDay u Banjoj Luci - Duško Bajić, Kotlin User Group Bosnia – Kotl...
Developers’ mDay u Banjoj Luci - Duško Bajić, Kotlin User Group Bosnia – Kotl...mCloud
 
KOTLIN VS. JAVA WHICH ONE IS BEST FOR ANDROID DEVELOPMENT.pptx
KOTLIN VS. JAVA WHICH ONE IS BEST FOR ANDROID DEVELOPMENT.pptxKOTLIN VS. JAVA WHICH ONE IS BEST FOR ANDROID DEVELOPMENT.pptx
KOTLIN VS. JAVA WHICH ONE IS BEST FOR ANDROID DEVELOPMENT.pptxShantanuApurva1
 
Say Goodbye To Java: Getting Started With Kotlin For Android Development
Say Goodbye To Java: Getting Started With Kotlin For Android DevelopmentSay Goodbye To Java: Getting Started With Kotlin For Android Development
Say Goodbye To Java: Getting Started With Kotlin For Android DevelopmentAdam Magaña
 
Dear Kotliners - Java Developers are Humans too
Dear Kotliners - Java Developers are Humans tooDear Kotliners - Java Developers are Humans too
Dear Kotliners - Java Developers are Humans tooVivek Chanddru
 
Kevin Whinnery: Write Better JavaScript
Kevin Whinnery: Write Better JavaScriptKevin Whinnery: Write Better JavaScript
Kevin Whinnery: Write Better JavaScriptAxway Appcelerator
 
Paris Web - Javascript as a programming language
Paris Web - Javascript as a programming languageParis Web - Javascript as a programming language
Paris Web - Javascript as a programming languageMarco Cedaro
 
'Full Stack Kotlin' Workshop at KotlinConf
'Full Stack Kotlin' Workshop at KotlinConf'Full Stack Kotlin' Workshop at KotlinConf
'Full Stack Kotlin' Workshop at KotlinConfGarth Gilmour
 
Enterprise Strength Mobile JavaScript
Enterprise Strength Mobile JavaScriptEnterprise Strength Mobile JavaScript
Enterprise Strength Mobile JavaScriptTroy Miles
 
Introduction to Android- A session by Sagar Das
Introduction to Android-  A session by Sagar DasIntroduction to Android-  A session by Sagar Das
Introduction to Android- A session by Sagar Dasdscfetju
 
Kotlin vs Java | A Comparative Analysis | IDEA USHER
Kotlin vs Java | A Comparative Analysis | IDEA USHERKotlin vs Java | A Comparative Analysis | IDEA USHER
Kotlin vs Java | A Comparative Analysis | IDEA USHERNitish Garg
 
Kotlin Overview
Kotlin OverviewKotlin Overview
Kotlin OverviewEkta Raj
 

Similar to Kotlin for Android - Goto Copenhagan 2019 (20)

Kotlin Native - C / Swift Interop - ACCU Autmn 2019
Kotlin Native - C / Swift Interop - ACCU Autmn 2019Kotlin Native - C / Swift Interop - ACCU Autmn 2019
Kotlin Native - C / Swift Interop - ACCU Autmn 2019
 
Kotlin for all the Things
Kotlin for all the ThingsKotlin for all the Things
Kotlin for all the Things
 
MOOC_PRESENTATION_KOTLIN[1].pptx
MOOC_PRESENTATION_KOTLIN[1].pptxMOOC_PRESENTATION_KOTLIN[1].pptx
MOOC_PRESENTATION_KOTLIN[1].pptx
 
moocs_ppt.pptx
moocs_ppt.pptxmoocs_ppt.pptx
moocs_ppt.pptx
 
Kotlin Language powerpoint show file
Kotlin Language powerpoint show fileKotlin Language powerpoint show file
Kotlin Language powerpoint show file
 
Programming with Kotlin
Programming with KotlinProgramming with Kotlin
Programming with Kotlin
 
DevNight #1 (Kotlin) @ The Brick Space
DevNight #1 (Kotlin) @ The Brick SpaceDevNight #1 (Kotlin) @ The Brick Space
DevNight #1 (Kotlin) @ The Brick Space
 
Down With JavaScript!
Down With JavaScript!Down With JavaScript!
Down With JavaScript!
 
Kotlin for Android Developers - 1
Kotlin for Android Developers - 1Kotlin for Android Developers - 1
Kotlin for Android Developers - 1
 
Developers’ mDay u Banjoj Luci - Duško Bajić, Kotlin User Group Bosnia – Kotl...
Developers’ mDay u Banjoj Luci - Duško Bajić, Kotlin User Group Bosnia – Kotl...Developers’ mDay u Banjoj Luci - Duško Bajić, Kotlin User Group Bosnia – Kotl...
Developers’ mDay u Banjoj Luci - Duško Bajić, Kotlin User Group Bosnia – Kotl...
 
KOTLIN VS. JAVA WHICH ONE IS BEST FOR ANDROID DEVELOPMENT.pptx
KOTLIN VS. JAVA WHICH ONE IS BEST FOR ANDROID DEVELOPMENT.pptxKOTLIN VS. JAVA WHICH ONE IS BEST FOR ANDROID DEVELOPMENT.pptx
KOTLIN VS. JAVA WHICH ONE IS BEST FOR ANDROID DEVELOPMENT.pptx
 
Say Goodbye To Java: Getting Started With Kotlin For Android Development
Say Goodbye To Java: Getting Started With Kotlin For Android DevelopmentSay Goodbye To Java: Getting Started With Kotlin For Android Development
Say Goodbye To Java: Getting Started With Kotlin For Android Development
 
Dear Kotliners - Java Developers are Humans too
Dear Kotliners - Java Developers are Humans tooDear Kotliners - Java Developers are Humans too
Dear Kotliners - Java Developers are Humans too
 
Kevin Whinnery: Write Better JavaScript
Kevin Whinnery: Write Better JavaScriptKevin Whinnery: Write Better JavaScript
Kevin Whinnery: Write Better JavaScript
 
Paris Web - Javascript as a programming language
Paris Web - Javascript as a programming languageParis Web - Javascript as a programming language
Paris Web - Javascript as a programming language
 
'Full Stack Kotlin' Workshop at KotlinConf
'Full Stack Kotlin' Workshop at KotlinConf'Full Stack Kotlin' Workshop at KotlinConf
'Full Stack Kotlin' Workshop at KotlinConf
 
Enterprise Strength Mobile JavaScript
Enterprise Strength Mobile JavaScriptEnterprise Strength Mobile JavaScript
Enterprise Strength Mobile JavaScript
 
Introduction to Android- A session by Sagar Das
Introduction to Android-  A session by Sagar DasIntroduction to Android-  A session by Sagar Das
Introduction to Android- A session by Sagar Das
 
Kotlin vs Java | A Comparative Analysis | IDEA USHER
Kotlin vs Java | A Comparative Analysis | IDEA USHERKotlin vs Java | A Comparative Analysis | IDEA USHER
Kotlin vs Java | A Comparative Analysis | IDEA USHER
 
Kotlin Overview
Kotlin OverviewKotlin Overview
Kotlin Overview
 

More from Eamonn Boyle

2019-06 - Goto Amsterdam - Microservices
2019-06 - Goto Amsterdam - Microservices2019-06 - Goto Amsterdam - Microservices
2019-06 - Goto Amsterdam - MicroservicesEamonn Boyle
 
2019-01-29 - Demystifying Kotlin Coroutines
2019-01-29 - Demystifying Kotlin Coroutines2019-01-29 - Demystifying Kotlin Coroutines
2019-01-29 - Demystifying Kotlin CoroutinesEamonn Boyle
 
BelTech 2017 - Building Quality in the Browser
BelTech 2017 - Building Quality in the BrowserBelTech 2017 - Building Quality in the Browser
BelTech 2017 - Building Quality in the BrowserEamonn Boyle
 
ASP .Net Core SPA Templates
ASP .Net Core SPA TemplatesASP .Net Core SPA Templates
ASP .Net Core SPA TemplatesEamonn Boyle
 
Being Expressive in Code
Being Expressive in CodeBeing Expressive in Code
Being Expressive in CodeEamonn Boyle
 
2018-09 - F# and Fable
2018-09 - F# and Fable2018-09 - F# and Fable
2018-09 - F# and FableEamonn Boyle
 

More from Eamonn Boyle (6)

2019-06 - Goto Amsterdam - Microservices
2019-06 - Goto Amsterdam - Microservices2019-06 - Goto Amsterdam - Microservices
2019-06 - Goto Amsterdam - Microservices
 
2019-01-29 - Demystifying Kotlin Coroutines
2019-01-29 - Demystifying Kotlin Coroutines2019-01-29 - Demystifying Kotlin Coroutines
2019-01-29 - Demystifying Kotlin Coroutines
 
BelTech 2017 - Building Quality in the Browser
BelTech 2017 - Building Quality in the BrowserBelTech 2017 - Building Quality in the Browser
BelTech 2017 - Building Quality in the Browser
 
ASP .Net Core SPA Templates
ASP .Net Core SPA TemplatesASP .Net Core SPA Templates
ASP .Net Core SPA Templates
 
Being Expressive in Code
Being Expressive in CodeBeing Expressive in Code
Being Expressive in Code
 
2018-09 - F# and Fable
2018-09 - F# and Fable2018-09 - F# and Fable
2018-09 - F# and Fable
 

Recently uploaded

What Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the SituationWhat Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the SituationJuha-Pekka Tolvanen
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...SelfMade bd
 
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...WSO2
 
%in Benoni+277-882-255-28 abortion pills for sale in Benoni
%in Benoni+277-882-255-28 abortion pills for sale in Benoni%in Benoni+277-882-255-28 abortion pills for sale in Benoni
%in Benoni+277-882-255-28 abortion pills for sale in Benonimasabamasaba
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplatePresentation.STUDIO
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...masabamasaba
 
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...chiefasafspells
 
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...Jittipong Loespradit
 
Announcing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareAnnouncing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareJim McKeeth
 
Artyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptxArtyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptxAnnaArtyushina1
 
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...Bert Jan Schrijver
 
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfonteinmasabamasaba
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrandmasabamasaba
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...Health
 
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024VictoriaMetrics
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisamasabamasaba
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisamasabamasaba
 
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...WSO2
 
WSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2
 
Architecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastArchitecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastPapp Krisztián
 

Recently uploaded (20)

What Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the SituationWhat Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the Situation
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
 
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
 
%in Benoni+277-882-255-28 abortion pills for sale in Benoni
%in Benoni+277-882-255-28 abortion pills for sale in Benoni%in Benoni+277-882-255-28 abortion pills for sale in Benoni
%in Benoni+277-882-255-28 abortion pills for sale in Benoni
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
 
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
 
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
 
Announcing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareAnnouncing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK Software
 
Artyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptxArtyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptx
 
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
 
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
 
WSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go Platformless
 
Architecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastArchitecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the past
 

Kotlin for Android - Goto Copenhagan 2019

  • 1. Transitioning Android Teams Into Kotlin Garth Gilmour (@GarthGilmour) Eamonn Boyle (@BoyleEamonn)
  • 2. Me
  • 3. Him
  • 4. Us
  • 5. 2018 was a very significant year • For developers on the JVM We stopped asking: • “Why aren’t you doing this in Java?” We started asking: • “Why are you doing this in Java?” The revolution is actualised • It’s a polyglot coding world now • …and there’s no going back This Talk Is (Maybe) Slightly Out Of Date
  • 6. “You thought Android devs still used Java”
  • 7. They still are? Inconceivable!
  • 8. This talk assumes: • You know Java and Android • You have the scars to prove it We will convince you that: • There is a better way • Kotlin is that way A Veteran’s Guide To Moving Android Teams To Kotlin
  • 9. Excellent interoperability • Call legacy Java code easily • Make calls into Kotlin from Java Really clear, yet concise syntax • Reduces the codebase by over 40% Beloved by frameworks • Spring Boot (esp. with Kofu) • Services (Ktor and Http4k) • User Interfaces (TornadoFx) • Build tools (Gradle from V5) • Dependency Injection (Koin) Why Code In Kotlin? Null Safety String Templates Default parameters Extensions Free Functions Coroutines Single Expression Functions Reified generics Data classes and Properties Type Inference Smart Casts Operator overloading
  • 10. public class Program { public static void main(String[] args) { List<String> data = Arrays.asList( "ab","cde","fghi","jklmn", "op","qrs","tuvw","xyz"); data.stream() .flatMapToInt(CharSequence::chars) .mapToObj(num -> (char)num) .forEach(c -> System.out.printf("%s ", c)); } } Let’s Print The Alphabet - In Java a b c d e f g h i j k l m n o p q r s t u v w x y z
  • 11. fun main() { val data = listOf( "ab","cde","fghi","jklmn", "op","qrs","tuvw","xyz") data.flatMap { it.toList() } .forEach { print("$it ") } } Let’s Print The Alphabet - In Kotlin a b c d e f g h i j k l m n o p q r s t u v w x y z
  • 12. Why Use Kotlin On Android? “Today we’re announcing another big step: Android development will become increasingly Kotlin-first. Many new Jetpack APIs and features will be offered first in Kotlin. If you’re starting a new project, you should write it in Kotlin;” Google I/O 2019
  • 13. Codebase reduction by 40% (JetBrains figure) Simplify the remaining code Plaster over Androids cracks Access FP features / patterns (Java 8+) Future proof your skill set Developer happiness  Why Use Kotlin On Android?
  • 14. We’ve written an awful lot of code… • Especially mobile applications with complex networking • Also embedded systems, web applications etc... For an awful lot of clients… • Atlassian, Johnson Controls, Shopkeep, Cybersource On every platform you’ve ever heard of • Plus (if you were lucky) a few you managed to avoid We switched to Kotlin four years ago • For all applications built on top of the JVM • Plus we are experimenting with Native and JS Why Listen To Us?
  • 15. Instil is a JetBrains training partner • Written 3 Kotlin courses so far We have delivered training for • Household names (Europe and US) • Brand new start-ups We believe Kotlin will help you write better solutions • Engineering Expertise is part of our ethos and Kotlin helps us • We believe in improving development practices within our community We started the Kotlin Belfast User Group • We promote it to help people, not to make money Why Listen To Us?
  • 16. We don’t get royalties from JetBrains or Google We’re placing a bet on Kotlin being the future Why Listen To Us?
  • 17. • What motivated us to switch? • How did we make the move? • Which features do we love? • What problems did we face? • Did we require new frameworks? • What would we do differently? • Are coroutines of any use? * Questions To Answer * we want to talk about coroutines because they're awesome…
  • 18. Prior to Kotlin we had written: • iOS mobile apps in Objective-C and Swift • Cross-platform mobile apps in Xamarin • Standard desktop apps in C / C++ / C# • Web applications in just about everything • JEE in all its incarnations (including EJB) • Spring from the earliest days to WebFlux We were tendering for some major Android jobs • The developers didn’t want to use Java • They really didn’t want to use Java What Motivated Us?
  • 19. Words From The Wise “I do not like this Java lang I do not like it, business man It does not suit our software house It makes me sad to click the mouse I will not code it here or there It sucks for Android anywhere” David Robert Seuss, Software Engineer (personal conversation with our CEO)
  • 20. We had a problem on the Java Virtual Machine • Kotlin was a pragmatic solution By todays standards Java is not great • But lots of great software is written in it We still leverage our historical knowledge • By remaining within the JVM ecosystem What Motivated Us? Java Kotlin
  • 21. Words from the Wise “Making the switch from Java to Kotlin was easy - being able to use the same tools and libraries that we knew and loved meant that we felt productive in Kotlin almost immediately. Over time, our code then became simpler, more stable and more performant as we started to experiment with the Kotlin functional toolkit and coroutines.” Chris van Es, Head of Engineering, Instil
  • 22. Words from the Wise “Working in Java is a fantastic developer experience because you can use Kotlin.” Kelvin Harron, Software Engineer, Instil “Kotlin negates the biggest weakness of the Java Ecosystem, i.e. Java.” Eoin Mullan, Principal Software Engineer, Instil
  • 23. The Community Was Going That Way
  • 24. We wanted an epic, heroic tale of a warrior’s struggle to final victory
  • 25. It was less Kill Bill, and more Kill Kenny – very easy
  • 27. Kotlin’s interop story is awesome • @Throws (adds checked exception) • @JvmOverloads (for default params) • @JvmName (rename most things) • @JvmWildcard (manage generics) Interop never caused serious disruption • But it was reassuring to know we had low level control should it be needed • Emotional Support Annotations  In Case Of Interoperability Emergency…
  • 29. Basic Class Design public class Movie { private String title; private String description; private Rating rating; private Genre genre; }
  • 30. Basic Class Design public class Movie { private String title; private String description; private Rating rating; private Genre genre; public Movie(String title, String description, Rating rating, Genre genre) { this.title = title; this.description = description; this.rating = rating; this.genre = genre; } }
  • 31. Basic Class Design public class Movie { private String title; private String description; private Rating rating; private Genre genre; public Movie(String title, String description, Rating rating, Genre genre) { this.title = title; this.description = description; this.rating = rating; this.genre = genre; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; }
  • 32. Basic Class Design public class Movie { private String title; private String description; private Rating rating; private Genre genre; public Movie(String title, String description, Rating rating, Genre genre) { this.title = title; this.description = description; this.rating = rating; this.genre = genre; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public Rating getRating() { return rating; } public void setRating(Rating rating) { this.rating = rating; } public Genre getGenre() { return genre; } public void setGenre(Genre genre) { this.genre = genre; } } class Movie(var title: String, var description: String, var rating: Rating, var genre: Genre) { }
  • 33. Basic Class Design import java.util.Objects; public class Movie { private String title; private String description; private Rating rating; private Genre genre; public Movie(String title, String description, Rating rating, Genre genre) { this.title = title; this.description = description; this.rating = rating; this.genre = genre; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public Rating getRating() { return rating; } public void setRating(Rating rating) { this.rating = rating; } public Genre getGenre() { return genre; } public void setGenre(Genre genre) { this.genre = genre; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Movie movie = (Movie) o; return Objects.equals(title, movie.title) && Objects.equals(description, movie.description) && Objects.equals(rating, movie.rating) && Objects.equals(genre, movie.genre); } @Override public int hashCode() { return Objects.hash(title, description, rating, genre); } @Override public String toString() { return "Movie{" + "title='" + title + ''' + ", description='" + description + ''' + ", rating=" + rating + ", genre=" + genre + '}'; } } data class Movie(var title: String, var description: String, var rating: Rating, var genre: Genre) { } But what if we need: • Equality • Hashing • Copying • Decomposition
  • 34. menu { submenu(“Setup") { item(“Edit Details", ::editDetails) item(“Reset Password", ::resetPassword) } submenu(“Sessions") { item(“Create New Session", ::createNewSession) item(“View All Sessions", ::viewall) item(“Synchronize", ::synchronize) } Lambda’s With Receivers
  • 35. fun menu(builder: Menu.() -> Unit) = Menu(builder) class Menu(builder: Menu.() -> Unit) { init { this.builder() } fun submenu(description: String, builder: Menu.() -> Unit) { ... } fun item(description: String, action: Action) { ... } . . . } Lambda’s With Receivers
  • 36. fun welcome() = sendCommandsToDevice { appendBootstrap() appendSelfCheck() appendBeep(BeepCode.WELCOME) } fun resetDevice() = sendCommandsToDevice { appendReset() appendFlush() } Lambda’s With Receivers
  • 37. private fun sendCommandsToDevice(instructions: ICommandBuilder.() -> Unit) { val commands = ioPortDelegate .createDeviceCommandBuilder() .apply(instructions) .commands sendDeviceCommands(commands) } Lambdas With Receivers
  • 38. sourceSets { create("integrationTest") { withConvention(KotlinSourceSet::class) { kotlin.srcDir("src/integrationTest/kotlin") resources.srcDir("src/integrationTest/resources") compileClasspath += sourceSets["main"].output + configurations["testRuntimeClasspath"] runtimeClasspath += output + compileClasspath + sourceSets["test"].runtimeClasspath } } } Lambdas With Receivers
  • 39. fun <T> with(obj: T, f: T.() -> Unit) = obj.f() class Tank { fun forward(distance: Int) = println("Going forward $distance") fun backward(distance: Int) = println("Going backward $distance") fun turn(degrees: Int) = println("Turning $degrees degrees") fun fire() = println("Firing cannon") } fun main() { val tank = Tank() with(tank) { forward(200) turn(45) backward(50) fire() } } Lambdas With Receivers  Standard Utility Functions Going forward 200 Turning 45 degrees Going backward 50 Firing cannon
  • 40. @kotlin.internal.InlineOnly public inline fun <T, R> with(receiver: T, block: T.() -> R): R { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } return receiver.block() } Standard Utility Functions
  • 41. with(navigationBar) { navigationBarTitle.visibility = View.GONE searchBar.visibility = View.VISIBLE searchBar.inputType = inputType searchBar.transformationMethod = null } Standard Utility Functions
  • 42. Standard Utility Functions Current Object passed as receiver Current Object Returned Result Of Block Returned Current Object passed via ‘it’ with apply run also let
  • 43. val toast = Toast.makeText(context, message, duration).apply { this.duration = duration this.view = buildToastView(view, message) this.setGravity(CENTER_VERTICAL, 0, Y_AXIS_OFFSET) } Standard Utility Functions
  • 44. leftSwipe.let { it.translationX += delta it.translationX = limitInDistance(it.translationX) } rightSwipe.let { it.translationX += delta it.translationX = limitInDistance(it.translationX) } Standard Utility Functions
  • 45. class MyThing { var firstProp: Int = 123 var secondProp: Int get() = firstProp * 2 set(value) { firstProp = value / 2 } var thirdProp by Delegate() } Delegated Properties
  • 46. class Delegate { private var value: String = "Homer“ operator fun getValue(thisRef: Any?, property: KProperty<*>) : String { println("---> Getting $value") return value } operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) { println("---> Setting $value") this.value = value } } Delegated Properties
  • 47. val saveButtonText: String by lazy { resourceService.getStringResource(R.string.save) } val addButtonText: String by lazy { resourceService.getStringResource(R.string.add) } val cancelButtonText: String by lazy { resourceService.getStringResource(R.string.cancel) } Delegated Properties Note the type A lazy object manages the initialisation but it is consumed as a simple string
  • 48. fun <T> weak(value: T? = null) = WeakReferenceDelegate(value) class WeakReferenceDelegate<T>(value: T?) { private var weakReference = WeakReference(value) operator fun getValue(thisRef: Any, prop: KProperty<*>): T? = weakReference.get() operator fun setValue(thisRef: Any, prop: KProperty<*>, value: T) { weakReference = WeakReference(value) } } Delegated Properties
  • 49. Delegated Properties private var dialog: InProgressDialog? by weak() Note the type A WeakReferenceDelegate object manages the WeakReference but it is read and written as the inner type
  • 50. abstract class BaseActivity<ViewModelType : ActivityViewModel> : AppCompatActivity(), DisposableManager, CoroutineScope by MainScope() { . . . } Implementation by Delegation
  • 51. Extensions allow us write more expressive code They also help us create Domain Specific Languages Extension Functions deviceStatusStream() .filterForErrors() .collate().and() .send()
  • 52. private fun Observable<Long>.runningAverage(bufferSize: Int) = this.buffer(bufferSize, 1) .map { round(it.average()) } Extension Functions
  • 53. private val currentHardwareOffsets = liveSession.hwTimeStamps .timestamp(TimeUnit.MILLISECONDS, scheduler) .map { it.time() - it.value().timestampMilliseconds } .runningAverage(5) Extension Functions
  • 54. <TextView android:id="@+id/title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAlignment="center"/> TextView titleView = activity.findViewById<TextView>(R.id.title) titleView.text = "Hello World!" title.text = "Hello World!" Extension Functions Kotlin Android Extensions provides this It most cases it will cache to avoid multiple calls to findViewById
  • 55. Null Safety private fun processUserPolicy(user: User) { val policy = user.policy if (policy.isComplete) { policyProcessor.process(policy) } } private static void processUserPolicy(User user) { if (user != null && user.getPolicy() != null) { Policy policy = user.getPolicy(); if (policy.isComplete()) { policyProcessor.process(policy); } } } Java Kotlin
  • 56. Words from the Wise “What's a null pointer exception?" Aaron Finn, Associate Software Engineer, Instil
  • 57. @BindingAdapter("onEnterKeyPressed") fun onEnterKeyPressed(editText: EditText, runnable: Runnable?) { editText.setOnKeyListener { view, keyCode, _ -> if (keyCode == KeyEvent.KEYCODE_ENTER) { view.hideKeyboard() view.clearFocus() runnable?.run() true } else { false } } } Null Safety (Plus Friends) Safe Call Operator <androidx.appcompat.widget.AppCompatEditText app:onEnterKeyPressed="@{() -> vm.activate()}"
  • 58. @BindingAdapter("onEnterKeyPressed") fun onEnterKeyPressed(editText: EditText, runnable: Runnable?) { editText.setOnKeyListener { view, keyCode, _ -> if (keyCode == KeyEvent.KEYCODE_ENTER) { view.hideKeyboard() view.clearFocus() runnable?.run() true } else { false } } } Null Safety (Plus Friends) Top Level Function <androidx.appcompat.widget.AppCompatEditText app:onEnterKeyPressed="@{() -> vm.activate()}"
  • 59. @BindingAdapter("onEnterKeyPressed") fun onEnterKeyPressed(editText: EditText, runnable: Runnable?) { editText.setOnKeyListener { view, keyCode, _ -> if (keyCode == KeyEvent.KEYCODE_ENTER) { view.hideKeyboard() view.clearFocus() runnable?.run() true } else { false } } } Null Safety (Plus Friends) <androidx.appcompat.widget.AppCompatEditText app:onEnterKeyPressed="@{() -> vm.activate()}" Extension Method
  • 60. @BindingAdapter("onEnterKeyPressed") fun onEnterKeyPressed(editText: EditText, runnable: Runnable?) { editText.setOnKeyListener { view, keyCode, _ -> if (keyCode == KeyEvent.KEYCODE_ENTER) { view.hideKeyboard() view.clearFocus() runnable?.run() true } else { false } } } Null Safety (Plus Friends) If as an expression <androidx.appcompat.widget.AppCompatEditText app:onEnterKeyPressed="@{() -> vm.activate()}"
  • 61. @BindingAdapter("onEnterKeyPressed") fun onEnterKeyPressed(editText: EditText, runnable: Runnable?) { editText.setOnKeyListener { view, keyCode, _ -> if (keyCode == KeyEvent.KEYCODE_ENTER) { view.hideKeyboard() view.clearFocus() runnable?.run() true } else { false } } } Null Safety (Plus Friends) If as an expression <androidx.appcompat.widget.AppCompatEditText app:onEnterKeyPressed="@{() -> vm.activate()}" Extension Method Top Level Function Safe Call Operator
  • 62. leftSwipe.let { it.translationX += delta it.translationX = limitInDistance(it.translationX) } rightSwipe.let { it.translationX += delta it.translationX = limitInDistance(it.translationX) } Standard Utility Functions
  • 63. leftSwipe?.let { it.translationX += delta it.translationX = limitInDistance(it.translationX) } rightSwipe?.let { it.translationX += delta it.translationX = limitInDistance(it.translationX) } Standard Utility Functions
  • 64. Null safety and immutability are great Some scenarios are a little messier • Reading in untyped JSON • DI injected values Kotlin has lots of ways of help • Good tooling • lateinit • lazy Null Safety in Reality One is your locker. The other is a garbage dump in the Philippines This one’s the dump They’re both your locker
  • 65. val saveButtonText: String by lazy { resourceService.getStringResource(R.string.save) } @Inject lateinit var loginViewModel: LoginViewModel @Inject lateinit var approvalViewModel: ApprovalViewModel @Inject lateinit var transferViewModel: TransferViewModel @Inject lateinit var resourceService: ResourceService Null Safety in Reality
  • 66. data class Reward( @JsonProperty("type") val type: RewardType, @JsonProperty("points") val points: Int, @JsonProperty("name") val name: String, @JsonProperty("eligible") val eligible: Boolean, ) Null Safety in Reality Non-nullable vals can be used when working with JSON Retrofit uses Jackson Object Mapper (which has a Kotlin specific module)
  • 67. Introducing Coroutines suspend fun doWork() { disableUI() val exchangeRates = readExchangeRate() val report = buildReport(exchangeRates) saveReport(report) enableUI() } fun doWork() { disableUI() val exchangeRates = readExchangeRate() val report = buildReport(exchangeRates) saveReport(report) enableUI() }
  • 68. Introducing Coroutines suspend fun doWork() { disableUI() val exchangeRates = readExchangeRate() val report = buildReport(exchangeRates) saveReport(report) enableUI() } suspend suspend suspend return
  • 69. Introducing Coroutines suspend fun doWorkWithThreadControl() { disableUI() withContext(Dispatchers.IO) { val exchangeRates = readExchangeRate() val report = buildReport(exchangeRates) saveReport(report) } enableUI() }
  • 70. 1 1 2 2 3 3 4 4 5 5 6 6 7 7
  • 72. Historically we had used RxJava extensively • To bypass standard features like AsyncTask With Kotlin, we’ve used RxKotlin heavily too We started using coroutines when they were experimental • We’ve found lots of code can be simplified by coroutines We still use Rx when what we’re modelling is intuitively a stream Using Coroutines
  • 73. private suspend fun processUpdateRequest(update: Update, requestOptions: RequestOptions) { val customer = customerService.customerDetails(update.customerId) val transaction = transactionBuilder.build(requestOptions) transaction.customer = customer customerSaleService.updateTransactionWithCustomer(transaction) val updateCopy = update.createCopy() transactionDao.save(transaction) eventBus.requestComplete(transaction, update) } Using Coroutines
  • 74. Realm threading restrictions were painful Required specific threads for work Coroutines made the threading easier Using Coroutines private fun fetchAndPersistSettings() = async(networkDispatcher) { val settings = fetchSettings() realmWrite { realm -> updateDao.overwrite(realm, settings) } }
  • 75. We experimented with Kotlin Test but reverted to JUnit • We were looking at Spek with Kotlin support but encountered issues Some Java interop requires back ticking to avoid language clashes What Were The Pain Points? @Test fun shouldConvertBytesHeldAsPositiveToPositiveIntegers() { assertThat(1.toByte().toPositiveInt(), `is`(equalTo(1))) assertThat(12.toByte().toPositiveInt(), `is`(equalTo(12))) assertThat(123.toByte().toPositiveInt(), `is`(equalTo(123))) assertThat(127.toByte().toPositiveInt(), `is`(equalTo(127))) } doReturn("$20.00").`when`(monetaryFormatter).format(Monetary.TWENTY) doReturn("$5.00").`when`(monetaryFormatter).format(Monetary.FIVE)
  • 76. Documentation in some areas are lacking • When features are experimental or very new • Requires trial and error • Some best practices would be nice • Only happy paths shown e.g. Kotlin Gradle DSL • Internally, some teams use and others have avoided We saw some collisions in some Java class names • But Kotlin type aliases came to rescue here What Were The Pain Points?
  • 77. Not too much “caught” us out but some things we would do differently Some of this and the pain points are simply timing • Better libraries and library support came later • Language features stabilised e.g. coroutines More and more libraries are writing Kotlin wrappers or Kotlin first interfaces • Android, Realm, Apache Beam, Spring etc Modern development requires so many dependencies – constant evolution What Would We Do Differently?
  • 78. Dagger  Koin Retrofit  Rx style migrated to coroutines Realm  Room Glide  Coil (coroutine support) Junit  Kotlin Test and AssertJ Espresso Spoon, Awaitility • These are just nicer with Kotlin Frameworks We Used Or Would Use
  • 79. We write quite a few multi-platform apps using Xamarin • This is a good, stable, cross platform solution for writing native apps We are keeping an eye on Kotlin Native • Still in beta but with a lot of potential Could allow us to write more Kotlin (yeah!) making Android easier • But leveraging the same code for iOS Kotlin Native One to watch
  • 80. Your existing skills remain relevant The learning curve is gentle and straightforward Interns and grads pick it up in no time Developers with Java, C# & Swift experience adopt it very easily The only pain is when go back to Java  In Summary
  • 81. Words from the Wise “As a services business we need to focus primarily on our customers needs. Thankfully, it's not just our developers that have grown to love the language. Our customers are in turn getting more maintainable software to market with lower lead times.” Matt McComb, Director of Business Development, Instil