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
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
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
AlarmKitで明後日起きれるアラームアプリを作る
trickart
0
160
These Five Tricks Can Make Your Apps Greener, Cheaper, & Nicer
hollycummins
0
230
Technical Debt: Understanding it Rightly, Engaging it Rightly #LaravelLiveJP
shogogg
0
160
Why Laravel apps break—Mastering the fundamentals to keep them maintainable
kentaroutakeda
1
300
AI 時代のソフトウェア設計の学び方
masuda220
PRO
28
10k
Oxcを導入して開発体験が向上した話
yug1224
4
220
TSKaigi2026-静的解析への投資がAI時代のコード品質を支える ── カスタムESLintルールの設計と運用
hayatokudou
6
1.2k
AIとRubyの静的型付け
ukin0k0
0
190
Oxlintのカスタムルールの現況
syumai
5
760
Lemonade + Foundry Toolkit でお手軽アプリ開発
seosoft
1
200
脅威をエンジニアリングの糧にして――現場編 / Turning Threats into Engineering Fuel — Field Edition
nrslib
0
200
Sans tests, vos agents ne sont pas fiables
nabondance
0
160
Featured
See All Featured
Understanding Cognitive Biases in Performance Measurement
bluesmoon
32
2.9k
Claude Code どこまでも/ Claude Code Everywhere
nwiizo
65
55k
The innovator’s Mindset - Leading Through an Era of Exponential Change - McGill University 2025
jdejongh
PRO
1
180
Amusing Abliteration
ianozsvald
1
180
Scaling GitHub
holman
464
140k
Building Better People: How to give real-time feedback that sticks.
wjessup
370
20k
The Hidden Cost of Media on the Web [PixelPalooza 2025]
tammyeverts
2
310
No one is an island. Learnings from fostering a developers community.
thoeni
21
3.7k
How To Stay Up To Date on Web Technology
chriscoyier
790
250k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
141
35k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
PRO
199
74k
Code Reviewing Like a Champion
maltzj
528
40k
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