Craig Marvelley

Software and such

The Story of the Swn Festival iOS App

[This is a rambling post about iOS app development, Appcelerator Titanium, dealing with short deadlines, evolving feature sets, submitting to the App Store, APIs with Symfony2, and more. I should have written a series of posts but I know I’d never have finished them, so this is a stream of consciousness affair that is hopefully understandable and of interest to someone)].

For the last four years I’ve made an iPhone app for Cardiff’s brilliant Swn Festival. Each year I’ve intended to write about the experience; this year I finally managed it.

That I have done so now is due to this year being the first to take advantage of groundwork gradually laid down since 2010, when I first approached John Rostron with a horrendous prototype that I’d made with Appcelerator Titanium while holidaying in Morocco (I’m not sure what made the prototype quite so poor; the tools I was using, or the local beer I was drinking). John, one of the co-founders of the festival, thankfully saw past that early effort and gave his blessing for an official app, and there the hard work began.

image

In many ways this year’s release is closer to a 1.0 than it is a 4.0, in terms of it having features I would have liked in from the get-go. In others, it’s a step back; it actually has less functionality now than it did at the start. Here’s the story of the app, right from the beginning.

Version 1.0 - All kitchen, no sync

Ideas for the app started to take shape a year prior, when I attended the festival in 2009. The event encompasses hundreds of bands playing in venues all over the city, typically over four days, and I was frustrated by constantly having to check the website to see who was playing where; the physical programme being difficult to read in the low-lit venues. I decided to build a simple app to display the schedule, and allow me to put together a personal plan of the bands I wanted to see, in time for the following year’s event. I was keen on doing more iOS development and it seemed a good excuse as any. I accosted Huw Stephens, who co-hosts the festival with John, during the closing night; he may not have been able to hear (or possibly understand) a single word I said but after I explained my plan he didn’t say no, which was good enough for me.

The idea gestated over the next 9 months, until I began the prototype in late July 2010. I used Titanium, a cross platform mobile framework which lets you create apps using JavaScript, because I’d done a few projects with it around the same time and I was fairly productive with it. I was yet to feel wholly comfortable with Objective-C, Apple’s then advocated language for native iOS apps. I decided to implement the following features:

  • An easily browsable schedule
  • A personalised shortlist of acts to see
  • An index of artists, with biographies, social media links etc. to aid discoverability
  • An index of venues

That made up the prototype that I showed John that year, albeit with data from the previous year. Also in the meeting was Marc Thomas who produces the Swn website along with lots of other things, and has therefore been closely involved with the app too. John asked if we could incorporate festival news and sponsor details into the app as well, which wasn’t a problem.

Soon thereafter I decided to abandon Titanium and throw my lot in with Objective-C, reasons being:

  • The Titanium IDE, based on Eclipse, was dreadful. XCode, Apple’s IDE, isn’t perfect but it was a sure improvement
  • I came across significant bugs with the platform, and when I submitted pull requests they sometimes went ignored for months
  • I needed to learn a lot about iOS very quickly, and didn’t want to have to filter the knowledge I was getting from Apple documentation and other sources into a “Titanium transformer” so I could apply it on that platform

I don’t regret investing time in Titanium because it distills the common concepts of mobile development to the bare minimum. I found it very accessible, where native development can initially be daunting. Had I stuck with it there would probably be an Android version of the Swn app by now; these days I haven’t the time to learn Android development, and was put off back then by its relative immaturity to iOS. Ultimately, once I was oriented I quickly outgrew the platform, and considering how much more complicated iOS has become since (see storyboards, auto layout, etc.) I wouldn’t want to stray too far from Apple’s toolchain - they struggle to keep up with it themselves.

It didn’t take very long to get the features I had in the prototype properly implemented in the native app, and the basic structure of the app hasn’t changed to this day. A tab bar controller hosted a navigation group for each distinct area of the app (schedule, artists, venues, and then also news and sponsors), and each of the sections made extensive use of tableviews to present data. I decided not to host the app’s data on a web service, and instead painstakingly added it manually to a set of plist files stored in the app bundle - this I would soon regret.

Another factor in deciding to go native was that a lot of the artists playing at the festival had SoundCloud accounts, and back then SoundCloud had a very permissive Objective-C client that made it ridiculously easy to stream songs via the app. As long as I attributed SoundCloud by displaying their logo I was free to play as much music as I wanted, so I added a player with some really basic playlist functionality as well. It was by far the most technically difficult part of the app (although all the clever bits around streaming were the SoundCloud library’s doing) but I don’t think many people even knew it was there. Indeed, my first submission to the App Store was rejected because the review team didn’t notice it and flagged the app as “unnecessarily requesting permission to play background audio” - which is a pretty damning indictment of my UX skills.

(Another late feature I added was the ability for users to share their personal planner on Facebook - I wrote a custom Facebook app, added authentication to the Swn app, integrated with their iOS SDK… and around six people ended up using it).

It was a rush to get the app ready in time. Because I was bundling the data in with the app, I had to wait until the schedule was finalised before I could ship; and before I could ship I had to pass Apple’s app review process, which usually takes anywhere from a week to a fortnight. When I got the schedule with around a week to go before the festival started, I knew I was in trouble.

I submitted the app on the 14th October, three days before opening day, and knew that it wasn’t going to make it in time. Desperate not to see our work go to waste, I frantically Googled for options - I briefly explored ways to distribute the app manually, which would have been insane - before reading about Apple’s expedited review provision; this is a mechanism where app developers can request a shorter review time if they feel their submission meets certain criteria (like a critical bug fix, or - hallelujah - apps that are time dependent). I made the request and was extremely grateful when Apple granted it.

The app went live a day before the festival began.

Overall it was well received. There were the inevitable complaints that there wasn’t a companion Android version, and each year since I’ve intended to address that, only for a lack of time to prevent me doing do. Aside from that there was a single major problem.

A day into the festival I got an email from John asking if I could make a few amendments to the schedule; a few bands had dropped out, there had been a couple of set time alterations, etc. I hadn’t considered this scenario at all, and here’s where my decision to bundle the data with the app came back to bite me - any amendment to the schedule would require a new release and another trip through the review process. In my experience minor updates to existing apps do get approved quicker than brand new submissions (perhaps subsequent reviews are less stringent? Or are tasked to the same reviewer as before, so they’re familiar with the app?), but given the festival was only four days long, it was unlikely to be available in time to be of any use - and indeed the event was over halfway through before the update hit the App Store.

In retrospect it would have been wiser to have spent time on externalising the data rather than adding flashy but little used features. Thankfully user feedback and download statistics suggested that the app was popular, so I suppose it was a success nonetheless.

Version 2.0 - Enter Wordpress

When the time came to start thinking about an update for 2012’s event an API was at the top of the list of new features. With an API delivering the schedule, artist and venue data the app could be updated at any time, without an app resubmission.

Since all of the artist data was already in the Wordpress installation that powered the Swn website it seemed logical to export it from there. Marc suggested we use the JetPack plugin for Wordpress to expose the artist data via its JSON API, and use the custom field functionality to provide additional data like set times or venue locations that were outside the requirements of the website. Inputting the data was a long-winded process, especially when adding dates since the custom field UI had no date picker - typing around 400 dates in ISO 8601 format into a text field is no fun. Thanks to Morgan’s hard work we eventually had an API delivering the data we needed - now I had to get it into the app.

The RestKit library for iOS hadn’t been around long but looked like it would do exactly what I needed - make HTTP requests to given endpoints, transform the responses into objects using custom mappings, and then store the resulting object graph into Core Data, Apple’s persistence framework. It also made it easy to load a seed database on the first run of the app, so I could bundle as accurate a dataset as I could get without leaving it too late to pass app review. That way the app would be fairly accurate from launch, and any amendments could be performed via the API as necessary. I had to jump through some hoops when transforming the object graph as our use of custom fields meant there weren’t concrete objects with primary keys to map to my event and venue Core Data entities, but it didn’t take long to work around that. I faked an identifier from hashed content to identify individual artist appearances, so I could persist favourited events beyond each schedule reload.

I found RestKit to be straightforward to implement, although its documentation was light, disorganised and outdated. Thankfully since getting it working I’ve not needed to touch it in two years save to update the odd URL, which has been a relief. I’ve often thought to replace it but if ain’t broke…

I simplified the app by removing its Facebook integration; I doubt it was missed. The SoundCloud player survived, but I had to redesign it, and other parts of the app, to accommodate the iPhone 5 which was released in the September and introduced a new 4” screen size into the iPhone lineup. Since the app made use of lots of UITableViewControllers I was quite lucky in this regard - the tableviews naturally stretched a little more to take up the additional space.

Despite our improved data approach we still contrived to cut it close with the app submission. Thankfully it was approved in time, and I saw plenty of people using it during the festival. Since I’m predominately a web developer I don’t often get to see people use the things I make, so it was nice to observe the odd person browsing the schedule or reading about an artist.

Version 3.0 - Bittersweet Symfony

2013 continued the pattern of very little innovation from the app’s perspective, with most of the work going into supporting the latest version of iOS (the 7th iteration came out that year and embraced flat design, so I gave the app a facelift to match) and improving data delivery.

Wordpress had proved a decent stop-gap API, but it needed to be replaced; it was too easy to enter incorrect data with no validation on custom fields, and the response times from the API were poor, and for a relatively small dataset too. Since people would usually be downloading over a data connection (3G at best) with spotty connectivity due to being in and out of venues I wanted updates to the schedule to be much quicker than they currently were.

I was working a lot with Symfony2 at the time, and it’s still my go-to PHP framework. Its out-of-the-box integration with the Doctrine ORM means it’s really easy to produce a decent webservice, so I decided to write my own API and import whatever I could from Wordpress to minimise he amount of data entry I had to do. Ideally the import would be semi-idempotent as well, so if any artist data (like biographies) changed I’d be able to rerun the import to get the latest data but maintain existing identifiers, so as not to break user’s favourite lists.

I used the Sonata Admin Bundle for Symfony2 to provide a front end to the API, so the Swn team could update the schedule themselves and no longer rely on me. We also managed to get a new feature into the app - venue capacity indicators, so festival goers would know ahead of time if they were likely to be queuing to get in to see a particular artist.

Because the changes weren’t drastic I didn’t expect many side effects in the app, but man was I wrong. There were some nasty schedule issues to resolve (mostly around dates and time zones, which may have been in the app from the start but were surely highlighted by my API changes). As a result I once again ended up rushing to finish in time, and most maddeningly had to spend a day at the PHPNW13 conference ensconced in my room, coding frantically and missing talks. Steve Halford - friend, colleague and beta tester extraordinaire - was probably sick of the sight of emails from TestFlight announcing another build for him to try. Another expedited review was requested, and granted. I’ve read that developers are limited to a certain amount of these, so really it’s a good thing I make apps sporadically.

Version 4.0 - Auto layout aside…

And so to 2014. I’ve been really busy since changing jobs last March, and feared I wouldn’t have time to produce the app this year. I was all set to take a back seat (which would have saddened me because I love making it and being involved) when I found out that this year’s festival was to be a smaller affair, and so if I were to do the app less work would be required. That was too tempting an offer to pass up, especially as I felt we’d spent four years getting to this point - where the API and the app were in harmony, and any time spent would be on maintaining the app and hopefully expanding it with the odd new feature.

image

Of course, nothing’s ever that simple. Apple announced not one but two new devices this year, the iPhones 6 and 6 Plus, each with a screen size which meant the app needed to support four form factors in total (the 4s, 5/5s/5c, 6 and 6+). Up until now I’d been quite lucky, with each new release of iOS not needing much in the way of view changes, but after watching several of this year’s WWDC videos I realised I couldn’t keep putting off using storyboards and auto layout - it was only going to get more difficult the longer I left it.

So I ended up scrapping the existing XIBs which defined the user interface and moved everything to a single storyboard (the app’s small so I could get away with that). Though I’d not used auto layout extensively I managed to convert everything without much bother - aside from one UI element which consisted of a set of tableviews in a paginated scrollview, one for each venue on a given day. Try as I might I couldn’t get it paging properly through Interface Builder (I suspect I need to manage it in code, as the tables are dynamic) so I ended up replacing the scrollview with a single tableview, which luckily I could do since the festival takes place on a single day this year - there’s less data to display.

Here’s the cool thing though - I estimate I spent no more than 2 days’ worth of time preparing the app for 2014, which is a significant improvement on previous years. I didn’t miss half of a conference this time either! The infrastructure that’s now in place should provide a consistent base from which I can experiment with new features. Here’s hoping Apple now slow down a bit so I can spend less time firefighting in future.

Final Thoughts

In a nutshell, here’s what I’ve learned from developing this app over the last four years:

  • Abstraction frameworks are useful for quick prototyping
  • Don’t waste time on features if they aren’t likely to be used (however cool you think they may be!)
  • If your app depends on a dataset but has a deadline, submit as early as possible and update it on first launch
  • Each year, run your app with the new iOS beta releases as soon as they’re available to identify what needs fixing, even if you don’t plan on updating it in the near future - avoid late surprises.
  • The WWDC videos are essential viewing
  • Where you can, own your own web services. Don’t rely on someone else’s platform and its performance, availability, etc.

Phew. That’s it. You have my thanks if you made it this far!

UISplitViewController Collapsing and Separating in iOS 8

The new UISplitViewController class and delegate methods in iOS 8 is interesting, and caused me a lot of head scratching last week. The problem Brent Simmons describes here, where after rotating the device from regular to compact size class and back again iOS uses the topmost master view controller as the new detail view, instead of the previous detail view, is roughly the same issue I had.

As far as I can tell so far, I think the following approach solves the issue. Note that I don’t think I have the same set up as Brent - I have a navigation stack in each of the master and detail sides - but I think the general approach is sound, based on advice from Apple in the the “Building Adaptive Apps with UIKit” session from this year’s WWDC, and the “AdaptivePhotos” sample app code they provide.

My UISplitViewController delegate looks like this:

  • In the ‘collapse’ method, which is called when the device rotates to portrait, we disregard the detail view controller and use the master view controller if the detail view has no content
  • In the ‘merge’ method, we look to see if there’s a navigation controller which is displaying a NoteViewController (this controller is currently only used as a detail view, exclusively, so it’s a safe bet). If it exists, we use it - otherwise we retrieve the ‘stock’ note view controller stack from the storyboard and use that.

This approach seems to have worked well so far. The majority of issues I’ve found have been on the iPhone 6 Plus, which combines the single hierarchy approach of the smaller form factor devices in regular mode, with the side-by-side dual view approach or the larger form factors in compact mode - this hybrid strategy seems to require more direction on our part, whereas elsewhere iOS tends to guess right on its own.

A final note - having to manually ensure the back button exists and is configured on the detail view controller is a bit icky, but I needed to do this to avoid a crash. I’d love to hear from anyone with more elegant ways to handle this.

NOOB 0.9.19 - ‘You Shouldn’t Have to Click It’

Gav and myself mainly talk about software company processes and principles, with a little bit on communication tools and AWS thrown in for good measure.

This is the first podcast we’ve recorded remotely, since Gav moved to Bristol. Following this Macworld post’s directions seemed to work; we each recorded our own audio via Quicktime, and synced it up with our “master” recording from Skype, made possible via Call Recorder. I sequenced it all in GarageBand, with the odd final edit in Audacity.

We’re five episodes in since we rebooted the podcast back in June. There’s still a lot of room for improvement (especially, for me, in my speech - I find it hard to speak in a slow cadence, and concentrating on that often distracts me from the topic at hand), but I feel that each episode has gained in professionalism, and they’re a lot of fun to do.

Check it out on Soundcloud here, or even subscribe on iTunes thanks to Soundcloud’s currently-in-beta integration with that service, which we’re fortunate to have been given access to.

Waiting for SSH

Update 2014/09/06 - Michael DeHaan mentions on Twitter that he adds in a few seconds of sleep with the pause module to ensure the SSH port is open.

I’ve spent the day provisioning a whole lot of EC2 instances with Ansible from a control machine in the cloud. This involves two stages: firstly an instance is launched, and then once SSH is available (using Ansible’s wait_for module), the second stage of more detailed provisioning begins.

An issue I’d experienced a few times previously but had not been able to pinpoint, was that often the wait_for module failed to identify that SSH is ready. My Ansible task looked like this:

1
2
3
4
5
6
7
8
9
- name: Wait until SSH is available
  local_action: 
    module: wait_for 
    host: "{{ item.public_dns_name }}"
    port: 22 
    delay: 60 
    timeout: 320 
    state: started
  with_items: launched_instances.instances

That task would often time out, but in such cases if I were to immediately try to SSH from the terminal it would succeed, which was odd indeed.

Today this behaviour was consistent, and I eventually realised that in the task I was using the instance’s public DNS name, whereas when I was connecting via the terminal I used the public IP address. Indeed, changing the task to use the IP address seems to have made the whole thing a lot more reliable:

1
2
3
4
5
6
7
8
9
- name: Wait until SSH is available
  local_action: 
    module: wait_for 
    host: "{{ item.public_ip }}"
    port: 22 
    delay: 60 
    timeout: 320 
    state: started
  with_items: launched_instances.instances

I’m guessing that on my Mac (where this was rarely an issue) the DNS cache updates quicker than it does on the control machine in EC2, where this problem was more frequent - using the explicit IP address renders the issue moot.

Never Out of Beta Returns!

I love podcasts. Since I moved house and gained a commute I’ve whiled away the time to and from work listening to The Talk Show, The Record, The Guardian’s Football Weekly, and a couple of other great shows. Enough that I’m barely able to listen to them all. They made me pine for Never Out Of Beta though, a podcast Gav and Carey started a couple of years ago that I and a few friends would guest on, which was great fun.

But my longing is over - Gav and I have rebooted the show, and the first episode is available now via Soundcloud!

A couple of notes:

  • Production “issues” (well, I forgot a bunch of audio equipment) meant that we had to record this one via my Macbook’s built in microphone. It turned out ok, but we’ve got higher standards which hopefully we’ll get closer to next time
  • It took longer than I’d have liked to get the episode out because I’m learning the ropes when it comes to editing. The WWDC stuff is a bit old hat now, but get past that and I think there’s some interesting discussion around the DevOps mindset and provisioning with Ansible
  • An iTunes feed is coming as soon as I can sort one out - I listen to podcasts through the Apple Podcast app so I’m eager to make it available there
  • Inspired by The Talk Show’s recent switch we’re hosting the show on SoundCloud, which has been perfect so far

As with pretty much everything else Gav and I do, it might take a few iterations before this is something we’re really happy with, and feedback to aid us in getting there will be very much appreciated.

If you like tech, you might like this. Check it out!

Handling Interactive Ansible Tasks

I recently re-ran some Ansible provisioning scripts after upgrading the base box to an Ubuntu 14.04 image and found they stalled midway through. The cause? One task involved installing the PECL mongo module, and the installation process now prompts the user to decide whether or not to build with Cyrus SASL support. I couldn’t see a way to force a decision via the PECL installer, and Ansible can’t respond to the prompt, so the provisioning process hung while awaiting an answer.

I found two ways to solve this.

I’ve been expecting you

I did a bit of Googling and after coming across this post on the Ansible forum, I took a look at expect. Expect lets you script interactions with a spawned command, using regex to match against prompt text, and send appropriate responses. It’s a sound approach; I wrote a script that looked like this:

1
2
3
4
5
6
7
8
#!/usr/bin/expect

spawn pecl install mongo

expect "Build with Cyrus SASL"
send "\r"

expect eof

And executed it on the box using Ansible’s script module:

1
2
- name: Install PECL mongo extension
  script: install_pecl_mongo.expect

Mission achieved. I felt very pleased with myself for about 30 seconds, which is how long it took for Paul to wander over and tell me there was a simpler way to do it. Expect is a really good solution for scripting varied or complex responses, but I wasn’t faced with that problem here…

Yes man

In this specific case, all I wanted to do was answer a prompt which needed a yes or no answer, and I wasn’t concerned which I went with. There’s a linux command called yes which “outputs an affirmative response, or a user-defined string of text continuously until killed”, which is just what I needed.

So now my task looks like this:

1
2
- name: Install PECL mongo extension
  shell: yes '' | pecl install mongo

Which continuously pipes the ‘y’ character (by default) and a newline character into the install command, automatically causing any prompts to be responded to in the affirmative. For my simple use case it works perfectly, and is more straightforward than writing expect scripts.

Local Provisioning With Ansible

I recently mentioned I’m going all-in on provisioning and running all my development environments in VMs provisioned with Ansible. My Ansible use doesn’t end there though - I’m also using it to provision my MacBook.

I’d read of a few other people doing this - Benjamin Eberlei has a particularly good post on the topic, and was pretty much the inspiration for me doing the same. Setting up a new machine can be a bit of a bore, and while in theory it only happens whenever I upgrade hardware I have been caught out in the past with kernel corruption forcing a reinstall, and I’d like to minimise the hassle should it ever happen again. I have backups , but one of the few upsides of going back to scratch with a machine is that it’s an opportunity for spring clean; a script that effectively lists all the essential components of my computer, and configures them to my taste, makes that so much easier.

Anyway. A couple of people mentioned they’d be interested in the playbooks I wrote to provision my laptop, so I’ve taken out anything personal to me and mirrored them on Github.

Currently the provisioning involves four things:

  • Install Homebrew and various brews
  • Install Homebrew Casks and various casks
  • Enable zsh as default shell and install oh-my-zsh
  • Install dotfiles to configure git, vim, etc. (my dotfiles repo is here)

It’s all straightforward, but a couple of implementation details:

  • I’ve ended up using Alfred as my OS X search tool because I store my casks under /usr/local with the other brew stuff and symlink to /Applications, and Spotlight doesn’t grok symlinks. Instead I configure Alfred to link in the cask files
  • I read on a few places on the web that the method I use to determine my current shell process - echo $SHELL - isn’t foolproof. Works for me, but YMMV

There’s more I could do in terms of what I manage, especially when it comes to dotfile configuration (incidentally one of the best things about automating provisioning in this way is you end up looking at other people’s approaches, and finding out about libraries and tools that you never even knew existed - Thoughtbot’s rcm is one such example here). Also I’m still finding my way with Ansible, so my playbooks can undoubtedly be improved, especially when it comes to idempotency. Nevertheless I’m really happy to have a record of my machine’s starting state, and will enjoy adding to it as time passes.

Vagrant 1.5 Syncing Situation

image

When starting work at BipSync I resolved to put the bits and bobs I’d learned about provisioning with Vagrant and Ansible into practice, and no longer host development environments locally on my MacBook. The reasons were twofold - firstly I wanted my development environment to mirror that of live as closely as possible, and secondly when previously hosting multiple, complex projects on one machine I experienced increased battery drain and frequent slowdowns caused by active background services that I often didn’t even need for my current task. It was a pain to keep track of everything, especially when multiple versions were required. So the attraction of having dev environments I could bring up and down, and if necessary occasionally trash, was a strong one.

I’d played with Vagrant / VirtualBox hosted projects on smallish codebases before, where the default VirtualBox synced folder support was sufficient; however when attempting to host and develop BipSync’s sizeable applications it was quickly clear that this combination wouldn’t be fast enough to be fit for purpose.

Since VirtualBox has been acknowledged as the slowest of Vagrant’s provider options, and we already had Parallels licences for the development of our Windows applications, next I tried out the third party Parallels plugin for Vagrant. Basically this was a non-starter - I immediately ran into bugs that were present in the project’s issue tracker, and the impression I got was that the plugin is still a work-in-progress. The plugin is overseen by Parallels so I’m optimistic that it’ll one day be a first-class provider, but as it was it was unusable.

So I went back to VirtualBox (VMWare was another option but before forking out money on the software and accompanying plugin I wanted to exhaust all other options) and tried the other synced folder types. First I tried the new rsync support, which I’d read good things about. In terms of speed this was very quick because there isn’t really a share to speak of; shared items are copied to the guest rather than mounted. It requires a command to be run constantly, to watch synced files for changes and copy them to the guest, and this proved to be a problem; as issues raised by others attest, the approach wasn’t scaling to large (20k+ files) codebases, which is common in my experience. I tried excluding some folders to see if that would help, but it didn’t.

So after all that I ended up using the NFS sync option, which aside from requiring a password for sudo when booting the VM has proved trouble free, so far. Performance is good, both in terms of the applications themselves, and when browsing and modifying files in the share; I’ve seen PHPStorm occasionally lock up but then it always has ;) It’s certainly good enough to work with now, and I’ll be keeping an eye on the rsync and Parallels options as they should improve in time.

(“Moonlight Synchro” image courtesy of Chris Phutully. See license.)

Goodbye Box UK, Hello BipSync

For the last 7 years I consider myself lucky to have been employed by Box UK. When I joined in 2007 I’d spent the previous 3 years writing what I consider ‘despite software’. Software that did its job despite the efforts of the developer behind it. I was guilty of pretty much every bad practice at some stage; a direct result of me being the sole developer within both my company and my social circles. I didn’t know better and had no-one to tell me otherwise, but by 2007 I knew I needed to address that by working for a company in which there were lots of people smarter and more experienced than me. To “aim to be the dumbest person in the room”, as it’s often put - and never better than by my colleague and mentor at Box UK, Carey Hiles, speaking about being a lone coder in the first Unified Diff meetup put on several years later.

My first assignment at Box UK was making some tweaks to a web form on Promethean’s e-commerce site. My last assignment was rearchitecting the technology behind careerswales.com, a multi-application portal serving millions of users, which is destined to help shape lives of the people of Wales for years to come. In between I’ve created mobile applications, written web services, ported databases, implemented designs, discovered search platforms, pushed to queues, knocked out specifications, made many a calculation and finally - finally - got to grips with git. I’ve taught schoolchildren how to code. I’ve also shared more in-jokes than you could shake a stick at. Seriously.

As a software developer, I can’t think of a better place to learn one’s trade; every couple of months a new project comes along which will either improve existing skills, or demand new ones. Through the work that I’ve done there I’ve had the opportunity to travel the world, meet heroes, and speak at conferences. My colleagues have been everything I’d hoped they’d be - smart, friendly, and more than happy to help. Most importantly, they’re passionate. Box UK have aimed to only hire those who care about the work they do, and that’s clearly reflected in what we’ve achieved.

TL/DR: I’ve had an amazing job these last 7 years, and have loved every single minute of it.

After seven years I’m ready for a new challenge, and a wonderful opportunity at a startup called BipSync means it’s time to move on. I’ll be working with some former colleagues on some exciting software in a domain that’s fresh and interesting. I can’t wait to get stuck in, and hopefully share my experiences. I’d like to thank all at Box UK, especially Benno and those with whom I worked closely with over the years, for all the opportunities I was given and the experiences I’ve had. You’ve undoubtedly made me a better person, and I wish you all the best for the future.

Restore Missing Audio in iMovie for Mac

image

I recently got a new Macbook (running Mavericks) and wanted to transfer the iMovie projects from my older machine (running Mountain Lion). The new machine featured the most recent version of iMovie (iMovie for Mac, version 10.0.2) while my old one was on 9.0.9.

I loaded the projects into iMovie for Mac by copying over the iMovie Events, iMovie Original Movies and iMovie Projects folders via AirDrop. Upon starting iMovie for Mac it prompted me to upgrade my projects to the new format. After some time a dialog appeared notifying me that some events had not been found, and that the upgrade had not been successful.

It turned out that the movie events were fine, but the background audio I’d added (via iTunes) was missing because I’d not copied over my iTunes folder (and hadn’t planned to, since I now use iTunes in the Cloud). Attempting to open a ported project gave me a dialog along the lines of ‘Upgrade now, with missing events, or upgrade later’ - the choice was inconsequential since even by choosing ‘Upgrade later’ before putting the tracks in the places they were expected before opening the movie, the movie didn’t seem to pick up on the fact that they were now there. The waveforms remained blank, and the audio didn’t play. Of course, in most cases I didn’t even know which files were missing because most of these movies were put together months ago.

I eventually fixed it by painstakingly downloading and importing each audio track into the movie alongside the original clip, which triggered a reload of the original. Then the second clip could be removed, leaving the original which now played. It would be nice if iMovie for Mac had a ‘reload all events in this movie’ feature (perhaps it does, and I couldn’t find it - I’ve never found iMovie to have the most intuitive of interfaces)- thankfully I only had 20 or so tracks to fix, but for some more hardcore users it could be a lot worse.

(Waveform image copyright Bernard Goldbach)