Ensuring API parity while maintaining a sample app for the Babylon SDK

Antonis Tsiapaliokas
Babylon Engineering
5 min readOct 14, 2019

In this article, we explore how we manage the source code of our sample application that accompanies our Babylon SDK for Android and how we make sure that the sample application is kept in sync with the SDK when breaking changes are introduced.

The Babylon SDK

In Babylon Health we provide professional healthcare services through our mobile applications, but we also make these services available to our partners via our mobile SDK (note the SDK is not publicly available, but only available to selected commercial partners). Overall we are following a mono-repo approach, so the SDK lives in the same repository as our Android application. At the same time, we offer to our partners a sample application that they can use to understand how to integrate the SDK and the flows associated to performing important actions, such as making a payment or booking an appointment.

The problem

As our sample application lives in a separate GitHub repository, to be accessible by our partners, and the SDK lives in our mono-repo, it was very easy to introduce a breaking change in the SDK without keeping the sample app in sync with these changes. That meant that whenever we had to do a new SDK release, the sample application wasn’t in a releasable state. This only got worse as the team got bigger (we are more than 30 now!) leading to a need to automatically catch these issues during feature development, rather than during an SDK release. Furthermore, we noticed that it was not very convenient for engineers to switch between multiple git repositories to fix these issues.

Brainstorming

After a few discussions with the team, we narrowed down to 3 potential solutions:

  • Using Gradle composite builds to link the 2 repositories together so that the sample application can consume the local SDK Gradle modules and then verify whether it can build properly.
  • Using Git submodules to achieve something similar.
  • Moving the sample application into the main mono-repo.

Discussing the pros and cons of these solutions we quickly rejected using composite builds because at the time there were a few pending issues with Android Studio, and it also wasn’t overall that straightforward for an engineer to link the 2 projects together to build the sample app with the local SDK.

We then also rejected the Git submodules approach as we felt that it introduces a lot of unneeded complexity and most of the engineers in the team had horror stories to share!

That left us with the option to move the sample app inside the mono-repo. Of course, that was challenging by itself as we did not want to provide access to our partners to our main repository, but at the same time, they needed to have access to the sample application, in order to understand how to integrate our SDK.

Moving sample app into the codebase

The first step for this was to move the whole sample application codebase into a directory in the main Android repository, then to import the sample application as a Gradle module in the project via the settings.gradle file. We ended up adding a boolean flag in the gradle.properties file so that we can load this module on-demand, to make sure that the sample application classes are not indexed by Android Studio at all during normal development (and thus returned when searching for classes in the IDE), but CI is able to pick this module up and build it.

Boolean flag in the gradle.properties file to control whether the sample app is loaded by Gradle or not.
This is how the flag is used in the settings.gradle file

After moving the project and including it as shown above, we tried to build it but quickly realized that the Gradle dependencies of the sample application were pointing to fixed aar versions of our SDK, while we wanted to build it with local SDK module dependencies. The solution for this was simple, just change the dependencies, but there was a hidden issue we identified: Changing the dependencies would introduce changes in the sample application project, meaning that these changes would be visible to our partners looking at sample application and not having any context about the main Android repository.

This is what the sample application dependencies block looks like. Note the `sampleAppUsePublishedSdkArtifacts` flag that controls whether the SDK artifact dependencies are included or not.

To solve this we ended up including a property in the sample app to enable or disable the declaration of our SDK artifact dependencies and at the same time to inject the local module dependencies into the sample application externally, as shown in the snippet below. In this way, the only change that we introduced in the sample application was just an if statement.

This is how we inject local module dependencies for the SDKs into the sample application project without actually including any changes in the `build.gradle` file of the sample application.

Syncing the sample app back to the public repository

The final challenge was around syncing this SDK sample application back to the GitHub project that our partners have access to. To do this we created a Gradle script that:

  • Clone the sample application from the external GitHub repository into the mono-repo, in a new directory sdk/sample-application
  • Copy the sample application that lives together in the mono-repo into this new sdk/sample-application folder.
  • Commit and push to the external sample application GitHub repository that our partners access.
The Gradle task that performs the syncing of the sample application back into the external SDK sample application GitHub project.

Then, as a part of our SDK release process, we also triggered this Gradle task on our CI server.

./gradlew prepareSampleAppSdkForRelease -PBranchName=<sample-app-target-branch>

After this is done we create a PR in the other repository to merge these changes into the master branch of that repository.

Ending

The above setup ended up working really well for us because:

  • We are able to build the sample app on every pull request.
  • If there is a breaking source code change, we can detect it easily and the developers are able to fix it as a part of the same pull request.
  • Updating the sample application doesn’t require big changes to our existing workflow because it is inside the same repository.
  • Our mono-repo is being used as a single source of truth, so we are always confident about the quality of our sample application.
  • We are still able to ship the sample application along with our SDK using a CI job relatively easily.

If you love Kotlin and want to help us build the future of healthcare, we are currently hiring to extend our Android team. You can check out how our interview process works here, or apply here.

--

--