When Apple first announced Swift, iOS developers across LinkedIn started learning it. This talk by Kamilah Taylor and Kyle Sherman describes LinkedIn’s experience with writing two drastically different apps in Swift. The SlideShare app has a much smaller user base, a smaller team of developers, and fewer features. The new LinkedIn app, Project Voyager, is a very large code base with more developers and a huge user base. This should give you an idea of what types of challenges and benefits both a startup and large company would have by switching from Objective-C to Swift.
Introduction (0:00)
We are Kyle and Kamilah, and each of us represent different apps within LinkedIn: Kyle works on the SlidesShare app, and Kamilah is on the Voyager team.
SlideShare’s app is a smaller one that some of you may have seen. Originally, it had four developers on it, and it took three months to build the first version. and then we went down to about two developers after that. The main flagship app, Voyager, had around 50 developers at its peak, and took one year from the start of coding to release.
Why Swift? (0:56)
For each of the apps that we work on, we had a choice between Objective-C and Swift. A nice thing about LinkedIn is that it’s not a very top-down organization, so they don’t dictate how we should write our code. In fact, we have had a lot of discussions on things like language choice and the platforms we’d write on.
For SlideShare, we chose to work in Swift for a number of reasons. First, the timing was right. We had just started development of the app, and the team member in charge at the time was brand new to iOS, so switching to Swift was a pretty simple decision for him. The advertised interoperability with Objective-C also seemed quite good, so we were thinking it would be nice to work with the libraries. Additionally, most of the team came from a Ruby background, so Objective-C was a lot more foreign looking than Swift. Finally, the safety features were a huge plus. Kyle wrote a blog post on LinkedIn’s engineering blog shortly after we’d released the app that delves deeper into the reasoning.
The flagship app, has had two iterations of working with Swift, the first being on the old version of the LinkedIn app. The Voyager team immediately started learning Swift when it was announced. We had team members who were doing luncheon tutorials, and the entire team was pretty enthusiastic about Swift. We started out by testing Swift on a couple of new features, like the Today widget and the Share extension. That was the first introduction of Swift into our code base.
The next major iteration was Project Voyager. As for the SlideShare app, a lof of our decision to use Swift revolved around timing: engineering discussions for the rewrite of the app had just started, and we knew that it was unlikely that another complete rewrite would happen soon. We didn’t want to be stuck using Objective-C years from now, wishing we had switched to Swift when we had the chance. We were also really excited about a lot of the language features of Swift itself.
Growing Pains (4:01)
We were there in the early days, in the betas. At that point, Slideshare had about 275 Swift files, and the slow compiler was an issue. The SlideShare compilation was slow in comparison to Objective-C, but not terribly slow overall.
Syntax highlighting and autoccomplete were either slow or crashing, and a select few classes had to be written in Objective-C for Interface Builder support. The abundant source kit crashes, of course, were quite an issue as well, but they separated that into a separate process, so at least you could keep typing.
There was no migration tool for the language changes in the beginning, which was quite a pain. With the size of SlideShare’s code base, it usually only took us a day to make all the changes manually, but it was still a pain.
By the time we started with Voyager in January 2015, we also had a small code base. However, by the time we got to the summer, the compiler was a really, really huge issue. As of today, we have 2,748 Swift files, so this was a pretty large problem.
At our peak last summer, we were at 25 minutes for a cold build on the maxed out 15” Retina MacBook Pro with an upgraded processor. Apple’s Migration Tool would crash on our code base, so we couldn’t actually use it. The app binary size kept increasing, and the load time would also increase, so we were having a lot of growing pains with it. We were pretty concerned.
Workarounds: Voyager (6:13)
We addressed several issues, the first being the code structure. When we started out, our code structure was already fairly modular, since we have a lot of different pillars at LinkedIn (i.e. Identity, Messaging, Feed, etc.), but we had to completely modularize it.
We dropped iOS 7 support so that we could switch to dynamic libraries. We looked at our adoption numbers, and realized that iOS 9 would be out by the time we launched our app, so we could afford to drop iOS 7 support.
We started modularizing using Cocoapod’s dev pods, which we eventually had to drop because they broke debug symbols so nobody could debug anymore. We manually converted all of the dev pods into dynamic frameworks, which was a huge, painful process, but it allowed us to still include everything correctly and be able to access debug symbols again.
Xcode 7.0 was a huge savior. It decreased build time dramatically, resulting in a 26% speed boost. The con here is that we actually had to manually migrate this, since the Migration Tool crashed, which was again a huge pain. This is at the peak of our development too, so someone would try and figure it out, and then you’d do a rebase and you’d have to fix all of the merge conflicts. It was pretty bad.
We also switched all of our generated models to Objective-C, since nobody was coding using those directly anyway. The Objective-C compiler is still much faster than the Swift compiler, so that gave us a good boost.
The best part, though, was that we actually got Mac Pros approved for all of the iOS developers on the team, which gave us a 2X speed boost over the top-of-the-line MacBook Pros. That made our lives a lot happier.
Workarounds: SlideShare (8:52)
We did some testing on how much improvement we could get from a Mac Pro, and it was more of a linear progression for our code base, which was not very modularized and didn’t have separate frameworks. If you went from 4 cores to 12 cores or something, then you’d get a 3x speed boost. It depends on your code base if you’ll get that type of improvement, but in general: the more threads, the better.
We also dealt with the increased cold launch time in iOS 9, which is due to an issue where if you have a lot of dynamic frameworks being loaded, it’ll increase your app loading time. It can be pretty significant if you have a lot of dynamic frameworks. For us, it made it to the point where if all of our frameworks were dynamically loaded, the app wouldn’t even launch because it would take 10 to 12 seconds, and the system would just kill it. We had to change some of the libraries to be static instead so that we could have our app actually launch in a reasonable amount of time.
The Pros (10:28)
In SlideShare, we found that Swift’s syntax was way cleaner, and easier for newcomers to get up and running. Optionals, initialization rules, and static typing were all really good and much safer. New team members who were new to iOS didn’t kind of need to learn about all of the baggage associated with Objective-C. Using optionals, we could avoid crashing a lot more and use asserts instead.
For Voyager, we saw whole classes of bugs disappear (i.e. null pointer exceptions), as long as you never force unwrap optionals. One caveat is obviously if Objective-C libraries aren’t annotated properly, then you would have some issues with the implicitly unwrapped optionals. We enforced this using some of the Swift lint tools.
As for SlideShare, we also found it easier to onboard web developers or those coming from Java. It was very noticeable when we had interns starting; they learned Swift and got up and running much faster than they did with Objective-C. Swift’s community is also active and helpful, which is great for sovling problems quickly. The functional programming paradigms were nice to try and adopt in the app as well.
Libraries (12:31)
SlideShare hasn’t integrated any Swift libraries at this point, only Objective-C libraries. Upgrading caused some problems with our internal code because of our Today extension, so we didn’t actually get to include Swift frameworks, like the use_frameworks!
flag in CocoaPods. We also stole a lot of developers from around the company to pull this off.
In Voyager, many of our internal libraries are still written in Objective-C, but we do have some that are written in Swift. We do dependency management through CocoaPods.
Key Takeaways for Teams (13:23)
For large teams and large apps: modularize from the beginning.
I can’t even imagine how difficult it would have been for us to fix the build and compile time issues without having a modular code base to start off with.
It will be faster for you to train new devs in Swift.
// Objective-C
if (myDelegate != nil) {
if ([myDelegate respondsToSelector: @selector(scrollViewDidScroll:)]) {
[myDelegate scrollViewDidScroll:myScrollView];
}
}
// Swift
myDelegate?.scrollViewDidScroll?(myScrollView)
I like Objective-C, but it’s not an intuitive language. Swift is more modern, and it’s so much easier that you get less of the newbie errors that were rampant in Objective-C.
Objective-C is still a valid option.
There are still a lot of Swift bugs that will cause crashes in your app, especially when Apple updates an iOS version. That’s pretty frustrating. If you choose to work in Objective-C, you won’t spend as much time working on workarounds with the language and the tools. We had an entire tools team, and they kept on adding more and more people on it to help us with a lot of these issues.
Managing Xcode versions is still a pain.
You’re still going to have to do branching if you want to keep your code up to date, and that can cause issues. In SlideShare, we originally released with Swift 1.1, and then when 1.2 came out, we didn’t want to have to do the whole migration until we were ready. We made the mistake of not testing the app on iOS 8.1 beforehand because we didn’t upgrade Xcode, and then there was a crashing bug that happened every time you rotated the device. We had to quickly update the code base to 1.2 that day, then fix it in the old code and release. In Voyager, it took months to upgrade to Xcode 7.2. The actual migration took one to two days, but the investigation into what we we needed to fix in our code base took quite awhile.
Now is a Great Time to Start! (16:55)
Xcode 7 and Swift 2 are here, and they are so much better than than Xcode 6 and Swift were last summer. It’s much more stable and the build times are significantly improved.
To help, we made a style guide for using Swift in iOS apps like SlideShare, which we also based the flagship style guide on.
Importantly, Swift is now open-source, so now is a really great time to start!
Should I Use Swift? (17:38)
For small teams with a brand new app: YES
In the case of SlideShare, the pros of Swift definitely outweighed the cons. We didn’t have many issues with tooling because there were very few people working on it, and it wasn’t a large impact or a huge code base where we had to spend a long time trying to work around these issues. Build times, though longer, were not as much of a problem. Build times are better now anyway.
For small teams with existing Objective-C code: YES, but…
If you have an Objective-C app already, code new features in Swift, get familiar with the language, see where the benefits are, then maybe go back and refactor some Objective-C where you think you’ll see significant benefits. Don’t go back and rewrite the entire app in Swift just because you can, unless you’re planning a rewrite for other reasons.
For large teams: MAYBE
You will spend less time on-boarding new developers, and you’ll make fewer mistakes and bugs because the language itself is stricter. However, you are going to spend more time on workarounds for tooling and code, which is maybe a considerable amount of time for larger teams. You decide what’s right for you!
Q&A (19:47)
In a large code base like you have, I’m assuming you have a branch that probably has some of the upcoming changes in Swift 3 or 2.2 which can’t compile at the moment, and in your current code base, you can drop the increments like ++
and --
. How are you handling that in your work flow, especially since you have 2500+ classes? How are going to merge those conflicts?
Kamilah: At least for Swift 2, we did have one or two people on a separate branch a month or two in advance of when we were actually going to do the migration. With each update of the Swift version, they would update it and see how it worked. We have someone for future versions who starts to try it out on a separate branch.
Kyle: Yeah, we definitely aren’t investigating the Swift 3 changes yet with the new compiler that’s not out. We have to be a bit more conservative with such a large app that hits so many people, so we’ll adopt it a little more slowly than others may. When we get around to thinking about doing the migration, then we’ll make a branch to try things out, but I don’t think there’s a big concern in trying to keep that branch exactly correct. We’ll just do a whole migration all at one time later.
Kamilah: Yeah, it’s a little too early for us to start adopting that. Plus our machines have to be serving all of the apps at LinkedIn, so it’s way too early for us.
Q: You mentioned that you stopped using dev pods. What was the problem?
Kamilah: It was unclear where the problem was, if it was on the CocoaPods side or the Apple side, but basically it was not reading the symbol table. Once you were in Xcode and you would try to do a PO to see any symbol, you could not get anything out of it. We had to stop because nobody could debug in the app. In the end, we basically manually did what dev pods are supposed to be doing. We still use CocoaPods for all of our external libraries, just not for the internal teams.
Q: What are your opinions on writing tests in Swift?
Kamilah: We have actually a pretty good test suite, and it’s definitely superior to what we had in our old code base. We have a layout testing library, so we do a lot of our unit tests and layout tests, and they’re pretty fast. For our scenario tests, we use a version of KIF, an open-source testing framework. We actually did some work on it, which I think somebody is working on and contributing back. It was a little bit slow for the massive amount of tests that we had.
Kyle: The layout tests are really cool. As far as writing unit tests on like viewDidLoad
and things where it doesn’t really make sense, these layout tests really catch a lot of common bugs. Especially if you’re writing tests for multiple devices and size changes, you may not think of all these different combinations of long text and small buttons, so this layout test library makes it extremely easy to test for all of that.
Q: I was wondering if you could talk a little bit more about the journey from your static libraries to dynamic frameworks and then back to static libraries for some of them.
Kamilah: For at least the last step, we’re sort of converting it in build sequence, so we’re still dynamically linking them when you’re working with it. We convert them back to static when you’re actually creating the package, because this is purely for the app itself being installed on the device.
Q: About your modularity, are you sharing that code between a few apps, or is it just to divide up the logic inside your own app?
Kyle: As for dev pods into frameworks, those are internal to just that app, so that’s why we’re calling dev pods. Different sections of the apps for different portions would be separated.
Q: You mentioned Swift lets you write code with fewer bugs and crashes. Do you have data to compare the old app versus the new one? Not that I don’t believe you, it would just be interesting to know!
Kyle: I think it would be a little difficult to compare since it’s completely rewritten and it’s a lot of different features. I don’t know if we’ve actually compared those numbers. It won’t be apples to apples, Objective-C versus Swift because it’s totally different. We should probably look into that, I guess!
Q: I was wondering whether there were any process changes or tooling changes you had to make, given that a lot of your developers are coming from Objective-C? How do you switch over without introducing a bunch of bugs or causing a slowdown in the actual development time?
Kamilah: We had maybe two training sessions that we sent developers to, like the two-day Swift thing from Big Nerd Ranch, so that was our initial throw-you-into-the-deep-end training. We actually have a lot of developers on the project who are new college grads, who came in writing Swift. I think it was a pretty smooth process though, overall.
Kyle: Yeah I think a lot of our developers who had been around awhile were very interested in Swift and were doing their own analysis of the language, trying to learn everything they could.
Q: Did you guys arrive at any style opinions around developers writing Swift? Also, you mentioned that you are switching between static and dynamic dev pods, and I was wondering how you handled any static transient dependencies that you might have in those.
Kyle: As far as the stylistic question, we have a style guide that I created for SlideShare that has some opinions, but I don’t think made anything too strict because everybody’s still figuring out what the best practices are. You can take a look at that and see for yourself how opinionated you think it is.
Kamilah: For our initial conversion from folders to dev pods, I think that was actually not that painful. Switching from dev pods to dynamic frameworks was much more painful, since that was basically us taking one dev pod, going through all of the settings in Xcode, and playing with all of them until we figured out which one allowed us to add it correctly. When it generated an app, all of the framework was picked up correctly in the right order. So there was a lot of trial and error there.
Q: While my team has been writing Swift, we’ve been noticing that we’ve had to promote some things that should be private to internal so they’d be accessible by the test bundle. I’m wondering if you guys ran into a similar problem.
Kyle: First of all, I think we’re not even using @testable
. I don’t know if we changed that, but because we saw slow downs in compilation with that keyword, that was an issue. I think we were mostly having to make things public that we really wanted tested, right?
Kamilah: We didn’t find any workarounds with that. It is unfortunate, definitely. The @testable
thing should be helpful, but for our code base size it was still an issue.
Receive news and updates from Realm straight to your inbox