Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Building SDKs with clean architecture

Building SDKs with clean architecture

Ever had to create one or more SDKs to expose your company’s services to other apps? We went through this process at babylon and we’re here to share the experience.

In this talk we’ll try to demonstrate how we went from a business decision of allowing the use of babylon services by 3rd party apps, to actually making this happen.

We’ll share some of the challenges and phases we went through to get there and how that impacted our code base.

0f689a0408557ef6ec49f1aa36bec35f?s=128

Joao Alves

April 18, 2018
Tweet

Transcript

  1. Building SDKs with clean architecture babylon Londroid April 2018 Joao

    Alves and Sakis Kaliakoudas
  2. Babylon Services

  3. • Partner agreement to ship babylon services as SDKs •

    2 months to ship initial versions • 5 months for them to integrate • 3 months of going through a multi phase QA Lift off
  4. • Initial discussion • Many parallel streams • Usually 2

    developers per SDK • At most 4 teams working in parallel in different SDKs Planning
  5. How many SDKs?

  6. Babylon SDKs Appointments SDK Authentication SDK Consultation SDK User SDK

    NHS GP SDK Maps SDK Clinical Records SDK Payment SDK AI Chatbot SDK Monitor SDK Notifications SDK Common SDK Wrapper
  7. What did the code look like?

  8. Views Presenters Interactors Gateways/ Repositories Retrofit Services Clean architecture layers

  9. Views Presenters Interactors Gateways/ Repositories Retrofit Services What to ship?

  10. View related Domain Views Presenters Interactors Gateways/ Repositories Retrofit Services

    What to ship?
  11. Views Presenters Interactors Gateways/ Repositories Retrofit Services Legacy

  12. Views Presenters Interactors Gateways/ Repositories Retrofit Services MVP

  13. Views Presenters Interactors Gateways/ Repositories Retrofit Services MVP + Clean

  14. Moving stuff around App Gateways/ Repositories Interactors Entities SDK 1

    SDK 2 SDK N App Non-SDK Interactors Non-SDK Gateways SDK Gateways Entities
  15. Moving stuff around App Gateways/ Repositories Interactors Entities App Non-SDK

    Interactors Non-SDK Gateways SDK Gateways Entities SDK 1 SDK 2 SDK N
  16. Moving stuff around App Gateways/ Repositories Interactors Entities App Non-SDK

    Interactors Non-SDK Gateways SDK Gateways Entities SDK 1 SDK 2 SDK N
  17. Gateways and entities sharing SDK Gateways Entities SDK 1 SDK

    2 SDK N
  18. Splitting it up Gateways 1 Gateways 2 Gateways N Entities

    SDK 1 SDK 2 SDK N
  19. class DoSomethingInteractor{ private Gateway gateway; @Inject public DoSomethingInteractor(Gateway gateway){ this.gateway

    = gateway; } Disposable execute(Request request, Callback callback){ ... } } But what does it look like
  20. interface Callback{ void onSuccess(Result result); void onError(Exception exception); } class

    Request { String someField1; String someField2; } class Result { String someField3; String someField4; } But what does it look like
  21. class DoSomethingInteractor{ private Gateway gateway; @Inject public DoSomethingInteractor(Gateway gateway){ this.gateway

    = gateway; } Disposable execute(Request request, Callback callback){ ... } } But what does it look like
  22. Client Clinical Records SDK Wrapping the interactors ClinicalRecordsApi clinicalRecordsApi =

    ClinicalRecordsSdk.getApiInstance(); clinicalRecordsApi.doSomething(request, callback); Client requests an instance of the API
  23. Clinical Records API Client Clinical Records SDK Wrapping the interactors

    ClinicalRecordsApi clinicalRecordsApi = ClinicalRecordsSdk.getApiInstance(); clinicalRecordsApi.doSomething(request, callback); The SDK class instantiates the API
  24. Clinical Records API Client Clinical Records SDK Wrapping the interactors

    ClinicalRecordsApi clinicalRecordsApi = ClinicalRecordsSdk.getApiInstance(); clinicalRecordsApi.doSomething(request, callback); Returns it to the client
  25. Clinical Records API Interactors Interactors Interactors Gateways Interactors Entities Client

    Clinical Records SDK Wrapping the interactors ClinicalRecordsApi clinicalRecordsApi = ClinicalRecordsSdk.getApiInstance(); clinicalRecordsApi.doSomething(request, callback); Client can access all the SDK interactors via the API
  26. SDK API Interface /** * Get list of appointments for

    the main user and its registered children * (if any). * * @param request the request object that contains the required information * to get the user appointments. * @param output the callback through which the results are returned. * * @return an RxJava 2 {@link Disposable} resource to manage this request. */ Disposable getAppointments(GetAppointmentsRequest request, GetAppointmentsOutput output);
  27. String patientId = "patientId"; GetAppointmentsRequest request = GetAppointmentsRequest.create(AppointmentType.UPCOMING, patientId); babylonAppointmentApi.getAppointments(request,

    new GetAppointmentsOutput() { @Override public void onFetchAppointmentsSuccess(List<Appointment> appointments) { if (appointments.isEmpty()) { getView().showNoAppointments(); } else { getView().showAppointments(appointments); } }}); Presenter using the SDK:
  28. Dog fooding • Using the SDKs inside our Apps •

    Local development with local gradle module dependencies • CI builds the SDKs, publishes them, then builds the app using artifact dependencies
  29. Build and deploy Local Maven Repo Artifactory Single Gradle Task

    • ~25 releases in 10 months (excluding hotfixes) • Releases around every 10 days a day an hour a minute
  30. Security • No sensitive information stored locally • Encryption with

    Android keystore • Using Dexguard • Logging based on environment • Timber Wrapper
  31. Uniquely identifying clients via their public certificate Offline: • Get

    certificate hash • Merge it together with the application id to generate a new hash • Save this hash inside the SDKs Runtime: • Calculate the same hash • Match it against the precomputed value
  32. Activities in the SDKs?

  33. Kotlin?

  34. SDK size • Trimming all dependencies • Native libraries •

    Dexguard
  35. Documentation • JavaDoc with CheckStyle • Release notes - from

    git diff to git code owners • Sample App • Wiki page
  36. Support • Slack support • Dedicated JIRA board • Daily/Weekly

    calls
  37. Finish line • Improved code quality • Much less legacy

    code • Modularized project • Loads of knowledge • Much bigger user base
  38. What does the code look like now?

  39. Lessons learned • Planning + Planning + Planning • Don’t

    create silos - merge often • More logging • Version controlled documentation
  40. • Problems are bound to happen and trust us they

    will happen. And they don’t come on their own they come in herds. • Work your way through them and you’ll eventually get to the finish line. Don’t Panic
  41. Questions? Presented by Joao Alves and Sakis Kaliakoudas Say hi

    on Twitter & Medium: @jcmsalves & @skaliakoudas PS: we’re hiring, come and talk to us to know more
  42. Useful links • SDK class example: (https://tinyurl.com/MyBossMadeMeDoThis) • Getting a

    certificate hash (https://tinyurl.com/tralalatralalo) • Merging a certificate hash with an application id to generate a new hash (https://tinyurl.com/we-r-hiringgg) • Calculating the same hash at runtime (https://tinyurl.com/PleaseDontAskQuestions)