ADDC 2018 - Ty Smith: Building for Developers

ADDC 2018 - Ty Smith: Building for Developers

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 it's 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.

Watch the video: https://www.youtube.com/watch?v=1cuhWSZqDCM
More about the talk, authors & slides: https://addconf.com/2018/schedule/building-for-developers/
Read about the conference: https://addconf.com

7a3baf2e1158e358885cdf7e89b9aa55?s=128

Ty Smith

July 04, 2018
Tweet

Transcript

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

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

  3. Overview — Developer Product Research — Developer Usability Focuses —

    Library Quality Standards — Best Practices for Releases — Managing Communities @tsmith
  4. Product Research @tsmith

  5. Standard product workflow @tsmith

  6. Developer Tool workflow @tsmith

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

  8. Expertise Bias @tsmith

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

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

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

  12. 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
  13. Developer Customers @tsmith

  14. Developer Demographics @tsmith | Search Engine Guide

  15. Developer Personas Name Role Company Frank CS Student University Betty

    Founder Seed Startup João Engineer Emerging 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
  16. Developer Research — Watch them integrate — Dig into expectations

    — Survey @tsmith
  17. Success Objectives — Developer Productivity — Developer Happiness — Developer

    Trust @tsmith
  18. @tsmith

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

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

  21. Easy to Integrate dependencies { implementation 'com.uber.autodispose:autodispose:x.y.z' } observable .doStuff()

    .as(autoDisposable(this)) //<--Here's the magic. .subscribe(s -> ...) @tsmith | https://github.com/uber/AutoDispose
  22. Concise observable .doStuff() .as(autoDisposable(this)) .subscribe(s -> ...) @tsmith | https://github.com/uber/AutoDispose

  23. 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
  24. Consistency public interface ScopeHandler { @CheckReturnValue <T> Function<Flowable<? extends T>,

    FlowableSubscribeProxy<T>> forFlowable(); @CheckReturnValue <T> Function<Observable<? extends T>, ObservableSubscribeProxy<T>> forObservable(); @CheckReturnValue <T> Function<Maybe<? extends T>, MaybeSubscribeProxy<T>> forMaybe(); @CheckReturnValue <T> Function<Single<? extends T>, SingleSubscribeProxy<T>> forSingle(); @CheckReturnValue Function<Completable, CompletableSubscribeProxy> forCompletable(); } @tsmith | https://github.com/uber/AutoDispose
  25. Composition public interface ObservableSubscribeProxy<T> { Disposable subscribe(); Disposable subscribe(Consumer<? super

    T> onNext); ... TestObserver<T> test(); ... } @tsmith | https://github.com/uber/AutoDispose
  26. Resilient and Defensive @Override public ObservableSubscribeProxy<T> apply(final Observable<T> upstream) {

    return new ObservableSubscribeProxy<T>() { @Override public Disposable subscribe() { return new AutoDisposeObservable<>(upstream, scope).subscribe(); } ... }; } @tsmith | https://github.com/uber/AutoDispose
  27. Flexibility public interface LifecycleScopeProvider<E> { Observable<E> lifecycle(); Function<E, E> correspondingEvents();

    E peekLifecycle(); } @tsmith | https://github.com/uber/AutoDispose
  28. 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
  29. 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
  30. 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
  31. Documentation /** * Entry point for auto-disposing streams from a

    {@link ScopeProvider}. * <p> * Example usage: * <pre><code> * Observable.just(1) * .as(AutoDispose.<Integer>autoDisposable(scope)) * .subscribe(...) * </code></pre> * * @param provider the target scope provider * @param <T> the stream type. * @return an {@link AutoDisposeConverter} to transform with operators like * {@link Observable#as(ObservableConverter)} */ public static <T> AutoDisposeConverter<T> autoDisposable(final ScopeProvider provider) {...} @tsmith | https://github.com/uber/AutoDispose
  32. 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
  33. @tsmith

  34. Quality Primum non nocere @tsmith

  35. Quality Stability @tsmith

  36. Performance @tsmith

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

  38. Data usage @tsmith

  39. Transitive Dependencies @tsmith

  40. @tsmith

  41. Releases @tsmith

  42. 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
  43. Changelogs @tsmith

  44. Deprecation — Be thoughtful about introducing new APIs — Respect

    semantic versioning — Mark methods as deprecated — Set expected timeline or version for removal — Incentivize updates @tsmith
  45. 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 <T> Observable<T>.autoDisposeWith(scope: Maybe<*>): ObservableSubscribeProxy<T> = this.`as`(AutoDispose.autoDisposable(scope)) @tsmith | https://github.com/uber/AutoDispose
  46. Community @tsmith | CC-BY-4.0 - Billie Grace Ward | http://uk.droidcon.com/skillscasts/11019-open-source-and-building-communities

  47. Issues @tsmith

  48. Contributors @tsmith

  49. Wrap up — Developer Product Research — Developer Usability Focuses

    — Library Quality Standards — Best practices for Releases — Managing Communities @tsmith
  50. BUILDING FOR DEVELOPERS Ty Smith uber.github.io @tsmith