How to avoid duplicate code when using similar SDKs

As software engineers, nothing bothers us more than duplicating code within a project. For every line of duplicate code, it potentially doubles the effort required for each bug fix, refactor, and enhancement later in the life of the project. You may have heard of the DRY principle — “don’t repeat yourself” — that most engineers try to follow.

Spiderman identifying a *cough* duplicate bug

Duplicating code for nearly identical SDKs

It’s frustrating to encounter situations where code must be slightly different due to dependencies. The first place I encountered this was the Amazon Maps API. I maintain an open-source Android app called OneBusAway that used the Android Maps API v2, and I wanted to launch a version on the Amazon app store that used the Amazon Maps API instead.

  • AmazonMapOptions instead of GoogleMapOptions
  • import package names of com.amazon.geo.mapsv2 instead of com.google.android.gms.maps for classes like LatLng, etc.

The solution — Gradle to the rescue

I started exploring Gradle in more detail, which is an absolutely amazing build system for Android, especially if you remember the old days of Eclipse and Ant scripts.

  1. Replace all Google import and class namespaces (com.google.android.gms.maps) in the Amazon file with the Amazon version (com.amazon.geo.mapsv2)
  2. Replace all references to GoogleMap with AmazonMap
  3. Add a comment block header to each class (from a templateAmazonMapsFileHeader.txt) that says DO NOT EDIT, etc., with an explanation of how those classes are generated (to avoid someone else unfamiliar with the build process from making changes that would get erased)
  4. Exclude a file named ProprietaryMapHelpV2.java from this process. This is a utility class that contains small implementation differences between each Maps API, such as a method isMapsInstalled() that uses a different process to verify if the Maps API library is available on the device. We want these classes to be different for each flavor, so we don’t copy it.

Copying libraries — Android Maps SDK v3 beta

I thought the above solution might be a one-off, but when working on the Android Maps Utils library project the team hit the same issue trying to support both the Android Maps SDK v2 and v3 beta in the same project.

  • Different dependencies in build.gradle
  • the -javadoc.jar file only created docs for one flavor, seemingly also related to limitations of the Gradle task
  • automated publishing code for the generated artifacts became very complex

…and back to apps

We used this copy/replace process yet again for the Google Maps Android Samples project, but, because these are apps and not libraries, we used build flavors instead of separate modules. Using build flavors allows sharing resources, etc. that you can’t easily do across modules. See these links for the Java and Kotlin projects for examples.

Tips and tricks

You should keep a few things in mind when using this technique to copy classes from one place in the project to another.

Source of truth

All code changes MUST be on the source-of-truth. Pick the original code you want to treat as the source of truth, and ONLY edit that code. Make it clear to other contributors, especially if the project is open-source, that edits shouldn’t be made to the copied code.

SDK APIs don’t have to be exactly 1:1

As I mentioned above, you’ll typically have a few small differences in the SDKs when using them within an app. For example, in OneBusAway, I wanted to take advantage of the Google SDK ability to set the marker Z index for better control of the display. However, the Amazon SDK didn’t include a Marker.setZIndex() method — so a straight copy from the code using the Google SDK wouldn’t build.

Conclusions

In summary, when supporting multiple similar SDKs you can use a Gradle copy task to copy source files and use filters to automatically replace simple items like import packages and class names. This saves a lot of time when trying to maintain code that relies on two nearly identical SDKs.

  • between modules in libraries to simplify the release process

Acknowledgements

  • Thanks to Chris Arriola for implementing the Gradle copy task for Android Maps Utils, KTX libraries, and Google Maps Android Samples projects!

Improving the world, one byte at a time. @sjbarbeau, https://github.com/barbeau, https://www.linkedin.com/in/seanbarbeau/. I work @CUTRUSF. Posts are my own.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store