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
jbarr21
April 19, 2020
Programming
490
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
330
Scaling UI
jbarr21
2
350
It's Time to Develop a Watch Face
jbarr21
1
310
Other Decks in Programming
See All in Programming
iOSDC2026登壇資料.pdf
riofujimon
0
120
Security issues being discussed on Web Platforms
petamoriken
0
820
LL言語やWebフレームワークのPostgreSQL対応 〜DBの機能がユーザーに届くまで〜
kentaroutakeda
0
150
AIは賢い。でも実行環境は? CLIおじさんがAI時代に伝えたいこと ~ CLIおじさんがAI時代に伝えたいこと ~
curekoshimizu
1
240
初心者DevRelとして参加者だった私が、DevRel Talks!#2に登壇するまでにしてきたこと
sokohirai
0
370
Laravelのアプリケーションをどこにデプロイするか #ツナギメオフライン.9
akase244
0
130
『寄り添うラジオ』をAIで作る 体験価値から逆算した、会話しないUXと品質設計
theoriatec2024
3
150
The Good Stuff, Not the Slop: Engineering High-Quality Android Apps with Modern AI Tooling
danybony
1
240
Building an Out-of-Order CPU
latte72
1
760
From 6 People Classroom Meetup to 100 People Regional Conference / FOSS4G Hiroshima 2026
furukawayasuto
0
150
技術的負債を組織課題として解く-増えすぎたマイクロサービスとの戦い-
reimaru
1
510
App Intentsのビルドプロセスを支える技術
kntkymt
0
310
Featured
See All Featured
Connecting the Dots Between Site Speed, User Experience & Your Business [WebExpo 2025]
tammyeverts
11
1k
How to build a perfect <img>
jonoalderson
1
6k
Balancing Empowerment & Direction
lara
6
1.3k
職位にかかわらず全員がリーダーシップを発揮するチーム作り / Building a team where everyone can demonstrate leadership regardless of position
madoxten
69
65k
A better future with KSS
kneath
240
18k
VelocityConf: Rendering Performance Case Studies
addyosmani
331
25k
Marketing to machines
jonoalderson
1
5.8k
SEOcharity - Dark patterns in SEO and UX: How to avoid them and build a more ethical web
sarafernandez
0
270
Automating Front-end Workflow
addyosmani
1369
210k
Highjacked: Video Game Concept Design
rkendrick25
PRO
1
450
Building Applications with DynamoDB
mza
96
7.2k
What's in a price? How to price your products and services
michaelherold
247
13k
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