What building an Android weather app taught me about designing for reliability

After dedicating 13 years to developing Android applications, the backend intricacies often felt like someone else’s concern. However, the creation of Weather Pal, my own weather forecasting app, swiftly transformed that perspective. This journey illuminated a crucial lesson: the reliability of mobile applications hinges not solely on server responses but rather on the journey of data from fetch to display, as well as the shared resources that come into play.

Two significant incidents crystallized this understanding. The first occurred when the operating system unexpectedly ceased refreshing my data. The second incident involved unauthorized scripts that depleted my quota, which would have otherwise facilitated the necessary updates. Remarkably, neither scenario triggered an error notification, highlighting the subtle complexities of mobile app management.

Weather Pal is crafted using Kotlin and Jetpack Compose, offering users hourly and daily forecasts, air quality index (AQI) data, radar imagery, weather alerts, and a layer of straightforward insights generated on-device with TensorFlow Lite. The forecasts are sourced from Open-Meteo and MET Norway, while official alerts from the National Weather Service API are seamlessly integrated. To enhance privacy and control, every request is routed through a gateway that I operate, rather than being called directly from the user’s device. Coordinates are rounded to city-block precision before transmission, ensuring that no account information or search history is stored on a server. This deliberate approach is reflected in my privacy policy, emphasizing the importance of transparency regarding location data.

The outage that existed only on the home screen

The widget feature, which I considered my crowning achievement, was the first to let me down. It was designed to refresh through a periodic WorkManager job, adhering to the best practices for background operations in modern Android development. However, a beta tester’s screenshot revealed a troubling discrepancy: his widget displayed a temperature of 31°C and clear skies, while his real-time view out the window captured a torrential downpour. The AQI reading was also significantly lower than the live data.

Despite the absence of any failures—Crashlytics reported no issues, and the gateway consistently returned 200 responses—the reality was that the user’s device had relegated my app to a restrictive App Standby bucket. Consequently, Doze mode had postponed my scheduled worker for approximately fourteen hours. The widget, in its unwavering fidelity, was merely reflecting the last data it had retrieved, oblivious to the fact that it was outdated by nearly half a day.

AppWizard