Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Lessons From a Librarian
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
jbarr21
April 19, 2020
Programming
500
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Lessons From a Librarian
jbarr21
April 19, 2020
More Decks by jbarr21
See All by jbarr21
Lessons From Librarians Makers
jbarr21
0
340
Scaling UI
jbarr21
2
360
It's Time to Develop a Watch Face
jbarr21
1
310
Other Decks in Programming
See All in Programming
[Rails World 2026] Durable orchestration on Rails: from continuation to workflow
palkan
1
750
Railsのためのパスキー実践入門 〜マルチテナントSaaSでの意思決定〜
utakaha
2
540
Workers Cache を知る
syumai
0
360
PumaからFalconに移行したRailsアプリケーションでの実践
falcon8823
0
170
3回つくってわかった、 定期実行ジョブ基盤の本質情報
takai
0
450
Apple Intelligence を用いた個人情報誤送信防止、及びユーザーリクエスト体験の改善について
yukiny
0
350
コーディング自動化の次へ。人の介入をゼロにするファクトリーとサポートAIによる実践
timakin
4
3.5k
sbt 2.0: takeoff
eed3si9n
0
160
re:Inventに行く前に知っておきたい現地参加のノウハウ
nokomoro3
0
420
Kotlinの15年とServer-Side Kotlin
n_takehata
1
150
Jetpack Compose Mechanisms
skydoves
3
820
外から家のPCの電源入れたい!をPHPで解決する
kawashimo0
1
130
Featured
See All Featured
Intergalactic Javascript Robots from Outer Space
tanoku
273
28k
A Guide to Academic Writing Using Generative AI - A Workshop
ks91
PRO
1
520
Paper Plane (Part 1)
katiecoart
PRO
2
12k
Code Reviewing Like a Champion
maltzj
529
40k
Reflections from 52 weeks, 52 projects
jeffersonlam
356
22k
Art, The Web, and Tiny UX
lynnandtonic
304
22k
Tell your own story through comics
letsgokoyo
1
1.1k
Mobile First: as difficult as doing things right
swwweet
225
10k
Building a Modern Day E-commerce SEO Strategy
aleyda
45
9.3k
Kristin Tynski - Automating Marketing Tasks With AI
techseoconnect
PRO
0
550
Accessibility Awareness
sabderemane
1
250
Why You Should Never Use an ORM
jnunemaker
PRO
61
10k
Transcript
Photo by Gabriel Sollmann on Unsplash Lessons From a Librarian
James Barr - @JBarr21 Zac Sweers - @ZacSweers
subscribe()
subscribe(new Consumer<String>() { @Override public void accept(String value) { //
Do stuff } })
subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { //
Do stuff } })
subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { //
Do stuff } })
subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { //
Do stuff } }) subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { // Do stuff } }) subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { // Do stuff } }) subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { // Do stuff } }) subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { // Do stuff } }) subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { // Do stuff } }) subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { // Do stuff } }) subscribe(new CrashOnErrorConsumer<String>() @Override public void accept(String value) { // Do stuff } }) subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { // Do stuff } }) subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { // Do stuff } }) subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { // Do stuff } }) subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { // Do stuff } }) subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { // Do stuff } })
subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { //
Do stuff } })
subscribe(value -> { // Do stuff })
subscribe(value -> { // Do stuff }) github.com/uber/rxdogtag
subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { //
Do stuff } }) subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { // Do stuff } }) subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { // Do stuff } }) subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { // Do stuff } }) subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { // Do stuff } }) subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { // Do stuff } }) subscribe(new CrashOnErrorConsumer<String>() @Override public void accept(String value) { // Do stuff } }) subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { // Do stuff } }) subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { // Do stuff } }) subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { // Do stuff } }) subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { // Do stuff } }) subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { // Do stuff } }) subscribe(value -> { // Do stuff })
subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { //
Do stuff } }) subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { // Do stuff } }) subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { // Do stuff } }) subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { // Do stuff } }) subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { // Do stuff } }) subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { // Do stuff } }) subscribe(new CrashOnErrorConsumer<String>() @Override public void accept(String value) { // Do stuff } }) subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { // Do stuff } }) subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { // Do stuff } }) subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { // Do stuff } }) subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { // Do stuff } }) subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { // Do stuff } }) subscribe(value -> { // Do stuff })
subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { //
Do stuff } }) subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { // Do stuff } }) subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { // Do stuff } }) subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { // Do stuff } }) subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { // Do stuff } }) subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { // Do stuff } }) subscribe(new CrashOnErrorConsumer<String>() @Override public void accept(String value) { // Do stuff } }) subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { // Do stuff } }) subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { // Do stuff } }) subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { // Do stuff } }) subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { // Do stuff } }) subscribe(new CrashOnErrorConsumer<String>() { @Override public void accept(String value) { // Do stuff } }) subscribe(value -> { // Do stuff }) And thousands more
subscribe(value -> { // Do stuff }) subscribe(value -> {
// Do stuff }) subscribe(value -> { // Do stuff }) subscribe(value -> { // Do stuff }) subscribe(value -> { // Do stuff }) subscribe(value -> { // Do stuff }) subscribe(value -> { // Do stuff }) subscribe(value -> { // Do stuff }) subscribe(value -> { // Do stuff }) subscribe(value -> { // Do stuff }) subscribe(value -> { // Do stuff }) subscribe(value -> { // Do stuff }) subscribe(value -> { // Do stuff })
- Anonymous audience member "But how?!"
Lessons from a Librarian
"Writing Code That Lasts Forever" - Jesse Wilson - Droidcon
NYC 2018
Writing Code That Lasts Forever
Helping Everyone Write Code That Lasts Forever
Codebase Health ✅ Builds quickly ✅ Test coverage ✅ Well
documented ❌ Duplicate code ❌ Deprecated APIs ❌ Large modules/classes
Name Build Time Undocumented Public Methods Module Size Deprecated Method
Calls Quality Score (Overall: 75%) app 5m25s 0 10,000 LOC 0 75% feature1 4m20s 0 120,000 LOC 0 50% feature2 20s 0 4,000 LOC 0 100% library1 7s 90 1,000 LOC 0 75% library2 5s 0 2,000 LOC 88 75% Codebase Health
Name Build Time Undocumented Public Methods Module Size Deprecated Method
Calls Quality Score (Overall: 75%) app 5m25s 0 10,000 LOC 0 75% feature1 4m20s 0 120,000 LOC 0 50% feature2 20s 0 4,000 LOC 0 100% library1 7s 90 1,000 LOC 0 75% library2 5s 0 2,000 LOC 88 75% Codebase Health
How does tech debt happen?
API Design
Limit Surface Area
Limit Surface Area class Hammer { public void hammer(Nail nail)
{ // ow } }
Limit Surface Area • Final by default final class Hammer
{ public void hammer(Nail nail) { // ow } }
Limit Surface Area • Final by default • Visibility final
class Hammer { public void hammer(Nail nail) { // ow } }
Limit Surface Area • Final by default • Visibility •
Factories final class Hammer { public static Hammer create() { // Stuff } private Hammer() { ... } }
Limit Surface Area final class Hammer { public void hammer(Nail
nail) { // ow } } • Final by default • Visibility • Factories
API Design • Limit surface area • Final by default
• Visibility • Factories • Consume interfaces interface Nail { void onHammer(); int length(); }
API Design • Limit surface area • Final by default
• Visibility • Factories • Consume interfaces • Fluent APIs as navigation final class Hammer { public void removeNail(Nail nail) { // } }
API Design • Limit surface area • Final by default
• Visibility • Factories • Consume interfaces • Fluent APIs as navigation final class Hammer { public RemovedNail removeNail(Nail nail) { // } }
API Design final class Hammer { public RemovedNail removeNail(Nail nail)
{ // } } hammer.removeNail() .dispose() • Limit surface area • Final by default • Visibility • Factories • Consume interfaces • Fluent APIs as navigation
API Design final class Hammer { public RemovedNail removeNail(Nail nail)
{ // } } hammer.removeNail() .dispose() • Limit surface area • Final by default • Visibility • Factories • Consume interfaces • Fluent APIs as navigation
- you, writing libraries "Does this put the user on
the right track?"
- you, writing libraries "Does this put the user on
the right track?" "Is this going to limit me later?"
API vs Implementation
API vs Implementation class Hammer { public void hammer(Nail nail)
{ // ow } }
API vs Implementation class Hammer { public void hammer(Nail nail)
{ // ow } } :hammer
API vs Implementation class Hammer { public void hammer(Nail nail)
{ // ow } } :hammer libA libA App
API vs Implementation class Hammer { public void hammer(Nail nail)
{ // ow } } :hammer libA libA App
API vs Implementation class Hammer { public void hammer(Nail nail)
{ // ow } } :hammer libA libA App
API vs Implementation class Hammer { public void hammer(Nail nail)
{ // ow } } :hammer libA libA App :hammer-api interface Hammer { void hammer(Nail nail) }
API vs Implementation class Hammer { public void hammer(Nail nail)
{ // ow } } :hammer libA libA App :hammer-api interface Hammer { void hammer(Nail nail) }
API vs Implementation class Hammer { public void hammer(Nail nail)
{ // ow } } :hammer libA libA App :hammer-api interface Hammer { void hammer(Nail nail) }
BuildConfig
BuildConfig public class BuildConfig { public static final String VERSION_NAME
= "1.0"; public static final int VERSION_CODE = 1; public static final boolean DEBUG == false; }
BuildConfig public class BuildConfig { public static final String VERSION_NAME
= "1.0"; public static final int VERSION_CODE = 1; public static final boolean DEBUG == false; } public interface AppBuildConfig { String versionName(); int versionCode(); boolean isDebug(); }
BuildConfig final class RealAppBuildConfig implements AppBuildConfig { // ... }
public interface AppBuildConfig { String versionName(); int versionCode(); boolean isDebug(); } :appbuildconfig :app
BuildConfig final class RealAppBuildConfig implements AppBuildConfig { // ... }
public interface AppBuildConfig { String versionName(); int versionCode(); boolean isDebug(); } :appbuildconfig :realappbuildconfig :app
BuildConfig final class RealAppBuildConfig implements AppBuildConfig { // ... }
public interface AppBuildConfig { String versionName(); int versionCode(); boolean isDebug(); } :appbuildconfig :realappbuildconfig :app android { // or libraryVariants applicationVariants { generateBuildConfigProvider { enabled = true } } }
More Resources • API Design As An Art: youtube.com/watch?v=Ve9HlnJ0wCM •
Writing Code That Lasts Forever: youtube.com/watch?v=YZstpc2939s • Effective Java • AppBuildConfig pattern: github.com/ZacSweers/CatchUp/pull/200
Code Review
Code Review Teach, don't tell
Code Review Approve with nits
Code Review
Static Analysis
Static Analysis
Static Analysis
Removing Tech Debt
Replace in Path (⌘⇧R) Find/Replace
Find/Replace Replace in Path (⌘⇧R) Command line tools > find
. -name "*.java" | xargs sed -i '' “s/import foo/import barr/g”
Kotlin ReplaceWith class Example { fun foo(s: String) {a/* old
*/ } fun usage() { foo("hello") } }
Kotlin ReplaceWith class Example { @Deprecated("Use Example.bar") fun foo(s: String)
{ /* old */ } fun bar(s: String) { /* new */ } fun usage() { foo("hello") } }
Kotlin ReplaceWith class Example { @Deprecated("Use Example.bar", replaceWith = ReplaceWith(“bar(s)"))
fun foo(s: String) { /* old */ } fun bar(s: String) { /* new */ } fun usage() { foo("hello") } }
Kotlin ReplaceWith class Example { @Deprecated("Use Example.bar", replaceWith = ReplaceWith(“bar(s)"))
fun foo(s: String) { /* old */ } fun bar(s: String) { /* new */ } fun usage() { foo("hello") } }
Kotlin ReplaceWith class Example { @Deprecated("Use Example.bar", replaceWith = ReplaceWith(“bar(s)"))
fun foo(s: String) { /* old */ } fun bar(s: String) { /* new */ } fun usage() { bar("hello") } }
import android.util.Pair fun doSomething() { val pair = Pair.create(“a”, “b”)
} <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent"> <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent"> <View /> </FrameLayout> </FrameLayout> Android Lint SuggestedFix
import androidx.core.util.Pair fun doSomething() { val pair = Pair.create(“a”, “b”)
} <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent"> <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent"> <View /> </FrameLayout> </FrameLayout> Android Lint SuggestedFix
Structural Find & Replace void main( Example ex, Other other)
{ ex.foo() ex.foo(“hi") other.foo() }
Structural Find & Replace void main( Example ex, Other other)
{ ex.foo() ex.foo(“hi") other.foo() } void main( Example ex, Other other) { ex.foo() ex.foo(“hi") other.foo() }
Structural Find & Replace void main( Example ex, Other other)
{ ex.foo() ex.foo(“hi") other.foo() } $Instance$ type=com.example.Example .foo($Parameter$ [0,∞]) $Instance$ type=com.example.Example .bar($Parameter$ [0,∞])
Structural Find & Replace void main( Example ex, Other other)
{ ex.bar() ex.bar(“hi") other.foo() } $Instance$ type=com.example.Example .foo($Parameter$ [0,∞]) $Instance$ type=com.example.Example .bar($Parameter$ [0,∞]) youtrack.jetbrains.com/issue/KT-10176
IntelliJ Plugin • Add your own refactor options • Leverage
IntelliJ’s tools • Good for automating multiple uses of refactors https://cutt.ly/find-matches-action
Kotlin Script File(args[0]).walkTopDown() .filter { it.extension in setOf("java", "kt") }
.filter { "/test/" !in it.absolutePath } .forEach {}
Kotlin Script File(args[0]).walkTopDown() .filter { it.extension in setOf("java", "kt") }
.filter { "/test/" !in it.absolutePath } .forEach { file: File -> val fileLines = file.readLines().toMutableList() // modify lines of file file.writeText(fileLines.joinToString("\n")) }
Kotlin Script File(args[0]).walkTopDown() .filter { it.extension in setOf("java", "kt") }
.filter { "/test/" !in it.absolutePath } .forEach { file: File -> val fileLines = file.readLines().toMutableList() // modify lines of file file.writeText(fileLines.joinToString("\n")) } $ brew install holgerbrandl/tap/kscript $ kscript MigrateToAndroidX.kts ~/project-root 16,866 files changed, 31,454 insertions(+), 31,415 deletions(-)
De-risking Change
Shadow Jobs
Shadow Jobs Android Gradle Plugin 4 beta/4.1 alpha Kotlin 1.4-M1
Gradle 6.4-rc -SNAPSHOT Androidx alphas JDK 8-14 Shadow Jobs
Offensive Programming
Offensive Programming abstract class Model { abstract List<String> modelList(); }
Offensive Programming abstract class Model { abstract ImmutableList<String> modelList(); }
Offensive Programming abstract class Model { abstract List<String> modelList(); }
ImmutableList
b7cb262 - Migrate lib1 d43aa98 - Migrate lib2 a1dc8d1 -
Migrate lib3 d843d8f - Migrate lib4 vs a13ab55 - Migrate all libs Safety Without Feature Flags
Photo by Webaroo on Unsplash
Photo by Pankaj Patel on Unsplash
Photo by Margarida CSilva on Unsplash
Photo by Hannes Wolf on Unsplash
Wrap Up
Photo by Gabriel Sollmann on Unsplash Lessons From a Librarian
James Barr - @JBarr21 Zac Sweers - @ZacSweers