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

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. Building SDKs with clean
    architecture
    babylon Londroid April 2018
    Joao Alves and Sakis Kaliakoudas

    View Slide

  2. Babylon Services

    View Slide

  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

    View Slide

  4. ● Initial discussion
    ● Many parallel streams
    ● Usually 2 developers
    per SDK
    ● At most 4 teams
    working in parallel in
    different SDKs
    Planning

    View Slide

  5. How many SDKs?

    View Slide

  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

    View Slide

  7. What did the code look like?

    View Slide

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

    View Slide

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

    View Slide

  10. View related Domain
    Views Presenters Interactors
    Gateways/
    Repositories
    Retrofit
    Services
    What to ship?

    View Slide

  11. Views Presenters Interactors
    Gateways/
    Repositories
    Retrofit
    Services
    Legacy

    View Slide

  12. Views Presenters Interactors
    Gateways/
    Repositories
    Retrofit
    Services
    MVP

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  17. Gateways and entities sharing
    SDK
    Gateways
    Entities
    SDK 1
    SDK 2
    SDK N

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

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

    View Slide

  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

    View Slide

  24. Clinical
    Records API
    Client
    Clinical
    Records
    SDK
    Wrapping the interactors
    ClinicalRecordsApi clinicalRecordsApi = ClinicalRecordsSdk.getApiInstance();
    clinicalRecordsApi.doSomething(request, callback);
    Returns it to the client

    View Slide

  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

    View Slide

  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);

    View Slide

  27. String patientId = "patientId";
    GetAppointmentsRequest request =
    GetAppointmentsRequest.create(AppointmentType.UPCOMING, patientId);
    babylonAppointmentApi.getAppointments(request, new GetAppointmentsOutput() {
    @Override
    public void onFetchAppointmentsSuccess(List appointments) {
    if (appointments.isEmpty()) {
    getView().showNoAppointments();
    } else {
    getView().showAppointments(appointments);
    }
    }});
    Presenter using the SDK:

    View Slide

  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

    View Slide

  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

    View Slide

  30. Security
    ● No sensitive information
    stored locally
    ● Encryption with Android
    keystore
    ● Using Dexguard
    ● Logging based on
    environment
    ● Timber Wrapper

    View Slide

  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

    View Slide

  32. Activities in the SDKs?

    View Slide

  33. Kotlin?

    View Slide

  34. SDK size
    ● Trimming all dependencies
    ● Native libraries
    ● Dexguard

    View Slide

  35. Documentation
    ● JavaDoc with CheckStyle
    ● Release notes - from git diff to
    git code owners
    ● Sample App
    ● Wiki page

    View Slide

  36. Support
    ● Slack support
    ● Dedicated JIRA board
    ● Daily/Weekly calls

    View Slide

  37. Finish line
    ● Improved code quality
    ● Much less legacy code
    ● Modularized project
    ● Loads of knowledge
    ● Much bigger user base

    View Slide

  38. What does the code look like now?

    View Slide

  39. Lessons learned
    ● Planning + Planning +
    Planning
    ● Don’t create silos - merge
    often
    ● More logging
    ● Version controlled
    documentation

    View Slide

  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

    View Slide

  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

    View Slide

  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)

    View Slide