SlideShare a Scribd company logo
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
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?
Transitioning Android Teams Into Kotlin

More Related Content

Similar to Transitioning Android Teams Into Kotlin

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
Eamonn Boyle
 
Kotlin for all the Things
Kotlin for all the ThingsKotlin for all the Things
Kotlin for all the Things
Eamonn Boyle
 
MOOC_PRESENTATION_KOTLIN[1].pptx
MOOC_PRESENTATION_KOTLIN[1].pptxMOOC_PRESENTATION_KOTLIN[1].pptx
MOOC_PRESENTATION_KOTLIN[1].pptx
kamalkantmaurya1
 
moocs_ppt.pptx
moocs_ppt.pptxmoocs_ppt.pptx
moocs_ppt.pptx
kamalkantmaurya1
 
Kotlin Language powerpoint show file
Kotlin Language powerpoint show fileKotlin Language powerpoint show file
Kotlin Language powerpoint show file
Saurabh Tripathi
 
DevNight #1 (Kotlin) @ The Brick Space
DevNight #1 (Kotlin) @ The Brick SpaceDevNight #1 (Kotlin) @ The Brick Space
DevNight #1 (Kotlin) @ The Brick Space
Jedsada Tiwongvokul
 
Programming with Kotlin
Programming with KotlinProgramming with Kotlin
Programming with Kotlin
David Gassner
 
Kotlin for Android Developers - 1
Kotlin for Android Developers - 1Kotlin for Android Developers - 1
Kotlin for Android Developers - 1
Mohamed 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.pptx
ShantanuApurva1
 
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
Adam Magaña
 
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
Marco Cedaro
 
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
Vivek Chanddru
 
Kevin Whinnery: Write Better JavaScript
Kevin Whinnery: Write Better JavaScriptKevin Whinnery: Write Better JavaScript
Kevin Whinnery: Write Better JavaScript
Axway Appcelerator
 
'Full Stack Kotlin' Workshop at KotlinConf
'Full Stack Kotlin' Workshop at KotlinConf'Full Stack Kotlin' Workshop at KotlinConf
'Full Stack Kotlin' Workshop at KotlinConf
Garth Gilmour
 
Enterprise Strength Mobile JavaScript
Enterprise Strength Mobile JavaScriptEnterprise Strength Mobile JavaScript
Enterprise Strength Mobile JavaScript
Troy Miles
 
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
Nitish Garg
 
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
dscfetju
 
Kotlin Overview
Kotlin OverviewKotlin Overview
Kotlin Overview
Ekta Raj
 
What's new with Kotlin - Google IO18' extended Covenant University.
What's new with Kotlin - Google IO18' extended Covenant University.What's new with Kotlin - Google IO18' extended Covenant University.
What's new with Kotlin - Google IO18' extended Covenant University.
SimileoluwaAluko
 

Similar to Transitioning Android Teams Into Kotlin (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
 
DevNight #1 (Kotlin) @ The Brick Space
DevNight #1 (Kotlin) @ The Brick SpaceDevNight #1 (Kotlin) @ The Brick Space
DevNight #1 (Kotlin) @ The Brick Space
 
Programming with Kotlin
Programming with KotlinProgramming with Kotlin
Programming with Kotlin
 
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
 
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
 
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
 
'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
 
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
 
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 Overview
Kotlin OverviewKotlin Overview
Kotlin Overview
 
What's new with Kotlin - Google IO18' extended Covenant University.
What's new with Kotlin - Google IO18' extended Covenant University.What's new with Kotlin - Google IO18' extended Covenant University.
What's new with Kotlin - Google IO18' extended Covenant University.
 

More from Garth Gilmour

Compose in Theory
Compose in TheoryCompose in Theory
Compose in Theory
Garth Gilmour
 
Kotlin / Android Update
Kotlin / Android UpdateKotlin / Android Update
Kotlin / Android Update
Garth Gilmour
 
TypeScript Vs. KotlinJS
TypeScript Vs. KotlinJSTypeScript Vs. KotlinJS
TypeScript Vs. KotlinJS
Garth Gilmour
 
Shut Up And Eat Your Veg
Shut Up And Eat Your VegShut Up And Eat Your Veg
Shut Up And Eat Your Veg
Garth Gilmour
 
Lies Told By The Kotlin Compiler
Lies Told By The Kotlin CompilerLies Told By The Kotlin Compiler
Lies Told By The Kotlin Compiler
Garth Gilmour
 
A TypeScript Fans KotlinJS Adventures
A TypeScript Fans KotlinJS AdventuresA TypeScript Fans KotlinJS Adventures
A TypeScript Fans KotlinJS Adventures
Garth Gilmour
 
The Heat Death Of Enterprise IT
The Heat Death Of Enterprise ITThe Heat Death Of Enterprise IT
The Heat Death Of Enterprise IT
Garth Gilmour
 
Lies Told By The Kotlin Compiler
Lies Told By The Kotlin CompilerLies Told By The Kotlin Compiler
Lies Told By The Kotlin Compiler
Garth Gilmour
 
Type Driven Development with TypeScript
Type Driven Development with TypeScriptType Driven Development with TypeScript
Type Driven Development with TypeScript
Garth Gilmour
 
Generics On The JVM (What you don't know will hurt you)
Generics On The JVM (What you don't know will hurt you)Generics On The JVM (What you don't know will hurt you)
Generics On The JVM (What you don't know will hurt you)
Garth Gilmour
 
Using Kotlin, to Create Kotlin, to Teach Kotlin, in Space
Using Kotlin, to Create Kotlin,to Teach Kotlin,in SpaceUsing Kotlin, to Create Kotlin,to Teach Kotlin,in Space
Using Kotlin, to Create Kotlin, to Teach Kotlin, in Space
Garth Gilmour
 
Is Software Engineering A Profession?
Is Software Engineering A Profession?Is Software Engineering A Profession?
Is Software Engineering A Profession?
Garth Gilmour
 
Social Distancing is not Behaving Distantly
Social Distancing is not Behaving DistantlySocial Distancing is not Behaving Distantly
Social Distancing is not Behaving Distantly
Garth Gilmour
 
The Great Scala Makeover
The Great Scala MakeoverThe Great Scala Makeover
The Great Scala Makeover
Garth Gilmour
 
Simpler and Safer Java Types (via the Vavr and Lambda Libraries)
Simpler and Safer Java Types (via the Vavr and Lambda Libraries)Simpler and Safer Java Types (via the Vavr and Lambda Libraries)
Simpler and Safer Java Types (via the Vavr and Lambda Libraries)
Garth Gilmour
 
The Three Horse Race
The Three Horse RaceThe Three Horse Race
The Three Horse Race
Garth Gilmour
 
The Bestiary of Pure Functional Programming
The Bestiary of Pure Functional Programming The Bestiary of Pure Functional Programming
The Bestiary of Pure Functional Programming
Garth Gilmour
 
BelTech 2019 Presenters Workshop
BelTech 2019 Presenters WorkshopBelTech 2019 Presenters Workshop
BelTech 2019 Presenters Workshop
Garth Gilmour
 
Kotlin The Whole Damn Family
Kotlin The Whole Damn FamilyKotlin The Whole Damn Family
Kotlin The Whole Damn Family
Garth Gilmour
 
The Philosophy of DDD
The Philosophy of DDDThe Philosophy of DDD
The Philosophy of DDD
Garth Gilmour
 

More from Garth Gilmour (20)

Compose in Theory
Compose in TheoryCompose in Theory
Compose in Theory
 
Kotlin / Android Update
Kotlin / Android UpdateKotlin / Android Update
Kotlin / Android Update
 
TypeScript Vs. KotlinJS
TypeScript Vs. KotlinJSTypeScript Vs. KotlinJS
TypeScript Vs. KotlinJS
 
Shut Up And Eat Your Veg
Shut Up And Eat Your VegShut Up And Eat Your Veg
Shut Up And Eat Your Veg
 
Lies Told By The Kotlin Compiler
Lies Told By The Kotlin CompilerLies Told By The Kotlin Compiler
Lies Told By The Kotlin Compiler
 
A TypeScript Fans KotlinJS Adventures
A TypeScript Fans KotlinJS AdventuresA TypeScript Fans KotlinJS Adventures
A TypeScript Fans KotlinJS Adventures
 
The Heat Death Of Enterprise IT
The Heat Death Of Enterprise ITThe Heat Death Of Enterprise IT
The Heat Death Of Enterprise IT
 
Lies Told By The Kotlin Compiler
Lies Told By The Kotlin CompilerLies Told By The Kotlin Compiler
Lies Told By The Kotlin Compiler
 
Type Driven Development with TypeScript
Type Driven Development with TypeScriptType Driven Development with TypeScript
Type Driven Development with TypeScript
 
Generics On The JVM (What you don't know will hurt you)
Generics On The JVM (What you don't know will hurt you)Generics On The JVM (What you don't know will hurt you)
Generics On The JVM (What you don't know will hurt you)
 
Using Kotlin, to Create Kotlin, to Teach Kotlin, in Space
Using Kotlin, to Create Kotlin,to Teach Kotlin,in SpaceUsing Kotlin, to Create Kotlin,to Teach Kotlin,in Space
Using Kotlin, to Create Kotlin, to Teach Kotlin, in Space
 
Is Software Engineering A Profession?
Is Software Engineering A Profession?Is Software Engineering A Profession?
Is Software Engineering A Profession?
 
Social Distancing is not Behaving Distantly
Social Distancing is not Behaving DistantlySocial Distancing is not Behaving Distantly
Social Distancing is not Behaving Distantly
 
The Great Scala Makeover
The Great Scala MakeoverThe Great Scala Makeover
The Great Scala Makeover
 
Simpler and Safer Java Types (via the Vavr and Lambda Libraries)
Simpler and Safer Java Types (via the Vavr and Lambda Libraries)Simpler and Safer Java Types (via the Vavr and Lambda Libraries)
Simpler and Safer Java Types (via the Vavr and Lambda Libraries)
 
The Three Horse Race
The Three Horse RaceThe Three Horse Race
The Three Horse Race
 
The Bestiary of Pure Functional Programming
The Bestiary of Pure Functional Programming The Bestiary of Pure Functional Programming
The Bestiary of Pure Functional Programming
 
BelTech 2019 Presenters Workshop
BelTech 2019 Presenters WorkshopBelTech 2019 Presenters Workshop
BelTech 2019 Presenters Workshop
 
Kotlin The Whole Damn Family
Kotlin The Whole Damn FamilyKotlin The Whole Damn Family
Kotlin The Whole Damn Family
 
The Philosophy of DDD
The Philosophy of DDDThe Philosophy of DDD
The Philosophy of DDD
 

Recently uploaded

GreenCode-A-VSCode-Plugin--Dario-Jurisic
GreenCode-A-VSCode-Plugin--Dario-JurisicGreenCode-A-VSCode-Plugin--Dario-Jurisic
GreenCode-A-VSCode-Plugin--Dario-Jurisic
Green Software Development
 
8 Best Automated Android App Testing Tool and Framework in 2024.pdf
8 Best Automated Android App Testing Tool and Framework in 2024.pdf8 Best Automated Android App Testing Tool and Framework in 2024.pdf
8 Best Automated Android App Testing Tool and Framework in 2024.pdf
kalichargn70th171
 
Using Query Store in Azure PostgreSQL to Understand Query Performance
Using Query Store in Azure PostgreSQL to Understand Query PerformanceUsing Query Store in Azure PostgreSQL to Understand Query Performance
Using Query Store in Azure PostgreSQL to Understand Query Performance
Grant Fritchey
 
Measures in SQL (SIGMOD 2024, Santiago, Chile)
Measures in SQL (SIGMOD 2024, Santiago, Chile)Measures in SQL (SIGMOD 2024, Santiago, Chile)
Measures in SQL (SIGMOD 2024, Santiago, Chile)
Julian Hyde
 
Why Choose Odoo 17 Community & How it differs from Odoo 17 Enterprise Edition
Why Choose Odoo 17 Community & How it differs from Odoo 17 Enterprise EditionWhy Choose Odoo 17 Community & How it differs from Odoo 17 Enterprise Edition
Why Choose Odoo 17 Community & How it differs from Odoo 17 Enterprise Edition
Envertis Software Solutions
 
ALGIT - Assembly Line for Green IT - Numbers, Data, Facts
ALGIT - Assembly Line for Green IT - Numbers, Data, FactsALGIT - Assembly Line for Green IT - Numbers, Data, Facts
ALGIT - Assembly Line for Green IT - Numbers, Data, Facts
Green Software Development
 
LORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOM
LORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOMLORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOM
LORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOM
lorraineandreiamcidl
 
原版定制美国纽约州立大学奥尔巴尼分校毕业证学位证书原版一模一样
原版定制美国纽约州立大学奥尔巴尼分校毕业证学位证书原版一模一样原版定制美国纽约州立大学奥尔巴尼分校毕业证学位证书原版一模一样
原版定制美国纽约州立大学奥尔巴尼分校毕业证学位证书原版一模一样
mz5nrf0n
 
Using Xen Hypervisor for Functional Safety
Using Xen Hypervisor for Functional SafetyUsing Xen Hypervisor for Functional Safety
Using Xen Hypervisor for Functional Safety
Ayan Halder
 
UI5con 2024 - Keynote: Latest News about UI5 and it’s Ecosystem
UI5con 2024 - Keynote: Latest News about UI5 and it’s EcosystemUI5con 2024 - Keynote: Latest News about UI5 and it’s Ecosystem
UI5con 2024 - Keynote: Latest News about UI5 and it’s Ecosystem
Peter Muessig
 
Graspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code AnalysisGraspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code Analysis
Aftab Hussain
 
LORRAINE ANDREI_LEQUIGAN_HOW TO USE WHATSAPP.pptx
LORRAINE ANDREI_LEQUIGAN_HOW TO USE WHATSAPP.pptxLORRAINE ANDREI_LEQUIGAN_HOW TO USE WHATSAPP.pptx
LORRAINE ANDREI_LEQUIGAN_HOW TO USE WHATSAPP.pptx
lorraineandreiamcidl
 
Oracle Database 19c New Features for DBAs and Developers.pptx
Oracle Database 19c New Features for DBAs and Developers.pptxOracle Database 19c New Features for DBAs and Developers.pptx
Oracle Database 19c New Features for DBAs and Developers.pptx
Remote DBA Services
 
What is Augmented Reality Image Tracking
What is Augmented Reality Image TrackingWhat is Augmented Reality Image Tracking
What is Augmented Reality Image Tracking
pavan998932
 
socradar-q1-2024-aviation-industry-report.pdf
socradar-q1-2024-aviation-industry-report.pdfsocradar-q1-2024-aviation-industry-report.pdf
socradar-q1-2024-aviation-industry-report.pdf
SOCRadar
 
A Study of Variable-Role-based Feature Enrichment in Neural Models of Code
A Study of Variable-Role-based Feature Enrichment in Neural Models of CodeA Study of Variable-Role-based Feature Enrichment in Neural Models of Code
A Study of Variable-Role-based Feature Enrichment in Neural Models of Code
Aftab Hussain
 
Neo4j - Product Vision and Knowledge Graphs - GraphSummit Paris
Neo4j - Product Vision and Knowledge Graphs - GraphSummit ParisNeo4j - Product Vision and Knowledge Graphs - GraphSummit Paris
Neo4j - Product Vision and Knowledge Graphs - GraphSummit Paris
Neo4j
 
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
Crescat
 
UI5con 2024 - Boost Your Development Experience with UI5 Tooling Extensions
UI5con 2024 - Boost Your Development Experience with UI5 Tooling ExtensionsUI5con 2024 - Boost Your Development Experience with UI5 Tooling Extensions
UI5con 2024 - Boost Your Development Experience with UI5 Tooling Extensions
Peter Muessig
 
Fundamentals of Programming and Language Processors
Fundamentals of Programming and Language ProcessorsFundamentals of Programming and Language Processors
Fundamentals of Programming and Language Processors
Rakesh Kumar R
 

Recently uploaded (20)

GreenCode-A-VSCode-Plugin--Dario-Jurisic
GreenCode-A-VSCode-Plugin--Dario-JurisicGreenCode-A-VSCode-Plugin--Dario-Jurisic
GreenCode-A-VSCode-Plugin--Dario-Jurisic
 
8 Best Automated Android App Testing Tool and Framework in 2024.pdf
8 Best Automated Android App Testing Tool and Framework in 2024.pdf8 Best Automated Android App Testing Tool and Framework in 2024.pdf
8 Best Automated Android App Testing Tool and Framework in 2024.pdf
 
Using Query Store in Azure PostgreSQL to Understand Query Performance
Using Query Store in Azure PostgreSQL to Understand Query PerformanceUsing Query Store in Azure PostgreSQL to Understand Query Performance
Using Query Store in Azure PostgreSQL to Understand Query Performance
 
Measures in SQL (SIGMOD 2024, Santiago, Chile)
Measures in SQL (SIGMOD 2024, Santiago, Chile)Measures in SQL (SIGMOD 2024, Santiago, Chile)
Measures in SQL (SIGMOD 2024, Santiago, Chile)
 
Why Choose Odoo 17 Community & How it differs from Odoo 17 Enterprise Edition
Why Choose Odoo 17 Community & How it differs from Odoo 17 Enterprise EditionWhy Choose Odoo 17 Community & How it differs from Odoo 17 Enterprise Edition
Why Choose Odoo 17 Community & How it differs from Odoo 17 Enterprise Edition
 
ALGIT - Assembly Line for Green IT - Numbers, Data, Facts
ALGIT - Assembly Line for Green IT - Numbers, Data, FactsALGIT - Assembly Line for Green IT - Numbers, Data, Facts
ALGIT - Assembly Line for Green IT - Numbers, Data, Facts
 
LORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOM
LORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOMLORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOM
LORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOM
 
原版定制美国纽约州立大学奥尔巴尼分校毕业证学位证书原版一模一样
原版定制美国纽约州立大学奥尔巴尼分校毕业证学位证书原版一模一样原版定制美国纽约州立大学奥尔巴尼分校毕业证学位证书原版一模一样
原版定制美国纽约州立大学奥尔巴尼分校毕业证学位证书原版一模一样
 
Using Xen Hypervisor for Functional Safety
Using Xen Hypervisor for Functional SafetyUsing Xen Hypervisor for Functional Safety
Using Xen Hypervisor for Functional Safety
 
UI5con 2024 - Keynote: Latest News about UI5 and it’s Ecosystem
UI5con 2024 - Keynote: Latest News about UI5 and it’s EcosystemUI5con 2024 - Keynote: Latest News about UI5 and it’s Ecosystem
UI5con 2024 - Keynote: Latest News about UI5 and it’s Ecosystem
 
Graspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code AnalysisGraspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code Analysis
 
LORRAINE ANDREI_LEQUIGAN_HOW TO USE WHATSAPP.pptx
LORRAINE ANDREI_LEQUIGAN_HOW TO USE WHATSAPP.pptxLORRAINE ANDREI_LEQUIGAN_HOW TO USE WHATSAPP.pptx
LORRAINE ANDREI_LEQUIGAN_HOW TO USE WHATSAPP.pptx
 
Oracle Database 19c New Features for DBAs and Developers.pptx
Oracle Database 19c New Features for DBAs and Developers.pptxOracle Database 19c New Features for DBAs and Developers.pptx
Oracle Database 19c New Features for DBAs and Developers.pptx
 
What is Augmented Reality Image Tracking
What is Augmented Reality Image TrackingWhat is Augmented Reality Image Tracking
What is Augmented Reality Image Tracking
 
socradar-q1-2024-aviation-industry-report.pdf
socradar-q1-2024-aviation-industry-report.pdfsocradar-q1-2024-aviation-industry-report.pdf
socradar-q1-2024-aviation-industry-report.pdf
 
A Study of Variable-Role-based Feature Enrichment in Neural Models of Code
A Study of Variable-Role-based Feature Enrichment in Neural Models of CodeA Study of Variable-Role-based Feature Enrichment in Neural Models of Code
A Study of Variable-Role-based Feature Enrichment in Neural Models of Code
 
Neo4j - Product Vision and Knowledge Graphs - GraphSummit Paris
Neo4j - Product Vision and Knowledge Graphs - GraphSummit ParisNeo4j - Product Vision and Knowledge Graphs - GraphSummit Paris
Neo4j - Product Vision and Knowledge Graphs - GraphSummit Paris
 
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
 
UI5con 2024 - Boost Your Development Experience with UI5 Tooling Extensions
UI5con 2024 - Boost Your Development Experience with UI5 Tooling ExtensionsUI5con 2024 - Boost Your Development Experience with UI5 Tooling Extensions
UI5con 2024 - Boost Your Development Experience with UI5 Tooling Extensions
 
Fundamentals of Programming and Language Processors
Fundamentals of Programming and Language ProcessorsFundamentals of Programming and Language Processors
Fundamentals of Programming and Language Processors
 

Transitioning Android Teams Into Kotlin

  • 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
  • 26.
  • 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