We’ve been a tad quiet of late on the blog, but with a new release in the App Store this week (www.appstore.com/publicity) now is a perfect time to give an update on what’s been going on behind the scenes this summer. Along with the standard summer festivals, weddings, stag dos etc. our Solution Architect Dan has had a baby (congratulations Dan & Kelly). But just because we haven’t had a new app store release for a couple of months doesn’t mean we haven’t been working hard!
In addition to some UI tweaks, our latest version includes much improved social media posting so that check-in photos and reviews can be shared across social networks. You can read more about our take on the social media ecosystem in a blog post from earlier this year http://www.blog.publicitymobile.com/post/71744358017/a-take-on-the-social-media-ecosystem, and this has very much guided our product roadmap.
In addition to the new features in this latest version, we have been doing LOADS behind the scenes. Ever since we went live we have been trying to make Publicity faster, and we think we’ve nearly cracked it. The performance challenges we have had have been largely due to our database activity. The first hurdle to improve this was to upgrade the data access frameworks, putting our 22 database projects into a framework that is a lot more flexible. Now we have done this, we can really get cracking on improving performance. We think the answer to our performance will be a paging solution to fetch sets of data rather than all at once - think the way Twitter shows you just want you need on the first screen and as you scroll down older data is loaded. This is exactly the type of solution we are implementing for Publicity, so how have we gone about this?
** Warning. The following may get technical **
With a fairly typical client-server architecture, our client sends a request to the server with a ‘key’. The key could be a username, location ID, review etc. Our service is hosted on Google’s App Engine cloud platform, and as a (bootstrapped) start-up we need to keep our database reads to a minimum to keep the costs of running our service manageable and therefore use dedicated cache. This means that for values stored in the cache (e.g. if someone had searched for that venue recently), we can retrieve the value much quicker and eliminate the need for a database read.
With our previous design, the server would look to see if each key in a request is stored in the cache. This is fine for loading one record, but when loading more than one key, the logic would first search for the first key, and then the second, and cycle through until data for all keys in the request from the client had been completed. The result of this is a lot of decision points to load venue data; throw in reviews, photos, summary data etc. and this can take a while. We have to balance putting too much data in the cache because as well as it having size limits (see later notes), it also means that the data isn’t necessarily up to date (as the data isn’t read from the database, only the memory), and our proposition is built around real-time data.
With our more flexible data access frameworks we have been able to redesign the database logic to pass all keys in a single request, so if we are going to load over 50 venues, we don’t load each one individually, rather we ask for them all at once. This means we make just one call to the database, collate the results and return them to the client, and the result is improved performance.
So this sounds obvious right? Well the challenge has been finding the right values to put in the cache. GAE’s cache works by assigning a unique value to each item in the cache, so for a venue record for example, we have to store them each individually. To pass multiple venues in the same request, we needed code to extract the collated values and store/check them against the cache. This gets complicated when one venue is in the cache and one isn’t etc.
We first discovered the complexity of this when we tried to introduce new functionality to run campaigns. We initially built this feature for London Wine Week, and it allows us to display a pre-confgured home screen advert and link to a customised search view with venues participating in the campaign. We will be using the same feature for London Cocktail Week in October and are looking for new opportunities to use it for other events, venues and brands to deliver targeted campaigns in London.
We tested this fully in our test environment and it worked fine, but our test environment didn’t have the same number of venues as our production environment, and when we deployed this code into production we found that the data was too big for the cache and it brought our service down. I should note that we were able to roll back to the previous version of server code and get the service back up within two hours, and it’s been our only outage since we launched, however it did teach us a few valuable lessons; namely to have a pre-prod environment which simulates that of the production environment as closely as possible, and not to deploy new code on a Friday afternoon when your heaviest use is over the weekend :-).
So if you’re thinking this all sounds pretty complicated, well you’re right, but the benefit is that it has allowed us to implement a paging solution to improve performance by adding in partitioning into how we cache our data, with two caches linked with different keys. This means that we can load historic data in batches, so rather than saying "give me all the data on The Rose & Crown", we can apply partitioning logic in the cache and say ‘give me all the data from Wednesday’, then, ‘give me all the data from Tuesday’ and so on. Hopefully this will hugely improve the performance of the app, allowing the user to get into the app quickly and access the most relevant data (nearest and most recent), and load the rest in the background
We’re testing this at the moment and will hopefully have it live by the end of August and we expect to see a massive improvement in performance, so keep an eye out for an update.