Or: How to fix bugs and change behavior without submitting a new version of your app to the marketplace.
If you ever wrote a Windows Phone app that’s even slightly complex, you must know that feeling of dread of finding a bug that affects a large percent of the users. Solving the problem and getting the app to users can take as long as 5-8 days from the time you submit the change to the marketplace and the time users will actually see it (and that’s if the certification process does not reject the app). That time can be critical. Users get annoyed and give you bad reviews or just stop using your app.
This series of blog posts is a summary of some of the ways in which our thinking has evolved with regards to making applications more dynamic and resilient to change – note that this is no magic bullet – it takes time to identify the potential places that need to be made resilient and it takes time to write the code to be resilient – however, once done, there’s a certain feeling of freedom.
1stpost: Framing (this post): I will try to explain what it is we are talking about, giving concrete examples for problems that can come up and various solutions I am sure many people use today.
2ndpost: Using (a highly modified version of) xpath on Windows Phone to achieve simple customization capabilities of your app.
4thpost: More examples for how to use both methods to make your application even more resilient and awesome.
5th post: Downloads, downloads, downloads – all the stuff you will need to be able to get what you read about to work.
What change-resiliency means to me
Any app released to the market place can have bugs – in fact, I have yet to see or release an app that does not have bugs in them – to make matters worse, a lot of apps rely on web services for their functionality and these services (when not in the developer’s control) may change and in turn cause issues with the applications.
When I talk about change-resiliency, I mean one of three things:
1. External dependencies: This is the most common occurrence that can cause issues to your app. Your app relies on an external service that has changed its behavior, output or even location and the app breaks. External dependencies can be an XML or JSON web service, it can be a web-page you navigate to and interact with on your app (like the Facebook sign in page or others).
2. Internal bugs:Some code you wrote does not behave as you expect under certain cases and you want to either fix it or at least be able to gather more information about it and maybe notify the user that there’s a problem.
3. Functionality changes: This category comprises of various odds and ends that can let the developer change the behavior of the app after it has been released – either because they need to learn something about the users, or because you decide that a certain feature is not good enough or needs to be changed.
Some concrete examples please
The idea is simple – your app connects to your server (or to some data source you control) and takes customization “instructions” from the server. I am sure a lot of people are doing this already, for example, allowing their server to customize their URIs or parsing instructions.
Here’s an example for an external dependency:
Let’s consider an app that gets weather from Yahoo!. (I am going to take some liberties with the actual input and output of the service to make a point – I like using this example because it’s easily accessible and does not require any API keys or anything like that). The service is a fairly simple RSS feed (you can read more about the API here)
The URI that gives you the result looks like this:
The “w” is a parameter that identifies the location for which you want the weather forecast. The result is an XML rss feed – as part of that feed, you get an element that gives you the current weather:
Your application uses Linq to XML to parse the XML and find the yweather:conditionelements, after which, depending on user settings, it retrieves either the one that has “C” in the unit attribute, or the one that has “F” to show Celsius or Fahrenheit, respectively.
As an external dependency, the following things can go wrong:
- Yahoo’s service has a bug, or decided to change their API structure in a way you did not anticipate:
- The XML output has changed.
- The URL for the API has changed.
- The parameters passed to the URL have changed.
- You were misusing the API unwittingly, passing in information that was malformed, but a recent Yahoo update essentially fixed the issue, causing you to break.
- Yahoo’s service goes down.
Unless you prepare for this, there’s essentially nothing you can do to adjust – your app will stop showing data – there’s really nothing you can do.
Developers are well aware of these types of issues, and I have seen them deal with it in three main ways:
- All access points to external dependencies are controlled by the developer: When the app starts, it “calls home” to a server owned by the developer and downloads a set of URIs to use to connect to external sources. In this case, our yahoo weather URI may look like this:
Before making the call, the developer uses String.Format() to create the specific URI and then makes an HTTP call to that URI.
- For parsing, developers usually use LINQ – which cannot be patched. The more advanced developers will use RegEx to parse the relevant stream that comes back and return results.
- Developers will sometimes completely avoid the issue by using their servers as “gateways” – all calls go to their servers which in turn call the external dependencies. This works well because, pretty much any break in the external dependency can be fixed by updating the developer’s server.
Each of these mechanisms has down sides associated with it:
- External entry points (URIs): Sometimes, a simple string format cannot solve the issue at hand. For example, in the aforementioned example of Yahoo!, assume that the way for getting future forecasts was to pass an extra piece of path to the URI – some kind of rudimentary paging mechanism:
As a developer, you are delighted to find that passing /page/1 is equivalent to making the following URI:
And so, your format string will look like this:
When you format the string, the page is passed as the first format argument and the zip code is passed as the second one.
However, at some point, Yahoo! Silently update their APIs and break this behavior (which, to be fair, they never purported to support). You are now unable to get the first page of the weather report because the URI no longer works.
- Using RegEx: There is no question RegEx is a wonderful tool – but it’s just not very easy to use when parsing XML or HTML. Expressions can become terribly complex for fairly simple documents. Furthermore, there’s no concrete expressions that can be executed in RegEx – at the end of the day, the results you get back are those that are already in the file. Consider the XML example above where both Farenhite and Celsius are present in the XML document. What happens if tomorrow one of them is omitted? How can RegEx handle that?
- Server-in-the-middle: This is the ideal solution, if you can handle it. However, there are a number of issues with it:
- A. Some services (such as Facebook) pass private and potentially sensitive information. Having your own server in the middle of it, acting as a middle-man may require you to store or handle some of that information. That increases the potential vulnerability of your overall system. When the phone connects directly to the service provider, there is less you need to worry about.
- Depending on your app usage, traffic and your infrastructure, your server could be beaten to a pulp by the traffic. The external dependency is going to be hit by traffic anyway – but now there’s another piece that needs to pay CPU, storage and network costs – and these costs are on you.
- Finally, typically, internet-scale servers are far more robust than a mobile app developer can achieve. It is more probable that your server will go down than Yahoo!’s servers and so you add a fairly critical, single point of failure.
Okay, so what’s next?
If you own a highly available server farm and the traffic produced by apps using external dependencies is dwarved by the amount of traffic you usually produce, think nothing of it – stop reading these posts and go back to your awesome servers, you magnificent bastard!
However.. If you are a part-time app developer, a hobbyist or somebody who just doesn’t have the infrastructure, read on – the next post will show you how to solve a lot of the issues presented and give you access to the tools for doing that.