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
WebMCP Challenge に星空観察アプリで参加した話
okajun35
0
140
高専キャリア LT 発表内容
crysta1221
6
5.7k
GraphRAGのKnowledge Graphを 直接!見る/View-GraphRAG's-KnowledgeGraph-directly!
tyumugi1113
1
290
標準パッケージに uuid が追加された 背景から見る Go らしい意思決定 / go_127_uuid_decision
convto
5
6.4k
Swift愛好会100回記念 第1回を振り返る
jollyjoester
0
120
市販E-Readerを乗っ取れ 〜Embedded Swiftで電子ペーパーガジェットを制御する〜
trickart
0
180
Foundry Localでエージェント開発
seosoft
0
180
Streamlitで実現する自然言語データアプリ開発
ayumu_yamaguchi
0
220
AIエージェント時代のコードレビューを設計する
nogu66
6
2.6k
AI Agent時代のリアーキテクチャ戦略と実践
hokaccha
9
4k
Webの地図
yosuke_furukawa
PRO
6
4.3k
AWS DevOps Agentで インシデント対応をAIに任せたい
honmarkhunt
7
2.8k
Featured
See All Featured
Exploring anti-patterns in Rails
aemeredith
3
500
Crafting Experiences
bethany
1
330
Designing for humans not robots
tammielis
254
26k
Speed Design
sergeychernyshev
33
2.1k
Building Flexible Design Systems
yeseniaperezcruz
330
41k
Statistics for Hackers
jakevdp
799
230k
Leveraging LLMs for student feedback in introductory data science courses - posit::conf(2025)
minecr
1
390
30 Presentation Tips
portentint
PRO
1
390
Game over? The fight for quality and originality in the time of robots
wayneb77
1
270
The AI Revolution Will Not Be Monopolized: How open-source beats economies of scale, even for LLMs
inesmontani
PRO
3
3.7k
The Straight Up "How To Draw Better" Workshop
denniskardys
239
140k
Leading Effective Engineering Teams in the AI Era
addyosmani
9
2.6k
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