The Grand iOS Migration: Was it worth it?

Ada Kirsch
Haiilo
Published in
6 min readJun 26, 2020

Let’s switch topics a little bit and talk about mobile today! Specifically about the iOS app we are developing at COYO called COYO Engage.

Recently COYO Engage for iOS has undergone a huge refactoring that included the migration from a native Core Data object graph and persistence framework to a third-party Realm database. And when I say that the refactoring was huge, I mean it. Just look at the size of the final pull request:

The final pull request with all the changes

But why did we need this change in the first place? Was it worth all the time and effort that was put into it? Long story short, yes. But let’s take a deeper look at the reasons, processes, and results.

Why did we decide to migrate?

For months iOS Engage was struggling with Core Data crashes, mostly related to channels synchronisation. The worst part of these crash reports is that they are mostly unreadable and extremely difficult to figure out. We knew that something was going wrong, but didn’t know how to fix a problem we couldn’t reproduce. After numerous attempts of trying to solve these issues, we realised that we have multiple pain points in our codebase: network layer (communication with the server, requests, and responses handling), synchronisation logic and the database itself.

After discussing and looking into different options and solutions, we came up with a plan for fixing these problems:

  1. We refactor our Network layer. We used to use a third-party library for firing requests and parsing responses. Not that long ago, Apple improved its network data-transfer API that perfectly covers all our needs. So a decision was made to use this native API instead of the third-party library and simplify our Network layer codebase.
  2. Migrate our old code base to VIPER. In the iOS Engage we use VIPER architecture. We still had some old classes based on the old architecture that needed to be migrated.
  3. We migrate from a native Core Data to a third-party Realm database (more on Core Data and Realm later). Because of all the issues we had with Core Data, we decided to rethink our local database layer and try something new. Realm was fitting all of our requirements: free, tested for years by lots of apps, easy to use.
  4. Finally, with the new database layer, we can rethink our synchronisation code. It used to be a huge mess with thousands of lines of code. Only the bravest were able to dig into it and fix issues.

With this plan in mind, we started the refactoring. The biggest change from this whole plan is the migration to a new database with all its consequences. Of course, not all of the developers jumped straight into this topic. We had one developer, who was mainly focused on the refactoring, while other developers took care of ongoing epics, new features and were helping with refactoring in the spare time.

Core Data vs Realm

Before we dive into the process and results, let’s take a quick look at Core Data and Realm.

Core Data

Core Data is an object graph and persistence framework provided by Apple. You can treat Core Data as a framework to save, track, modify and filter the data within iOS apps, however, Core Data is not a Database. Core Data is mainly using SQLite as its persistent store. So basically, it is a layer between the SQLite database and a developer to make interactions between these two parties more convenient. However, even though Core Data is intended to simplify our interactions with a database, the learning curve with Core Data is massive. You need to learn a ton of stuff to just get started with it. Apple tried to simplify this in the most recent Core Data update, but still, you need quite some time to get started. And that, of course, leads to the fact, that it is quite easy to make a mistake working with Core Data. Especially when it concerns multithreading.

Realm

Realm is a mobile file-based database, acquired by MongoDB. Realm is not using SQLite as its engine. Instead, it has its own C++ core and aims to provide a mobile-first alternative to SQLite. Realm stores data in a universal, table-based format by a C++ core. This is what allows Realm to be used on different platforms. Because of this unique design that is focused on mobile platforms, the main benefit of using Realm is its speed. Realm Team even made a bold statement of up to 10x speedup over raw SQLite for normal operations.

Having a speed boost, is of course, nice, but this is not the reason we decided to move to Realm. The main reasons are the stability of this library and how easy it is to use. Out of the box, Realm is much easier to get your head around than CoreData. To use CoreData you need a deep understanding of the API which is spread across several related classes when on Realm you can try something out almost right away.

Of course, most of our team had at least a basic understanding of Core Data and almost no experience working with Realm. So we knew that there will be learning to be done and that we can make mistakes at early stages. But weighing all pros and cons of Realm, we still decided to take this risk.

Funnily enough, COYO is the second company in a row for me where the decision to migrate from Core Data to Realm was made. The reasons are lots of crashes and difficulties in working with another Apple Framework — SceneKit (framework to work with 3D scenes), which is quite ironic.

The Process

As mentioned before, only one developer from the team was dedicating most of his time to the refactoring. Other developers helped when they had some spare time. Because of that, the iOS team was still delivering all the new features that our Android colleagues had at almost the same pace.

However, as good as it sounds on paper, we stumbled upon some issues with the process like this. The whole refactoring process took us a few months. It was done in a separate branch, that should pull changes from the development branch regularly. In the meantime, other developers were working on adding new features, changing an existing structure of the project, fixing bugs, etc. As you can imagine, the merge conflicts were unavoidable. Some of them were minor, some of them required more than 1 developer to solve. However, this made us realise that we need to rethink our branches structure, when do we merge a new feature to develop and how often do we release new updates. But being a small and agile team helped us try new things and settle on a new flow that works for us (at least at this stage).

For the overview, here is what we did during this refactoring:

  • completely rebuilt our Network layer. We got rid of the 3rd-party library we used, rewrote and simplified the requests firing and parsing logic, updated models and removed unused fields;
  • completely rebuilt our Local Database layer. We moved from Core Data to Realm, rewrote our local models, rewrote the whole database interaction and synchronisation logic, and greatly simplified our codebase;
  • migrated the leftovers of the old code base to a VIPER architecture, that is used in the app;
  • lots of minor quality of life improvements.

And what’s the point?

The refactoring was shipped to all users in the 3.1.0 update, which was released on 18.05.2020. It’s been more than 1 month since the release, so we can talk about the results. First, just take a look at the picture below. I think it speaks volumes:

Number of crashes before and after the refactoring

At the moment of writing this article, we are at 99.44% crash-free users, which is amazing! Before that, we were at around 87% of crash-free users.

On the other side we, as developers, are really happy with the results we have achieved. The new code base is much cleaner and easier to work with, we got rid of some 3rd-party libraries and, of course, we learned and tried out new things. Did we achieve our goal and are happy with the results? Absolutely yes and I hope our users appreciate that.

What’s next? The next big step for the iOS team will, probably, be a migration to SwiftUI and Combine, which is a move from imperative to reactive programming. But for now, we will focus on improving the product and add new exciting features.

--

--