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
220
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
76
Improving your Android Gradle experience with Kotlin
kotlinhh
0
37
Building SDKs - The Kotlin Way
kotlinhh
1
33
Concurrency with Coroutines and Actors
kotlinhh
0
31
Fight cold startup times for Kotlin lambdas with GraalVM
kotlinhh
0
180
Microservices with Kotlin and Ktor
kotlinhh
2
84
Dependency Management in Gradle 5 and Beyond
kotlinhh
0
270
What's up next for Kotlin?
kotlinhh
1
160
Kotlin's Hidden Costs, Revisited
kotlinhh
0
150
Other Decks in Programming
See All in Programming
20241217 競争力強化とビジネス価値創出への挑戦:モノタロウのシステムモダナイズ、開発組織の進化と今後の展望
monotaro
PRO
0
230
Amazon S3 NYJavaSIG 2024-12-12
sullis
0
130
return文におけるstd::moveについて
onihusube
1
1.4k
React 19でお手軽にCSS-in-JSを自作する
yukukotani
5
530
Fibonacci Function Gallery - Part 1
philipschwarz
PRO
0
270
ISUCON14感想戦で85万点まで頑張ってみた
ponyo877
1
200
生成AIでGitHubソースコード取得して仕様書を作成
shukob
0
600
Fixstars高速化コンテスト2024準優勝解法
eijirou
0
170
PHPで学ぶプログラミングの教訓 / Lessons in Programming Learned through PHP
nrslib
4
1k
MCP with Cloudflare Workers
yusukebe
2
270
アクターシステムに頼らずEvent Sourcingする方法について
j5ik2o
6
670
非ブラウザランタイムとWeb標準 / Non-Browser Runtimes and Web Standards
petamoriken
0
410
Featured
See All Featured
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
356
29k
The Language of Interfaces
destraynor
155
24k
Learning to Love Humans: Emotional Interface Design
aarron
274
40k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
29
2.4k
4 Signs Your Business is Dying
shpigford
182
21k
How to Ace a Technical Interview
jacobian
276
23k
jQuery: Nuts, Bolts and Bling
dougneiner
62
7.6k
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
2
160
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
38
1.9k
Writing Fast Ruby
sferik
628
61k
Visualization
eitanlees
146
15k
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
97
17k
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