How not to fuckup with building mobile SDK and make clients happy

How not to fuckup with building mobile SDK and make clients happy

Presentation from GDG DevFest Nantes 2017
More information at: https://devfest.gdgnantes.com/

Abstract:
Are you working on the client library? Or design a public API for the module that is going to be used by other team or department?

In this session, Vitality will share his experience and key learnings from building a mobile SDKs for last 4 years.

F456ed67b75e58e533d11b301f5f62b5?s=128

Vitaliy Zasadnyy

October 19, 2017
Tweet

Transcript

  1. @zasadnyy With building the mobile SDK How not to Fuck

    Up Vitaliy Zasadnyy Head of Mobile @ GetSocial
  2. @zasadnyy Integrated SDK. But it doesn’t work.

  3. Developer. GDG Lead. Public Speaker. @zasadnyy

  4. None
  5. None
  6. None
  7. SDK Lifecycle

  8. @zasadnyy SDK Lifecycle Develop 1

  9. @zasadnyy

  10. @zasadnyy SDK Lifecycle Develop 1

  11. @zasadnyy SDK Lifecycle Develop 1 Integrate 2 Support 3 Update

    4
  12. Develop 1

  13. @zasadnyy Start shaping your API Use Cases Examples Integration Tests

  14. @zasadnyy Cost of fixing API

  15. @zasadnyy Cost of fixing API Spend 10x more time on

    line of examples comparing to production code
  16. @zasadnyy NOT SURE? DROP IT!

  17. @zasadnyy IS BETTER LESS CODE

  18. @zasadnyy Boilerplate ➡ Copy/Paste ➡ Bugs Why?

  19. <receiver android:name="im.getsocial.InstallReferrerReceiver"> <intent-filter> <action android:name="com.android.vending.INSTALL_REFERRER"/> </intent-filter> </receiver> <provider android:name="im.getsocial.sdk.invites.ImageContentProvider" <meta-data

    android:name="im.getsocial.sdk.AppId" android:value="LuDPp7W0J4"/> <activity android:name="com.demo.GetSocialDeepLinkingActivity"> <intent-filter> <action android:name="android.intent.action.VIEW"/> <category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.BROWSABLE"/> <data android:scheme="https" android:host="demo.gsc.im"/> <data android:scheme="getsocial" android:host="LuDPp7W0J4"/> </intent-filter> </activity> GetSocial.init()
  20. <receiver android:name="im.getsocial.InstallReferrerReceiver"> <intent-filter> <action android:name="com.android.vending.INSTALL_REFERRER"/> </intent-filter> </receiver> <provider android:name="im.getsocial.sdk.invites.ImageContentProvider" <meta-data

    android:name="im.getsocial.sdk.AppId" android:value="LuDPp7W0J4"/> <activity android:name="com.demo.GetSocialDeepLinkingActivity"> <intent-filter> <action android:name="android.intent.action.VIEW"/> <category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.BROWSABLE"/> <data android:scheme="https" android:host="demo.gsc.im"/> <data android:scheme="getsocial" android:host="LuDPp7W0J4"/> </intent-filter> </activity>
  21. @zasadnyy How to solve? AndroidManifest merging Gradle plugin Android Studio

    plugin …
  22. @zasadnyy Gradle plugin apply plugin: 'im.getsocial' getsocial { appId "LGa80P9790xsg4"

    }
  23. @zasadnyy Auto initialisation <provider android:name="im.getsocial.AutoInitContentProvider" android:authorities="..." android:exported="false" />

  24. @zasadnyy IS BETTER LESS CODE

  25. @zasadnyy API SURPRISES AVOID

  26. @zasadnyy Avoid API surprises Thread.interrupted() Returns the current interrupted status

    and then clears it
  27. @zasadnyy Avoid API surprises

  28. @zasadnyy Avoid API surprises Thread.interrupted() Returns the current interrupted status

    and then clears it
  29. @zasadnyy Make API of your library as boring as possible

    - Chris Sells, Google
  30. @zasadnyy ? Library is crashing you app?

  31. @zasadnyy

  32. @zasadnyy CRASH HOST APP NEVER

  33. @zasadnyy GetSocial approach Rx Development Mode @Nullable / PMD /

    FindBugs / Lint
  34. @zasadnyy Rx chains Observable .just(MetaDataKey.APP_ID) .map(ValidateAppIdFunc.create()) .flatMap(TrackInstallFunc.create()) ... .subscribe((result) ->

    { ... }, (throwable) -> { // all exceptions end up here } );
  35. @zasadnyy Rx chains Observable .just(MetaDataKey.APP_ID) .map(ValidateAppIdFunc.create()) .flatMap(TrackInstallFunc.create()) ... .subscribe((result) ->

    { ... }, (throwable) -> { // all exceptions end up here } );
  36. @zasadnyy

  37. @zasadnyy INTERNALS HIDE

  38. @zasadnyy Hide internals

  39. @zasadnyy Hide internals Use .internal package Keep everything private by

    default
  40. @zasadnyy There is much more!

  41. Integrate

  42. @zasadnyy ? What is important to developers?

  43. @zasadnyy SIZE

  44. @zasadnyy List information about Library size Method count Proguard rules

  45. @zasadnyy COMPATIBILITY

  46. @zasadnyy Keep compatibility Select minimum supported platform version. After detailed

    market research Update maximum supported version. Continuously
  47. @zasadnyy SUPPORT

  48. @zasadnyy Give a voice to your users GitHub issue tracker

    Intercom Support email …
  49. @zasadnyy Get ready to repetitive questions

  50. @zasadnyy DOCS

  51. @zasadnyy Documentation is like sex. Even bad is better than

    nothing
  52. @zasadnyy Key parts Step by step tutorials Product guides API

    Reference
  53. @zasadnyy

  54. @zasadnyy

  55. @zasadnyy

  56. @zasadnyy What is wrong with snippet? CurrentUser user = getSocial.getCurrentUser();

  57. @zasadnyy What is wrong with snippet? CurrentUser user = getSocial.getCurrentUser();

  58. @zasadnyy ALL SNIPPETS MUST COMPILE

  59. @zasadnyy Better snippet import im.getsocial.sdk.GetSocial; import im.getsocial.sdk.CurrentUser; ... CurrentUser user

    = GetSocial.getInstance().getCurrentUser();
  60. @zasadnyy There is more GitHub Wiki, MkDocs, Jekyll Google Developer

    Documentation Style Guide
  61. @zasadnyy ? Favourite source of copy / paste code?

  62. @zasadnyy

  63. @zasadnyy DEMOS

  64. @zasadnyy Demo apps Make demos well documented Keep SDK integration

    code separated
  65. Support

  66. @zasadnyy ? You’ve got support request. Now what?

  67. @zasadnyy Two types of problems Integration time problems End-user side

    problems
  68. @zasadnyy Solving integration time problems Easy way to get SDK

    version Unique log tag Debug SDK configuration Actionable errors
  69. @zasadnyy Debug SDK configuration adb shell setprop \ debug.getsocial.sdk.app com.demo

  70. @zasadnyy Actionable errors public class GetSocialException extends RuntimeException { private

    final int _errorCode; … }
  71. @zasadnyy Actionable errors public class GetSocialException extends RuntimeException { private

    final int _errorCode; … }
  72. @zasadnyy Solving end-user side problems Comprehensive logs Errors analytics

  73. @zasadnyy Solving end-user side problems void trackError(GetSocialException exception) { ...

    AnalyticsTrackManager.trackAnalyticsEvent( AnalyticsEventDetails.Name.SDK_ERROR, eventProperties); }
  74. @zasadnyy

  75. @zasadnyy

  76. @zasadnyy s THINK ABOUT SUPPORT AHEAD

  77. Update

  78. @zasadnyy ? Why developers update SDKs?

  79. @zasadnyy Update. Build. And…

  80. @zasadnyy

  81. @zasadnyy UPDATES SMOOTH

  82. @zasadnyy Backward compatibility Use @Deprecation cycle /** * @deprecated use

    {@link #getAllIdentities()} instead. * Method will be removed in SDK v5.0.0. */ @Deprecated public List<String> getIdentities() { ... }
  83. @zasadnyy Semantic versioning v4.5.1 Major Minor Bugfix

  84. @zasadnyy Versioned packages import okhttp3; import im.getsocial.sdk6;

  85. @zasadnyy Versioned packages import okhttp3; import im.getsocial.sdk6; Partial transition A/B

    testing
  86. @zasadnyy Changelog Fixed issues New features Deprecations Upgrade guide

  87. @zasadnyy

  88. To sum up

  89. @zasadnyy PER APP 17 SDKs Source: Safe SDK

  90. @zasadnyy SDK Lifecycle Develop 1

  91. @zasadnyy SDK Lifecycle Develop Integrate Support Update 1 2 3

    4
  92. @zasadnyy API can be you biggest asset of liability -

    Joshua Bloch Put yourself in your customer’s shoes - Cesare Rocchi
  93. @zasadnyy Happy dog Make developers happy again.

  94. @zasadnyy @zasadnyy / zasadnyy.com Questions? Merci!