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.

Sakis Kaliakoudas

April 17, 2018
Tweet

More Decks by Sakis Kaliakoudas

Other Decks in Technology

Transcript

  1. • 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
  2. • Initial discussion • Many parallel streams • Usually 2

    developers per SDK • At most 4 teams working in parallel in different SDKs Planning
  3. 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
  4. Moving stuff around App Gateways/ Repositories Interactors Entities SDK 1

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

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

    Interactors Non-SDK Gateways SDK Gateways Entities SDK 1 SDK 2 SDK N
  7. 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
  8. 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
  9. 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
  10. Client Clinical Records SDK Wrapping the interactors ClinicalRecordsApi clinicalRecordsApi =

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

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

    ClinicalRecordsApi clinicalRecordsApi = ClinicalRecordsSdk.getApiInstance(); clinicalRecordsApi.doSomething(request, callback); Returns it to the client
  13. 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
  14. 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);
  15. 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:
  16. 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
  17. 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
  18. Security • No sensitive information stored locally • Encryption with

    Android keystore • Using Dexguard • Logging based on environment • Timber Wrapper
  19. 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
  20. Documentation • JavaDoc with CheckStyle • Release notes - from

    git diff to git code owners • Sample App • Wiki page
  21. Finish line • Improved code quality • Much less legacy

    code • Modularized project • Loads of knowledge • Much bigger user base
  22. Lessons learned • Planning + Planning + Planning • Don’t

    create silos - merge often • More logging • Version controlled documentation
  23. • 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
  24. 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
  25. 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)