The Swift 3 Grand Migration
Some days ago I finally merged one of the biggest Pull Request our team has seen, the migration of our codebase to Swift 3. I decided to write some words here as a way of remembering the beginings of the language we expect to work with for ages.
At the time or writing a draft for this post the team at Airbnb and Firefox (and many more, it has become a thing now) shared their experience with the migration. Is worth a read if you want some other view on the topic, with a bigger team and resoursces.
Without counting the time spent looking at the support of the third party libraries to make sure we had a clean path for the migration, I started working on it the 27th of January. Take into consideration that I haven't been working on this full time during this period, so the absolute hours are somehow more realistic than the actual number of days. According to my time logs I've put 64 hours into it. I've been working on it alone as we couldn't afford disrupting the rest of our feature teams, at least until the PR had to be reviewed.
I've been writing Swift since it was made publicly availalbe and I still considered a big mistake when it was decided to start witing Swift code in our project, and in retrospective I'm even more convinced that I was right. Luckly I've been actively avoiding moving to Swift our entire codebase until the langauge was more stable. But in the past few weeks, new project and new joiners have started writing mainly in Swift so it become a big tension between different priorities. We coudln't aford the time to do the migration but we had to do it as soon as posible in order to avoid adding more inmidialty deprectaed code.
The migration nightmare
From our entire codebase only 13% is in Swift, is so cool that GitHub shows you this so easily! Probably some people will be ashamed of this but I'm quite happy with it, and remember that I love Swift. The project has an established arquitecture that, altough it needs some imrpovements, it allows us to write new features without any issue, we are fast writing Objective-C and we are happy with it.
If tt took me that many hours to migrate only 13% of our codebase, I can't imagine doing it if we would have been writing Swift earlier and all over the place. But now that is done we can safely move to it! About time!
One of the most asked questions is: doesn't the Xcode migrator deal with it? Mmmm yes… well… kind of. The issue with Swift 3 migration is not the language changes themselves, at least not the ones that directly affect your own code. Xcode deals with those, and I have to say that I'm quite surprised by the good job that it did. In fact before this project I migrated other 3 personal projects and it was just a couple of hours. What is the issue then? Dependencies and the Grand Renaming of their APIs.
In our case it was Alamofire and the huge changes they did when migrating to Swift 3. The way the Swift part of our project was structured had Alamofire dependent code all over the place, and it used so much function overloading that the migration was a nightmare. When I could wrap my head around all the required changes (Alamofire migration document helped, but it was missing some important points) Xcode would freak out with so many errors, and when that happens there is no way to convince the compiler that there is a function overload that matches what is needed. The worst nightmare.
This is the screenshoot that I used in our PR, a small inside joke and my feeling at the time :P
Is Unit Testing worth it
The other thing I wanted to talk about is tests and the ethernal discussion of if they are a waste of time or are lifesavers. In this monumental task I had the oportunity to feel the two sides of the coin.
On one side there was the pain to have a lot more code to migrate, the test code, that came with its own set of challenges. Specially the fact that in some ocasions you can't be sure if a test is failing becuase the test code has been wrongly migrated or because the production code has been broken.
On the other side, those tests, once working, ensured that my changes were reflecting the expected behaviour, something that for now is giving us confidence that we haven't broke that much, if at all. And that's a big relief. It also helps that you can check your changes with a test run instead of having to deal with UI and edge cases that are hard to reproduce.
More than a migration
I also took some of the time to completly rewrite a couple of screens of the App. Luckily they were the only ViewControllers that were written in Swift and they were originally written without much experience with the language and at a time when there was no care on adding bastardised objectivecfied Swift code everywhere.
It was a good chance to make some changes. I already had to spend the time migrating those screens and they didn't follow any patterns used in other parts of the app and had plenty of bugs since the first day they were merged, so I didn't hesitate on rewriting them and even reusing properly the ViewControllres.
After the changes I ended up with less code, proper reusaiblity and more Swiftiness. There are still some parts I would have liked to improve but I I was running out of time and there was still a huge PR review to do.
The Pull Request
The Pull Request was something that took many days. It was important because even not being a high prioirty for the busniess, it was a big deal for us because one of our feature teams was migrating our news feed to IGListKit and it was decided to write that code in Swift as it is expected to be there for the long term. This was one of the main projects that was in a complicated situation, writing already out of date code. I had to finish the migration before they had too much code to migrate.
Another important aspect of this migration is that I didn't intend to change the naming conventions of everything to be aligned with Swift 3. I did the ones that were obvious an easy but not all of them. In my opinion to be a proper Swift 3 API you need to rethink many things, not only changes a couple of naming conventions. I left this out of the scope. In any case the current APIs privded by our Swift code will likely be changing in upcoming refactors so it was not really worth our time.
Here you can see the final PR stats, including dependencies migration.
After my teammates spend quite some time reviewing the PR, which I'm really thankful for, we pressed the button!
And it is finally done, after 30 days we have our poject using Swift 3. Now I can start migrating to Swift 3.1 😅.
For now we haven't find any regression made by this code. Luckly being such a small code change, percentage wise, we know which parts of the App may be affected so I don't expect it to be a big deal.