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
240
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
79
Improving your Android Gradle experience with Kotlin
kotlinhh
0
57
Building SDKs - The Kotlin Way
kotlinhh
1
42
Concurrency with Coroutines and Actors
kotlinhh
0
38
Fight cold startup times for Kotlin lambdas with GraalVM
kotlinhh
0
210
Microservices with Kotlin and Ktor
kotlinhh
2
95
Dependency Management in Gradle 5 and Beyond
kotlinhh
0
300
What's up next for Kotlin?
kotlinhh
1
170
Kotlin's Hidden Costs, Revisited
kotlinhh
0
170
Other Decks in Programming
See All in Programming
Azure SRE Agentで運用は楽になるのか?
kkamegawa
0
2.2k
ソフトウェアテスト徹底指南書の紹介
goyoki
1
150
Testing Trophyは叫ばない
toms74209200
0
860
Ruby Parser progress report 2025
yui_knk
1
440
Putting The Genie in the Bottle - A Crash Course on running LLMs on Android
iurysza
0
140
ファインディ株式会社におけるMCP活用とサービス開発
starfish719
0
320
print("Hello, World")
eddie
2
530
rage against annotate_predecessor
junk0612
0
170
AI Coding Agentのセキュリティリスク:PRの自己承認とメルカリの対策
s3h
0
200
2025 年のコーディングエージェントの現在地とエンジニアの仕事の変化について
azukiazusa1
24
12k
Go言語での実装を通して学ぶLLMファインチューニングの仕組み / fukuokago22-llm-peft
monochromegane
0
120
GitHubとGitLabとAWS CodePipelineでCI/CDを組み比べてみた
satoshi256kbyte
4
220
Featured
See All Featured
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
8
920
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
252
21k
The Pragmatic Product Professional
lauravandoore
36
6.9k
Bootstrapping a Software Product
garrettdimon
PRO
307
110k
[RailsConf 2023] Rails as a piece of cake
palkan
57
5.8k
It's Worth the Effort
3n
187
28k
A Modern Web Designer's Workflow
chriscoyier
696
190k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
12
1.1k
What’s in a name? Adding method to the madness
productmarketing
PRO
23
3.7k
The Illustrated Children's Guide to Kubernetes
chrisshort
48
50k
Being A Developer After 40
akosma
90
590k
Intergalactic Javascript Robots from Outer Space
tanoku
272
27k
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