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
1
250
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
Tweet
Share
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
84
Improving your Android Gradle experience with Kotlin
kotlinhh
0
74
Building SDKs - The Kotlin Way
kotlinhh
1
53
Concurrency with Coroutines and Actors
kotlinhh
0
55
Fight cold startup times for Kotlin lambdas with GraalVM
kotlinhh
0
210
Microservices with Kotlin and Ktor
kotlinhh
2
110
Dependency Management in Gradle 5 and Beyond
kotlinhh
0
310
What's up next for Kotlin?
kotlinhh
1
180
Kotlin's Hidden Costs, Revisited
kotlinhh
0
180
Other Decks in Programming
See All in Programming
CSC307 Lecture 01
javiergs
PRO
0
680
re:Invent 2025 トレンドからみる製品開発への AI Agent 活用
yoskoh
0
710
.NET Conf 2025 の興味のあるセッ ションを復習した / dotnet conf 2025 quick recap for backend engineer
tomohisa
0
130
AI Schema Enrichment for your Oracle AI Database
thatjeffsmith
0
200
フロントエンド開発の勘所 -複数事業を経験して見えた判断軸の違い-
heimusu
7
2.7k
AIによるイベントストーミング図からのコード生成 / AI-powered code generation from Event Storming diagrams
nrslib
2
1.7k
AIフル活用時代だからこそ学んでおきたい働き方の心得
shinoyu
0
120
Implementation Patterns
denyspoltorak
0
270
コントリビューターによるDenoのすゝめ / Deno Recommendations by a Contributor
petamoriken
0
200
Basic Architectures
denyspoltorak
0
650
LLM Observabilityによる 対話型音声AIアプリケーションの安定運用
gekko0114
2
410
なぜSQLはAIぽく見えるのか/why does SQL look AI like
florets1
0
420
Featured
See All Featured
svc-hook: hooking system calls on ARM64 by binary rewriting
retrage
1
92
Unlocking the hidden potential of vector embeddings in international SEO
frankvandijk
0
160
What does AI have to do with Human Rights?
axbom
PRO
0
2k
Why You Should Never Use an ORM
jnunemaker
PRO
61
9.7k
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
12
1k
Data-driven link building: lessons from a $708K investment (BrightonSEO talk)
szymonslowik
1
900
Primal Persuasion: How to Engage the Brain for Learning That Lasts
tmiket
0
230
Heart Work Chapter 1 - Part 1
lfama
PRO
5
35k
Measuring & Analyzing Core Web Vitals
bluesmoon
9
740
Intergalactic Javascript Robots from Outer Space
tanoku
273
27k
Leveraging LLMs for student feedback in introductory data science courses - posit::conf(2025)
minecr
0
130
Ethics towards AI in product and experience design
skipperchong
2
190
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