$30 off During Our Annual Pro Sale. View Details »

Building for Developers - Droidcon Italy 2019

Building for Developers - Droidcon Italy 2019

Many teams are designed so that engineers can take an abstract view of the customer and focus on implementation. But when the customers are other engineers, that entire dynamic is thrown on its head.

In this talk, Ty will walk you through the best practices of building great products for developers, from team processes to the technical delivery.

Topics covered will include: Building customer personas and product strategies, Developer Experience research and analytics, customer empathy and support structures, API Design and usability, testing, code distribution, and creating great documentation.

Ty Smith

April 04, 2019
Tweet

More Decks by Ty Smith

Other Decks in Programming

Transcript

  1. DESIGNING FOR
    DEVELOPERS
    Ty Smith
    uber.github.io
    @tsmith

    View Slide

  2. Building for
    Developers
    Ty Smith
    uber.github.io
    @tsmith

    View Slide

  3. USER
    EXPERIENCE
    @tsmith

    View Slide

  4. USER DEVELOPER
    EXPERIENCE
    @tsmith

    View Slide

  5. Developer Experience (DX) - Overiew
    — Developer Product Research
    — Developer Usability Focuses
    — Library Quality Standards
    — Best Practices for Releases
    — Managing Communities
    @tsmith

    View Slide

  6. Product Research
    @tsmith

    View Slide

  7. Standard product workflow
    @tsmith

    View Slide

  8. Developer Tool workflow
    @tsmith

    View Slide

  9. People Need Focus
    @tsmith | https://twitter.com/marcos_placona/status/882487720597237760

    View Slide

  10. Expertise Bias
    @tsmith

    View Slide

  11. Product's role in a developer world
    @tsmith

    View Slide

  12. Finding the right job for your product
    @tsmith | https://hbr.org/2016/09/know-your-customers-jobs-to-be-done

    View Slide

  13. Finding the right job for your
    product
    @tsmith | https://hbr.org/2016/09/know-your-customers-jobs-to-be-done

    View Slide

  14. Finding the right job for your product
    Crash Reporting
    -Stability
    -Time to build features
    -Insight into instability
    @tsmith | CC-BY-2.0 - Bill Ward | https://hbr.org/2016/09/know-your-customers-jobs-to-be-done

    View Slide

  15. Developer Customers
    @tsmith

    View Slide

  16. Developer Demographics
    @tsmith | Search Engine Guide

    View Slide

  17. Developer Personas
    Name Role Company
    Frank CS Student University
    Betty Founder Seed Startup
    João Engineer New Market Series A
    Paul Product Manager Hypergrowth Series C
    Sharon Staff Engineer Public SV Company
    Hannah Consultant Enterprise Company
    @tsmith | https://wiki.mozilla.org/DeveloperExperience/Personas

    View Slide

  18. Developer Research
    — Watch them integrate
    — Dig into expectations
    — Survey
    @tsmith

    View Slide

  19. Success Objectives
    — Developer Productivity
    — Developer Happiness
    — Developer Trust
    @tsmith

    View Slide

  20. @tsmith

    View Slide

  21. Usability
    @tsmith | CC-BY-2.0 - Sherman Paggi

    View Slide

  22. Autodispose
    Automatic binding+disposal of
    RxJava 2 streams.
    @tsmith | https://github.com/uber/AutoDispose

    View Slide

  23. Easy to Integrate
    dependencies {
    implementation 'com.uber.autodispose:autodispose:x.y.z'
    }
    observable
    .doStuff()
    .as(autoDisposable(this))
    .subscribe(s -> ...)
    @tsmith | https://github.com/uber/AutoDispose

    View Slide

  24. Easy to Integrate
    dependencies {
    implementation 'com.uber.autodispose:autodispose:x.y.z'
    }
    observable
    .doStuff()
    .as(autoDisposable(this))
    .subscribe(s -> ...)
    @tsmith | https://github.com/uber/AutoDispose

    View Slide

  25. Concise
    observable
    .doStuff()
    .as(autoDisposable(this))
    .subscribe(s -> ...)
    @tsmith | https://github.com/uber/AutoDispose

    View Slide

  26. Intuitive
    //-------------------Vanilla RXJava----------------
    fun doStuff() {
    subcription = observable.doStuff().subscribe(s -> ...)
    }
    override fun onDestroy() = subscription.unsubscribe()
    //-------------------Autodispose-------------------
    observable.doStuff()
    .as(autoDisposable(this))
    .subscribe(s -> ...)
    @tsmith | https://github.com/uber/AutoDispose

    View Slide

  27. Intuitive
    //-------------------Vanilla RXJava----------------
    fun doStuff() {
    subcription = observable.doStuff().subscribe(s -> ...)
    }
    override fun onDestroy() = subscription.unsubscribe()
    //-------------------Autodispose-------------------
    observable.doStuff()
    .as(autoDisposable(this))
    .subscribe(s -> ...)
    @tsmith | https://github.com/uber/AutoDispose

    View Slide

  28. Consistency
    public interface ScopeHandler {
    @CheckReturnValue
    Function forFlowable();
    @CheckReturnValue
    Function forObservable();
    @CheckReturnValue
    Function forMaybe();
    @CheckReturnValue
    Function forSingle();
    @CheckReturnValue
    Function forCompletable();
    }
    @tsmith | https://github.com/uber/AutoDispose

    View Slide

  29. Composition
    public interface ObservableSubscribeProxy {
    Disposable subscribe();
    Disposable subscribe(Consumer super T> onNext);
    ...
    TestObserver test();
    ...
    }
    @tsmith | https://github.com/uber/AutoDispose

    View Slide

  30. Resilient and Defensive
    @Override public ObservableSubscribeProxy apply(final Observable upstream) {
    return new ObservableSubscribeProxy() {
    @Override public Disposable subscribe() {
    return new AutoDisposeObservable<>(upstream, scope).subscribe();
    }
    ...
    };
    }
    @tsmith | https://github.com/uber/AutoDispose

    View Slide

  31. Flexibility
    public interface LifecycleScopeProvider {
    Observable lifecycle();
    Function correspondingEvents();
    E peekLifecycle();
    }
    @tsmith | https://github.com/uber/AutoDispose

    View Slide

  32. Flexibility
    dependencies {
    implementation 'com.uber.autodispose:autodispose-android:x.y.z'
    implementation 'com.uber.autodispose:autodispose-android-archcomponents:x.y.z'
    implementation 'com.uber.autodispose:autodispose-kotlin:x.y.z'
    implementation 'com.uber.autodispose:autodispose-rxlifecycle:x.y.z'
    }
    @tsmith | https://github.com/uber/AutoDispose

    View Slide

  33. Testability
    dependencies {
    implementation 'com.uber.autodispose:autodispose-android-archcomponents:x.y.z'
    testImplementation 'com.uber.autodispose:autodispose-android-archcomponents-test:x.y.z'
    }
    TestLifecycleOwner lifecycle = TestLifecycleOwner.create();
    subject.as(autoDisposable(from(lifecycle))).subscribe(o);
    lifecycle.emit(Lifecycle.Event.ON_CREATE);
    ...
    lifecycle.emit(Lifecycle.Event.ON_DESTROY);
    subject.onNext(1);
    o.assertNoMoreEvents();
    @tsmith | https://github.com/uber/AutoDispose

    View Slide

  34. Debugability
    public final class AutoDisposePlugins {
    public static void lockdown() {
    lockdown = true;
    }
    public static void setOutsideLifecycleHandler(
    @Nullable Consumer super OutsideLifecycleException> handler) {
    if (lockdown) {
    throw new IllegalStateException("Plugins can't be changed anymore");
    }
    outsideLifecycleHandler = handler;
    }
    }
    @tsmith | https://github.com/uber/AutoDispose

    View Slide

  35. Documentation
    /**
    * Entry point for auto-disposing streams from a {@link ScopeProvider}.
    *
    * Example usage:
    *
    * Observable.just(1)
    * .as(AutoDispose.autoDisposable(scope))
    * .subscribe(...)
    *
    *
    * @param provider the target scope provider
    * @param the stream type.
    * @return an {@link AutoDisposeConverter} to transform with operators like
    * {@link Observable#as(ObservableConverter)}
    */
    public static AutoDisposeConverter autoDisposable(final ScopeProvider provider) {...}
    @tsmith | https://github.com/uber/AutoDispose

    View Slide

  36. Example Code
    @Override protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    // Using automatic disposal, this should determine that the correct time to
    // dispose is onDestroy (the opposite of onCreate).
    Observable.interval(1, TimeUnit.SECONDS)
    .doOnDispose((value) -> {
    Log.i(TAG, "Disposing subscription from onCreate()"))
    })
    .as(autoDisposable(from(this)))
    .subscribe((value) -> {
    Log.i(TAG, "Started in onCreate(), running until onDestroy(): " + num);
    });
    }
    @tsmith | https://github.com/uber/AutoDispose

    View Slide

  37. @tsmith

    View Slide

  38. Quality
    Primum non nocere
    @tsmith

    View Slide

  39. Quality
    Stability
    @tsmith

    View Slide

  40. Performance
    @tsmith

    View Slide

  41. Size
    @tsmith| source: https://www.youtube.com/watch?v=CVQ8cg_WIwY

    View Slide

  42. Data usage
    @tsmith

    View Slide

  43. Transitive Dependencies
    @tsmith

    View Slide

  44. @tsmith

    View Slide

  45. Releases
    @tsmith

    View Slide

  46. Semantic Versioning - X.Y.Z
    Decimal Use Example
    X - Major API Change Changed Public
    Method Name
    Y _ Minor Feature Added New
    Functionality
    Z - Patch Fix Fixed Crash
    @tsmith

    View Slide

  47. Changelogs
    @tsmith

    View Slide

  48. Deprecation
    — Be thoughtful about
    introducing new APIs
    — Respect semantic versioning
    — Mark methods as deprecated
    — Set expected timeline or
    version for removal
    — Incentivize updates
    @tsmith

    View Slide

  49. Deprecation
    /**
    * Extension that proxies to [Observable.as] + [AutoDispose.autoDisposable]
    */
    @Deprecated(
    level = ERROR,
    message = "Replaced with autoDisposable() to match top level APIs.",
    replaceWith = ReplaceWith("autoDisposable(scope)",
    "com.uber.autodispose.kotlin.autoDisposable")
    )
    @CheckReturnValue
    inline fun Observable.autoDisposeWith(scope: Maybe<*>): ObservableSubscribeProxy
    = this.`as`(AutoDispose.autoDisposable(scope))
    @tsmith | https://github.com/uber/AutoDispose

    View Slide

  50. Community
    @tsmith | CC-BY-4.0 - Billie Grace Ward | http://uk.droidcon.com/skillscasts/11019-open-source-and-building-communities

    View Slide

  51. Issues
    @tsmith

    View Slide

  52. Contributors
    @tsmith

    View Slide

  53. DX - Wrap up
    — Developer Product Research
    — Developer Usability Focuses
    — Library Quality Standards
    — Best practices for Releases
    — Managing Communities
    @tsmith

    View Slide

  54. BUILDING FOR
    DEVELOPERS
    Ty Smith
    uber.github.io
    @tsmith

    View Slide