Scaling iOS at Bumble: Part 1/3 — The Challenges

Jonathan Crooke
Bumble Tech

--

Introduction

This article is the first in a series of three. We’ll be presenting work undertaken during 2022 and 2023 aimed at tackling the challenges of scaling our iOS production apps.

Who are we?

Bumble Inc. is the parent company of Bumble, Badoo, Fruitz and Official. The Bumble platform enables people to build healthy and equitable relationships, through kind connections.

Founded by CEO Whitney Wolfe Herd in 2014, Bumble was one of the first dating apps built with women at the centre and connects people across dating (Bumble Date), friendship (Bumble BFF) and professional networking (Bumble Bizz). Badoo, which was founded in 2006, is one of the pioneers of web and mobile dating products. Fruitz, founded in 2017, encourages open and honest communication of dating intentions through playful fruit metaphors. Official is an app for couples that promotes open and honest communication between partners and was founded in 2020.

Who is this for?

This blog post series is aimed squarely at teams operating at scales similar to ours. So what is our scale?

Scale at Bumble Inc.

iOS development at Bumble Inc. is certainly not small! We have:

  • Dozens of engineers
  • Hundreds of modules
  • 100+ feature workspaces
  • Millions of lines of Swift, with a dusting of ObjectiveC for old time’s sake 🙃
  • Tens of thousands of lines of custom tooling code
  • Lots of modularity, and of a quite high standard
Just a tiny section of our module graph

This might seem to readers as a pretty large scale. However in this article series we’ll be considering Bumble Inc. as a medium scale team. So why is that?

“Medium” sized teams

We’ve chosen this medium terminology to emphasise the “in-between” state that teams can fall into in the iOS ecosystem.

  • On one hand you have the small team; the startup, the individual Developer. Apple’s Developer marketing often seems oddly focussed on these kinds of teams! They’re very happy with the out-of-the-box Developer experience (and why not!)
  • At the other extreme you have the biggest big names in the industry. You know their names! They’ve got the largest Developer head-counts, constellations of products and millions upon millions of lines of code. These companies can justify large investments into infrastructure tooling alone, and are often the originators of the very kinds of tools we’ll be discussing in this series.

And in between those two, you have middle-scale teams; while Bumble Inc. is certainly not a startup or an indie app, we’re also not one of the industry’s most gigantic giants. And we’re not alone; most of our peers are operating at this scale.

Being in the middle

When projects scale up from startup or indie size, up to this medium scale, there is an all-too-familiar experience: that previously-idyllic Apple Developer experience begins to fail. What do we mean by this?

Modularity, build times, Xcode

It’s simple enough: the more code you have, the more time it takes to compile, read, save and index.

Those who have worked on large Xcode projects will know that its performance degrades as project sizes increase; workspace opening times, file operations, and of course build times! Modularity can mitigate this: structure your code well enough and you can increase parallelisation and caching. But modularisation needs to be easy — if there’s too much friction when moving, splitting, adding and removing modules, then it’s less likely to happen.

Of course you can create frameworks and adjust projects in Xcode. The problem arises when these operations start affecting more than a handful of modules — then you’re in trouble; Xcode has no tooling for performing batch project modifications. Thankfully the developer community provides plenty of tools to help wrangle the .pbxproj format. At Bumble Inc. we’ve written tools based around XcodeProj. Whilst this unblocked us, it also left us with plenty of custom tooling code that needed to be maintained, and which was only as flexible as the features we’d already implemented.

Over time it begins to feel like you’re serving Xcode’s project format, and not the other way around!

Team and collaboration

Scaling a project is not just about increasing lines of code, it’s also about scaling the team itself. The surface area of project work needs to expand in order to accommodate an increasing number of developers working on the codebase.

Once again, .pbxproj shows its limitations; project files are text, but describe a complex object graph, making them barely human-editable and containing much redundancy. Merge conflicts can leave you with projects that can’t be opened, and the same applies to .xibs and .storyboards. Text editor surgery is possible as a last resort, but hardly a productive solution.

But it’s not just us — these issues are commonly documented around the Internet:

What to do?

As we previously mentioned, teams of this size have a double-bind: the traditional Xcode-oriented workflow is slowing their velocity, but they aren’t in a place to make large in-house investments into infrastructure. These teams must then make pragmatic choices from off-the-shelf tools, and research their options carefully.

So, entering the early stages of this project at the beginning of 2022, the Bumble Inc. iOS Core Team was in this situation. In the remainder of this series we’ll be looking into which solutions we considered, what we chose, and how it worked out for us.

The specifics — where we were

Before going further, we should take inventory of where we were as a team going into this project.

While we were reaching the limits of our existing solutions, we had been able to leverage them with a high level of success. We had a well-layered architecture and a large amount of modularity, and with a good level of uniformity. We were already templating our module types and sharing their common settings using a large network of .xcconfigs. As previously mentioned, we automated module operations by parsing and mutating .pbxproj using custom tooling built with XcodeProj.

Other than that, we were and still are almost entirely in a monorepo and had a concept of “feature workspaces” that allowed playground-style development away from the entire codebase, particularly for SwiftUI. We had a low double-digits count of third-party dependencies and a powerful CI and testing infrastructure.

Overall we had the means, motive and opportunity to make a big switch in our core workflow. But what solution would suit our needs?

Goals

So what were we looking for?

  • The ability to remove and/or significantly reduce the amount of our custom tooling
  • Significantly reduce the friction involved in modularisation
  • (Ideally) improve build speeds, or at least place ourselves in a better position
  • Open the door to new ideas and workflows
  • Preserve as much maintainability and future-proofing as possible
  • Untrack .xcodeproj from the repository 😉

The Solutions

Throughout the course of our research projects, we considered three tools:

  • Swift Package Manager — core code distribution tool for the Swift language
  • Tuist — a third-party development automation toolkit
  • Bazel — a no-nonsense, fully featured traditional build orchestration tool, originally developed at Google

It’s important to note that these tools are not equivalent. They do not have strictly overlapping feature sets. However, they all address our goals, albeit achieving that in different ways.

🍎 Swift Package Manager (SPM)

SPM was the first tool we investigated, and it brings with it a certain amount of “first-party cachet”. Since Xcode 11, it is fully integrated into the Xcode toolset and requires no installation. This means no direct maintenance on our part. A great advantage, since we’d rather be using a tool rather than maintaining it.

Some readers may be surprised to see the inclusion of SPM, and this is likely because it already has the image of being oriented around third-party dependency management, in the vein of good ol’ CocoaPods. However, while you certainly can pull dependencies from Github.com and so forth, SPM also supports file URL sources. Therefore we can just as easily pull in local modules from within our monorepo.

Once all modules have been migrated to SPM Packages you’re very close to not needing .xcodeproj at all — although not quite (more on that later). So, could we just go with the out-of-the-box solution?

It’s the de-facto tool, but would it suit our needs?

🇪🇸 Tuist

Unlike SPM, Tuist is a third-party solution. With its first version being released in 2018, and version 1.0 following in 2019, it’s still relatively new on the block. However, it has already gathered a lot of support from the community in that time and is shipping releases regularly.

At its heart, Tuist is an opinionated project generator, which leverages that functionality to deliver a toolkit that’s very oriented towards the needs of exactly the kind of team and projects that we have.

Would its features be appealing enough to prefer over the shiny Apple solution?

🪴 Bazel

Bazel is another matter entirely. It is a fully-fledged, multi-platform build orchestration tool. So not only is it third-party, not built by Apple or the Swift team, but is not directly oriented to the iOS ecosystem at all! The engine of Bazel itself must be combined with rules needed to build and package particular build inputs. Oh, and it requires learning a new language, although that language is likely to be somewhat familiar.

In spite of that, Bazel unlocks a lot of power and promises to do some very impressive things. It is also the only solution of the three likely to deliver improved build speeds on day one. But it is also a dramatic departure from the traditional Xcode way.

But would all this power be enough to justify its costs?

What’s next

In this post we explained where we found ourselves going into this project, what our goals were, and the tools we were to consider. In our next post we’ll talk about the investigations themselves, and what we learnt about each tool. See you then!

--

--