The deployment cycle of a mobile SDK is different than that of a mobile application – no matter how often and quick your release cycles are, you’re still dependent on the release cycles of the hosting app. This fact makes it harder to test and tweak your code based on production experience.

Configurable parameters to the rescue! Making your code configurable by adding parameter control from the server is not limited solely to the development stage of the SDK lifetime, it can be extremely beneficial in production as well. All part of the deal when you don’t control when new versions and code will be rolled out to users. So, while using configurations is a good practice for mobile apps and SDKS alike, for SDKs it can literally become a ‘make it or break it’ issue.

The basic need is for your code to behave differently based on server-side configuration. The configuration can include different behaviors for different customers, A\B testing, general parameters used throughout the code etc.

The implementation details can vary between different platforms, languages and use cases, but there are a few common issues to consider.

1. Developer Awareness and Ease of Use

It’s much easier to hardcode your values inside a function, so make sure using a configurable value isn’t much harder. Build a simple framework that allows adding new values easily.

For example, instead of adding a function for each configurable value, you can use a JSON dot-notation to access parameters in the configuration (This can also help in splitting your configuration into logical parts).

So instead of:

String server_url = GetAnalyticsServerURL();

You can have a “Configuration” class and simply query it for the property you need:

String server_url = configuration.getString(
  "server_details.analytics.url", "https://www.myserver.com/analytics");

While the configuration can look like this:

{
  "server_details": {
    "analytics": {
      "url": "https://www.myserver.com/analytics-testing"
    }
  }
}

The biggest challenge here is definitely making this part of your development culture. Developers who aren’t necessarily used to making every little primitive configurable, would have to be “reprogrammed” to think about their code in configurable terms. It may be frustrating and there may be some labor pains, but the frustration would be much greater when you need this control and don’t have it. Trust me, the end result would far outweigh the internal turmoil of the beginning.

2. Clear and Easy Default

So, you’ve got the configuration working for you in your code. But what do you do when there’s no configuration value available for what you’re looking for?

Always make sure you have defaults for such cases. It’s a pretty common convention to use two-parameters getters, where the second parameter is the fallback / default value. This helps make your code much more readable:

int iterations = 
  configuration.getInt(“max_iterations”,100);

Ideally, you would also keep your default in constant values, thus increasing readability even further:

int iterations = configuration.getInt(
  "max_iterations",
  DEFAULT_MAX_ITERATIONS);

You can also have an initial configuration deployed with the app, but keep in mind you might need to ask your customers to incorporate this in the app (add it as a resource bundle or assets, write this to your binary in a post build step, etc.)

3. Backwards compatibility

Backwards compatibility is a pain – no one likes it, but (almost) everybody must support it.

When writing configurable code, don’t disregard older clients – these are usually tested more briefly and can sometimes misinterpret new configuration syntax and so unexpected behavior is bound to occur.

It’s pretty easy to avoid such issues with a good framework: every new key in the configuration will probably be ignored by older clients so use this to your advantage: add new values when needed or better yet – put your configurations under version namespaces:

{
  "v1": {
    "server_protocol": "LONG_POLL"
  }
},
"v2": {
  "server_protocol": "WEB_SOCKET"
  }
}

And of course, be very very careful with old or existing keys. Changing their meaning or expected values can lead to the mother of all crashes.

5 Tips on Configuration for Mobile SDK Developers

4. Decoupling and Dependency Injection

Instead of polluting your code with if-else conditions based on configurations, you can use different classes altogether, and simply load the needed class dynamically. This can be done with a simple dependency injection framework that will create your class hierarchy based on your configuration. By doing this, you can get cleaner and readable code, while hiding the nits and grits of your dependency hierarchy.

Public class AnalyticReporter {

  private List producers;

  public AnalyticReporter() {
    producers = createProducers();
  }

  public List createProducers() {
    List producers = 
      new ArrayList();
    JSONArray array = configuration.getJSONArray(
      "v1.analytics.producers");
    for(int i = 0 ; i < array.length() ; i++) {
      producers.add(
         ProducerFactory.create(
           array.getJSONObject(i)));
    }
  }
}

and the configuration can be written as follows:

{
  "v1": {
    "analytics": {
      "producers": [
        "network_scraper": {
          "class_name": "NetworkScraper",
          "options": {
            "technologies": [
               "HTTPS",
               "FTP"
            ]
          }
        },
        "network_scraper_v2": {
          "class_name": "NetworkScraperEx",
          "options": {
            "technologies": [
              "HTTPS",
              "FTP"
            ],
            "interval_sec": 60
          }
        },
        ...
      },
      "clicks_scraper": {
        ...
      }
    ]
  }
}, 
"v2": {
  "server_protocol": "WEB_SOCKET"
  }
}

5. Testing

Having configurable code, can greatly help with testing your SDK. If you can allow your QA engineers to modify the configuration for each test (configurable configuration J), they will be able to reproduce edge cases more easily and thus expand the range of tests your SDK undergoes.

You can point the configuration requests to a test server that answers with different configurations based on the current test.

Another option is adding the ability to read a configuration patch file during the initialization of the code. The configuration patch file can then be merged with the live configuration to create a modified test configuration. Just make sure this patch persists between configuration updates and\or application restarts.

An important note regarding this point: opening the configuration to patches, may introduce code vulnerabilities, so it’s better to allow this in QA flavors only and disable this functionality in your released product.

Configuration, Configuration, Configuration

Sooner or later every SDK learns its biggest pain is the complete lack of control over when updates roll out to users. It’s completely in the hands of apps integrating them.

The above are just a handful of points to consider during an SDK’s development cycle. There are other considerations that must be taken into account such as code readability, performance impacts, vulnerabilities and how does a configuration change may affect the hosting app. Naturally, when you start planning your configuration framework, all of these issues should be addressed.

Introducing such a framework at the early stages of your development can make your SDK more robust and flexible, despite the inherent dependency on the hosting application’s development and release cycles.