TED 3.0: Working Effectively with Legacy iOS Code
I don’t talk often about the work I do to keep the lights on at my house, but I have spent a good portion of the last four years working on the TED for iOS app. The 3.0 release is the biggest release we’ve undertaken at TED in terms of scope and amount of changes to bring it to a head. The marquee feature is the app is now localized in 20 new languages. Users all over the world can now experience TED in their native languages from Arabic to Turkish.
Behind the scenes we have been planning to localize the app for over a year. What took so long?
A History Lesson
TED for iOS first arrived on the App Store in October of 2010, and was released exclusively for the original iPad. TED for iOS 1.0 was designed to run on iOS 3.2. For the last six years we have been building on on this foundation as devices and capabilities for Apple’s platforms change. In my time at TED (September 2012 to present) I’ve seen:
- Retina graphics, 3x graphics, and eventually vectors.
- AVFoundation making it easy for us to do our own custom video player (my first TED project!).
- The introduction of ARC as a replacement for manual retain/release.
- XCTest replacing OCTest.
- Larger and smaller devices such as the iPad mini, iPad Pro, iPhone 5, iPhone 6, and iPhone 6 Plus.
- Auto Layout and size classes for bringing some sanity to managing all these new device sizes.
- App extensions for things like widgets and custom share actions.
- Oh, and a little thing called Swift.
When TED shipped back in 2010 it was written entirely in Objective-C and designed to work on two device sizes: the iPhone 3GS and original iPad. Now we support phones as small as the iPhone 4s up to iPads like the 12.9" iPad Pro. In that entire time, we have continued to update the same app code base. There has never been a full-on rewrite of the iOS project, as tempting as it may be at times.
Renovating The House You Live In
Early last year, I took over as the lead developer of TED and began to dedicate more time to it than anyone had in previous years (TED has always been at most 2 part-time developers, and sometimes just 1). This allowed us to shift our mindset from maintaining the existing app to keep the wheels on while adding features occasionally to trying to be more ambitious with mobile goals. The only problem was that a lot of our code was showing its age. I made a list of high level goals to modernize the app going forward in small chunks so that we could still continue to ship updates to make TED HQ happy, while I eliminated many of the things that kept me up at night.
The first of those projects was to modularize the app. Since we are a small team, and have a fairly engaged group of users who upgrade quickly, we jump on the latest version of the iOS SDK faster than most companies. I set our minimum SDK to iOS 8 and began to break the app down into separate components. Instead of a single Xcode project with all our code in it, we broke it into separate dynamic frameworks:
- TED: the main iOS app
- TEDData: data layer and business logic related classes
- TEDVideo: our custom video player
- TEDCore: shared code that is used between all of the different frameworks
By modularizing the code, it made it easier to start adopting unit tests for pieces of the code that had never sniffed XCTest in its life. It also helped the workflow so I could only try compiling TEDData if I was working with the data model exclusively, rather than having to wait and compile the entire app.
Adopting Adaptivity
When I found out that localizing the app into 20 languages was high on the list of priorities for TED, I made it pretty clear that the current foundation that the app lived on would not be capable of supporting it in a way that would allow the development team to be successful. Nearly every piece of code in the application was duplicated for both the iPhone and iPad. Up until earlier this year when you would launch the TED app on your iPhone, we would fork off to a different set of interface elements depending on if you were on an iPhone or iPad. So, for example, our Featured tab had FeaturedViewController_iPhone and FeaturedViewController_iPad with completely separate interface elements. On top of it, none of this interface code had been updated for Auto Layout, size classes, or Storyboards. In fact, most of it hadn’t been touched in years other than the occasional bug fix.
This was by far the most painful part of the app and took several months (you can see the gap in our releases last fall.) to not only consolidate down to a single UIApplicationDelegate, but also to consolidate and clean up the TED interface as much as possible using size classes, Auto Layout, and Storyboards.
We shipped all of this work in late January as part of TED 2.6. You likely didn’t notice a thing had changed if you used the app, but that was by design. Our metric for success was the user not noticing anything had changed. Internally, however, the entire app had been built up on a new foundation that would enable us to move a lot faster and move closer to localization.
Adopting Swift
As of version 3.0, about 20% of the TED code base is written in Swift. That is up from 0% at this time last year.
The first bits of Swift code we wrote were part of the adaptivity cleanup when I rewrote the entire ‘Surprise Me’ tab in Swift as a test case to see how it would go. You’ve heard the success stories before, so it should come as no surprise that I was a big fan. Not only was the code more concise and easy to read, but there was a lot less of it.
I’m pragmatic when it comes to adopting Swift in TED. If we need receive new designs for an existing feature, we go through the process of rewriting the code in Swift. If we encounter some Objective-C code that isn’t a candidate for a rewrite, I do take the time to add nullability attributes to it so that it behaves better when we are calling it in Swift, which makes the entire mixed code base experience much more pleasant.
I lose zero sleep over the lack of dynamism in Swift.
Tests and CI
The last component of our maturation as a mobile development team is building out our test suite and getting it running automatically as part of continuous integration. All commits are now automatically running our test suite on our CI server to make sure that we don’t add any regressions. Most (not all) new code is also being written with automated tests attached to it. We still have a major gap when it comes to integration and UI testing, but we’ll get there eventually.
One example where we are having great success with our test suite is when it comes to working with localization. There are several edge cases we need to handle when it comes to mapping Chinese language codes between iOS and the TED API. We automate all of that using XCTest, which makes it super easy to understand the intent of the code without having to run the app and step through the debugger.
The Localization Process
This entire modernization process took place off-and-on from January of 2015 to April of 2016. The actual process of localizing the app took place in the last four weeks. Since we went through the work of getting the app running on Auto Layout in as many places as possible, exporting and importing our xliff files meant that we had a minimal amount of interface work to do when it came to testing the actual interface. The biggest hassles turned out to be adjusting a few buttons to support multi-lines for more verbose languages like German.
I was admittedly shocked that this worked as well as it did, but it’s a testament to the work we put in building up to this actual release. 16 months of preparation for 4 weeks of work!
tl;dr
- You don’t have to rewrite your legacy app from scratch.
- Don’t fall too far behind Apple’s current functionality or you will pay for it, eventually.
- Swift is great, but Objective-C is just fine too.
- Localization is way easier with Auto Layout and size classes.
- Unit testing and CI are worth it.
There’s still a ton of work to be done both internally and externally to bring the TED app to where I want it to be, but I’m pretty pleased with the work that we put in to get to this 3.0 release. I hope you’ll check it out
Originally published at carpeaqua.