Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Refactoring Legacy Code with Kotlin and Coroutines
Search
Kotlin User Group Hamburg
August 30, 2019
Programming
260
1
Share
Refactoring Legacy Code with Kotlin and Coroutines
by Ash Davies
presented on August 30, 2019 @Kotlin/Everywhere Hamburg
Kotlin User Group Hamburg
August 30, 2019
More Decks by Kotlin User Group Hamburg
See All by Kotlin User Group Hamburg
Structure your Project with Gradle by using Kotlin Everywhere
kotlinhh
1
89
Improving your Android Gradle experience with Kotlin
kotlinhh
0
86
Building SDKs - The Kotlin Way
kotlinhh
1
61
Concurrency with Coroutines and Actors
kotlinhh
0
66
Fight cold startup times for Kotlin lambdas with GraalVM
kotlinhh
0
220
Microservices with Kotlin and Ktor
kotlinhh
2
130
Dependency Management in Gradle 5 and Beyond
kotlinhh
0
320
What's up next for Kotlin?
kotlinhh
1
190
Kotlin's Hidden Costs, Revisited
kotlinhh
0
190
Other Decks in Programming
See All in Programming
OSもどきOS
arkw
0
250
Why Laravel apps break—Mastering the fundamentals to keep them maintainable
kentaroutakeda
1
300
気づいたらRubyで100作品 ー クリエイティブコーディングが生活の一部になるまで / 100 Ruby Sketches Later: How Creative Coding Became Part of My Life
chobishiba
3
450
These Five Tricks Can Make Your Apps Greener, Cheaper, & Nicer
hollycummins
0
230
ふつうのFeature Flag実践入門
irof
6
3.2k
oxlintはeslint/typescript-eslintを置き換えられるのか
shomafujita
2
270
Hive Metastoreを通して学ぶIceberg REST Catalog ― 仕様から実装まで
okumin
0
290
AI時代の仕事技芸論 — ソフトウェア開発で「遊ぶように働く」職人的熟達のすすめ
kuranuki
1
400
Skillは並べた。動かなかった。契約で繋いだ。— 65個のSkillから、自走する開発サイクルへ
junholee
0
770
脅威をエンジニアリングの糧にして――現場編 / Turning Threats into Engineering Fuel — Field Edition
nrslib
0
200
tsserverとは何だったのか、これからどうなるのか
nowaki28
1
400
Agentic UI beyond Chats Architecture Patterns & Open Standards @ngMunich 05/2026
manfredsteyer
PRO
0
160
Featured
See All Featured
Ethics towards AI in product and experience design
skipperchong
2
290
The SEO identity crisis: Don't let AI make you average
varn
0
470
AI Search: Where Are We & What Can We Do About It?
aleyda
0
7.5k
What does AI have to do with Human Rights?
axbom
PRO
1
2.2k
WCS-LA-2024
lcolladotor
0
600
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
28
3.5k
RailsConf 2023
tenderlove
30
1.4k
エンジニアに許された特別な時間の終わり
watany
107
240k
What's in a price? How to price your products and services
michaelherold
247
13k
Measuring Dark Social's Impact On Conversion and Attribution
stephenakadiri
2
200
brightonSEO & MeasureFest 2025 - Christian Goodrich - Winning strategies for Black Friday CRO & PPC
cargoodrich
3
710
Faster Mobile Websites
deanohume
310
31k
Transcript
Refactoring Legacy Code with Kotlin & Coroutines Kotlin Everywhere: Hamburg
@askashdavies
@askashdavies
Java @askashdavies
{ } @askashdavies
Streams ↝ @askashdavies
@askashdavies
Kotlin @askashdavies
Null @askashdavies
if (foo == null) { bar(); } @askashdavies
O"ensive Code < > @askashdavies
Urgency @askashdavies
Kotlin? @askashdavies
Kotlin @askashdavies
@askashdavies
Google IO 2018 @askashdavies
! " @askashdavies
Google IO 2019 @askashdavies
Kotlin @askashdavies
Libraries @askashdavies
@askashdavies
@askashdavies
@askashdavies
@askashdavies
@askashdavies
@askashdavies
Kotlin @askashdavies
Idiomacy @askashdavies
@askashdavies
Idiomatic Code @askashdavies
Idiomatic Code • Consistent, easier to read • Less cognitive
load • Less ambiguity • Function > Style @askashdavies
Code Style • kotlinlang.org/docs/reference/coding-conventions.html • android.github.io/kotlin-guides/style.html @askashdavies
Refactoring Legacy Code @askashdavies
⌃⌥⇧K @askashdavies
@askashdavies
@askashdavies
public class BadJavaActivity extends Activity { @Inject Dependency dependency; }
@askashdavies
General Assumptions @askashdavies
class BadKotlinActivity : Activity() { @Inject var dependency: Dependency? =
null } @askashdavies
class SlightlyLessBadKotlinActivity : Activity() { @Inject internal lateinit var dependency:
Dependency } @askashdavies
UninitializedPrope.yAccessException! @askashdavies
lateinit var file: File if (::file.isInitialized) { /* ... */
} @askashdavies
Data Classes @askashdavies
public class User { private String firstName; private String lastName;
public User(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } User user = (User) o; return Objects.equals(firstName, user.firstName) && Objects.equals(lastName, user.lastName); } @Override public int hashCode() { return Objects.hash(firstName, lastName); } } @askashdavies
class User(var firstName: String?, var lastName: String?) { override fun
equals(o: Any?): Boolean { if (this === o) { return true } if (o == null || javaClass != o.javaClass) { return false } val user = o as User? return firstName == user!!.firstName && lastName == user.lastName } override fun hashCode(): Int { return Objects.hash(firstName, lastName) } } @askashdavies
data class User(val firstName: String, val lastName: String) @askashdavies
data class User(val firstName: String, val lastName: String? = null)
@askashdavies
@NotNull public final User copy(@Nullable String firstName, @Nullable String lastName)
{ return new User(firstName, lastName); } @askashdavies
Kotlin • Singleton objects • String interpolation • Elvis operator
! • Destructuring • Extension functions • Scoping functions @askashdavies
Maintaining History @askashdavies
Maintaining History • Change extension .java -> .kt • First
commit • Apply Kotlin conversion • Second commit @askashdavies
Maintaining History Refactoring @askashdavies
Refactoring @askashdavies
Refactoring SOLID • Single-responsibility • Open-closed • Liskov substitution •
Interface segregation • Dependency inversion @askashdavies
Refactoring Single Responsibility @askashdavies
Perspective @askashdavies
Asynchronicity @askashdavies
Concurrency is Hard @askashdavies
Thread new Thread(() -> { foo(); }).start(); @askashdavies
CompletableFuture CompletableFuture.supplyAsync(this::findSomeData) .thenApply(this:: intReturningMethod) .thenAccept(this::notify); @askashdavies
RxJava Observable .fromIterable(resourceDraft.getResources()) .flatMap(resourceServiceApiClient::createUploadContainer) .zipWith(Observable.fromIterable(resourceDraft.getResources()), Pair::create) .flatMap(uploadResources()) .toList() .toObservable() .flatMapMaybe(resourceCache.getResourceCachedItem())
.defaultIfEmpty(Resource.getDefaultItem()) .flatMap(postResource(resourceId, resourceDraft.getText(), currentUser, resourceDraft.getIntent())) .observeOn(AndroidSchedulers.mainThread()) .subscribeOn(Schedulers.io()) .subscribe( resource -> repository.setResource(resourceId, resource, provisionalResourceId), resourceUploadError(resourceId, resourceDraft, provisionalResourceId) ); @askashdavies
@askashdavies
What If? @askashdavies
Coroutines @askashdavies
fun main() { GlobalScope.launch { delay(1000L) println("World!") } println("Hello,") Thread.sleep(2000L)
} // Hello, // World! @askashdavies
fun main() { GlobalScope.launch { delay(1000L) println("World!") } println("Hello,") Thread.sleep(2000L)
} // Hello, // World! @askashdavies
fun main() { GlobalScope.launch { delay(1000L) println("World!") } println("Hello,") Thread.sleep(2000L)
} // Hello, // World! @askashdavies
⚖ Stability @askashdavies
@askashdavies
@Annotations ( ! Here be dragons) @askashdavies
Annotations @ExperimentalCoroutinesApi // ⚠ @askashdavies
Annotations @ExperimentalCoroutinesApi // ⚠ @FlowPreview // ⚠ @askashdavies
Annotations @ExperimentalCoroutinesApi // ⚠ @FlowPreview // ⚠ @ObsoleteCoroutinesApi // ⚠
@askashdavies
Annotations @ExperimentalCoroutinesApi // ⚠ @FlowPreview // ⚠ @ObsoleteCoroutinesApi // ⚠
@InternalCoroutinesApi // ☠ @askashdavies
Annotations @Experimental @askashdavies
! Coroutines @askashdavies
! Native (rst-pa-y library @askashdavies
E"cient @askashdavies
! Easy-to-use @askashdavies
! suspend fun @askashdavies
! Suspend fun main() { GlobalScope.launch { delay(1000L) println("World!") }
println("Hello,") Thread.sleep(2000L) } // Hello, // World! @askashdavies
! Suspend fun main() { GlobalScope.launch { doWorld() println("Hello,") Thread.sleep(2000L)
} } suspend fun doWorld() { delay(1000L) println("World!") } // Hello, // World! @askashdavies
! Suspend fun main() { GlobalScope.launch { doWorld() println("Hello,") Thread.sleep(2000L)
} } suspend fun doWorld() { withContext(Dispatchers.IO) { delay(1000L) println("World!") } } // Hello, // World! @askashdavies
Dispatchers @askashdavies
Dispatchers • Default • IO • Main • Android (Main
Thread Dispatcher) • JavaFx (Application Thread Dispatcher) • Swing (Event Dispatcher Thread) • Unconfined @askashdavies
Testing @Test fun testFoo() = runBlockingTest { val actual =
foo() // ... } suspend fun foo() { delay(1_000) // ... } @askashdavies
Fu#her Reading • Google Codelab: Refactoring to Kotlin https://codelabs.developers.google.com/codelabs/java-to-kotlin/ •
KotlinX Coroutine Test https://github.com/Kotlin/kotlinx.coroutines/tree/master/kotlinx-coroutines-test • Sean McQuillan: Coroutines + Testing = https://www.droidcon.com/media-detail?video=352671106 • Ash Davies: RxJava & Coroutines: A Practical Analysis v3 https://speakerdeck.com/ashdavies/rxjava-and-coroutines-a-practical-analysis- v3 @askashdavies
Thanks! @askashdavies