Weather Alert app development: a skills benchmark and walkthrough
Weather Alert, now marketed as Wind Times in the app store, is a wind spot locator displaying current, three hour and five day wind speed forecasts using a radar chart. It plots the cardinal directions and speed strength categorised by colours similar to the Beaufort scale. It was developed in four days as part of an iOS contract application for a broadcasting
telecommunications company. It benchmarks my efficiency and skill set (or lack of) in building iOS application with the help of Cocoa pods. I was given a requirements specification asking to write an app that displays wind information and forecasts taken from the Open Weather Map (OWM) service. The document also asks to render wind information in its cardinal direction as described in the wiki page http://en.wikipedia.org/wiki/Cardinal_direction. In simple terms show the wind direction like a radar or compass pointing to north, south etc. and show wind forecast data coming from any city in the world.
So for the next couple of days I set into gear to developing this app. The excercise was like a hackathon with all the stakes and deadline. I had to analyse the requirements, design the most sensible user interface, plan an architecture, choose the relevant technologies, build and code, beautify, test, the whole shebang in less than a week. I spent a day collecting all the requirements, thinking about what cocoa pods I can use to achieve them and planning what tasks takes higher priority. Of course I used the latest Xcode 7.2 with Swift 2.1 as my choice of programming language. A little side note, I love Swift. It is leaps and bounds from Objective-C in terms of readability and maintainability to say the least.
As I was reading the OWM API, the first thing I noted was the difference between the wind speed information returned from the JSON format and the XML data. One of them is the existence of speed description such as ‘Light Breeze’, ‘Moderate Breeze’ and ’Calm’ in the
XML data whilst they are missing in the JSON data. Why OWM allowing this difference I don't know, but to me this single field I thought is very important, since I would like the users to show a human readable text in English. I definitely don’t want to transform the speed value to English as the XML description perfectly describe the wind speed in its own right. On the flip side I thought of the option for localisation of this particular English text. I may actually want to translate it myself into a localised language. But alas! this is made possible by adding a language parameter to the URL points in the OWM API.
The other critical information that made my decision to choose XML was the presence of direction code and name. Both formats have the degree value but JSON does not have the code and name. I have a choice between displaying the direction using degree angle or using the direction code which is sixteen discreet values of North, North North East, North East etc. There is no specific requirement to render the direction accurately to the degree
angle. If I could plot the direction of the wind in a radar chart, I may be able to easily do this using a cocoa pod. Luckily the wheel has been invented already and the wheel was invented perfectly in the form of a cocoa pod originally made for Android: Charts by D. Gindi. So it is decided to choose XML data as my return format and use Charts to display the wind speed strength and direction. Charts is a very good choice of cocoa pod as I thought this would save more time doing mathematics. A re-usable Cocoa pod like this will definitely help in developing for different iOS size classes and even mundane things such as layouts.
One of the requirements is to be able to save the current and forecast data locally in a data store as a favourite. So the next important architectural decision to make is what local datastore I can use. There are currently several I can use that springs into mind : user defaults, property lists, CoreData, Parse and Realm. User defaults is too simplistic when looking at the XML return data. Although it's possible to serialise the objects it's just too messy to write the boiler plate code. Speaking of boiler plate code, CoreData has its own fair share of boiler plate code. A good alternative to CoreData is MagicalRecord which is basically it’s extension in a more manageable and concise classes. Property lists like user defaults are normally used as device settings not for big or medium size database that may be possibly storing around hundreds or thousands of records. Parse unfortunately is not an option as it has been recently announced on the beginning of the year 2016 that it will reach
its end of life. In my experience parse local data store is very poor performance wise. Speaking of which performance is a very important decision choosing the local data store because I envisioned a table list of favourites and recently inspected cities and spots as the main screen of the app having a search bar on top of the list and automatically filtering the result set as the user type. Similar to Mail and Whatsapp search bars. Realm is the perfect local data store for a performance based application wanting to achieve the above requirements.
At this point I know Realm is a good performance choice but I have a big risk implementing it as I have never used it, which later on proves to be extremely easy to use. Also my flow of thinking is aware of other requirements such as the key entry points to the OWM API. What are they and do they fit together with my choice local data store? Or is it a square peg in a round hole? So I carry on reading the OpenWeatherMap.org website in detail.
So there are a number of URL points into OWM. Including four variations of getting the current weather data. Via city name, ID, zip code and geographic coordinates. OWM recommends searching by ID in order to be precise and prevent ambiguity in the results. This piece of information proves to be vital in making the app flow and user interaction cleaner. Later I find out that searching by name and postcode via the OWM API does not return a set. It returns a single city, and if the criteria is ambiguous, you will receive only one possibly incorrect city! This is no good at all.
It's a little bit confusing at this point. I need the city ID for me to get the current data. In the perspective of the user, the user enters the name of the city by text. Where do I get the city ID from? It's like a chicken and egg problem. Which one comes first, the city ID or the city name? Reading a little further there is a section showing a bulk sample data download of cities and abbreviated data including city name, coordinates, country and ID! The only thing is there is more than two hundred thousand entries. No problem!
With this information, I can import the city bulk data on app install once, and I would have a highly optimised search bar that searches locally on the device. Realm promises to be the fastest local datastore existing on mobile platforms to date. And they do not disappoint!. Implementing this in Realm is quite simple. I thought I had to break down the bulk data into several files but this is is not necessary it's a simple file read and a JSON serialisation parsing using NSJSONSerialization object. The only small issue is the import data takes at least twenty seconds so I have to run this over a background thread whilst showing an activity indicator to prevent the user from any activity whilst the initial load is happening. A HUD is necessary so I use MBProgressHUD by M Bukovinski. Performance test on search by city name against 200k+ records produces blazingly fast results. Realm is very easy to implement. Basic add, update and delete operations are enclosed in a a write transactions. Whilst reading objects and filtering are implemented recursively with predicates and returned as Realm Results with all the handy swift functional programming features such as map, transform etc.
Now that I have the city ID in memory where the users search by city name locally from the device, I have an unambiguous search to the current weather data and forecast via ID. The choice of network connection to the service is next to be considered. The following pops into
mind: native NSURLSession, OpenWeatherMap Cocoa pod, and Alamofire. There is nothing wrong with NSURLSession apart from boiler plate code again this seem to be a common theme in native frameworks. But alas Alamofire looks promising since it has some nice modern swift syntax and is actually based on NSURLSession under the hood. One of the
simple and elegant implementations of Alamofire in Swift is the API parameter abstraction using an enumeration. In layman’s term, this basically transforms the consumption of cumbersome URL strings into Swift functions. So instead of doing http://site.com/?q=foo%20bar&offset=50 which is a messy string, you do
Alamofire.request(Router.Search(query: "foo bar", page: 1)) which is checked at compile time not at runtime. At this point all I need is an XML parser and a serialiser. But before I go in to XML, OpenWeatherMap Cocoa pod maybe a contender since it manages the network connections under the hood, except that looking deeper into the returned data, it only returns JSON which is what we don't want. Looks like Alamofire plus XML parsing will support my cause. XML serialising and parsing is made simple using Fuzi and Ono.
Other cocoa pods I used are cosmetic ones but are still vital in beautifying the app. They are SlideMenuController, UIColor+FlatColors, VTAcknowledgementsViewController which collects and display the license agreements used from the list of cocoa pods used.
I had a lot of fun doing this exercise and there were a lot of obstacles when I began development. So I wrote this walkthrough, discussing logical decisions and challenges. If you read this far, congratulations as it may be quite boring to some people. But in my opinion it's not boring at all. If you are reading this because you're applying for an application, good luck, I hope I may have helped! The main reason for sharing this experience is that it highlights my strong points of delivering an excellent app (IMHO) under pressure and on time. It benchmarks the depth of my skills and speed of learning new and exciting technologies on demand, as when required.
I submitted Wind Times a couple of days ago for review to the iTunes App Store. Hopefully it should be approved without any hiccups.
Happy wind times!