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
Lessons From Librarians Makers
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
jbarr21
April 20, 2020
310
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Lessons From Librarians Makers
jbarr21
April 20, 2020
More Decks by jbarr21
See All by jbarr21
Lessons From a Librarian
jbarr21
0
480
Scaling UI
jbarr21
2
340
It's Time to Develop a Watch Face
jbarr21
1
300
Featured
See All Featured
Making the Leap to Tech Lead
cromwellryan
135
9.9k
The SEO Collaboration Effect
kristinabergwall1
1
490
The AI Revolution Will Not Be Monopolized: How open-source beats economies of scale, even for LLMs
inesmontani
PRO
3
3.5k
Amusing Abliteration
ianozsvald
1
210
Jamie Indigo - Trashchat’s Guide to Black Boxes: Technical SEO Tactics for LLMs
techseoconnect
PRO
0
170
Bioeconomy Workshop: Dr. Julius Ecuru, Opportunities for a Bioeconomy in West Africa
akademiya2063
PRO
1
150
Impact Scores and Hybrid Strategies: The future of link building
tamaranovitovic
0
310
Agile Leadership in an Agile Organization
kimpetersen
PRO
0
170
JAMstack: Web Apps at Ludicrous Speed - All Things Open 2022
reverentgeek
1
480
The Pragmatic Product Professional
lauravandoore
37
7.3k
Visual Storytelling: How to be a Superhuman Communicator
reverentgeek
2
560
A Soul's Torment
seathinner
6
3k
Transcript
Photo by Gabriel Sollmann on Unsplash Lessons From a Librarian
James Barr - @JBarr21 Zac Sweers - @ZacSweers
cutt.ly/lessons-from-libs
cutt.ly/lessons-from-libs
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 interface Nail { void onHammer(); int length(); }
- you, writing libraries "How easy is it to do
the wrong thing?"
- you, writing libraries "How easy is it to do
the wrong thing?" "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
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 refactor operations 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
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