Slack succeeded in the effort to bring their iOS and Android apps up-to-date and adopt new design trends. Among other things, this enabled a full switch to Swift for iOS.
When Slack engineers decided to revamp their iOS and Android apps, they had to face the reality of two several year-old codebases that had grown organically and accumulated a significant tech debt over time. After discarding the idea of a complete rewrite as well as of reusing code across platforms, they decided for a complete refactoring.
Choosing this option did mean that we had to deal with our existing tech debt — we had to migrate our legacy code and re-architect the apps in place, while keeping the app shippable and continuing development of new features.
To accomplish their result, the team devised three different goals: stabilizing their codebase to get rid of the tech debt; modularizing the apps into separate components; modernize their design and tech-stack commitments.
Stabilization was the first, enabling step. On iOS, it included rewriting in Swift the remaining parts of the app that were still written in Objective-C. According to Slack engineers, the coexistence of Swift and Objective-C code in the same project made compilation slower and impacted performance, but mostly hindered the adoption of new Swift language features due to interoperability requirements.
In addition, they had to rewrite some code that accessed Core Data directly and make it use their own Core Data-based persistent framework, which improved performance and stability. Likewise, all network operations were rewritten to use an internal connectivity framework.
On Android, most of the work aimed to split a couple of monoliths used for networking and database access, in the latter case adopting SQLDelight and migrating all existing SQLite queries to use it. Additionally, the Slack team adopted the repository pattern, which made it easier to support smarter caching and improve performance.
A key factor in the stabilization phase was tracking progress using clear metrics associated with each one of the goals described above. For example, to track Objective-C to Swift migration, the team used a script to count how many Objective-C files were remaining, while counting deprecated class and method names was useful for the rest of the goals.
Modularization, as mentioned, aimed to carve a number of components out of the two existing monoliths. This effort reduced interdependencies and build times, which had grown larger with the codebase, but mostly made it possible for distinct teams to work in a more independent way.
Slack engineers provided much more background and detail about the stabilization phase of their project than what can be summarized here, so do not miss the original post to get the full picture.