Articles
Refactoring Uber’s Rider app
We burned the old code. Literally. We printed it out, took a trip out to Sunset Beach, and burned it in a bonfire pit so it would never haunt us again.

There was a lot of discussion at the end of 2020 about Uber’s mobile apps, largely due to a Twitter thread by McLaren Stanley. Many wondered aloud why we didn’t just refactor the app instead of rewriting it.
I thought I’d add some context into where things were prior to the rewrite.
In the beginning…
I joined Uber in December of 2013, shortly after “Guinness” (a redesign of the app) launched. I was mobile engineer #8; I think all of engineering was around 130 people. At that time, the app had a fairly constrained feature set — “push a button, get a ride.“ Products like uberPOOL didn’t exist yet.
Trip Lifecycle
When you dig into the lifecycle of a trip, there are several steps. The “core flow” breaks down into four main ones (shown above, albeit with a more updated design than existed at the time I joined):
- Looking — you’re effectively “browsing.” You haven’t set pickup location yet (remember, prior to the 2016 redesign, pickup location was the primary entry point; before the redesign of the address bar (in 2014?) the only place destination could be entered was on the confirmation screen, and most people blew through that screen). The “Guinness” redesign introduced the product slider. When you’re “looking” you can change which product you want (Black Car, uberX, etc), and the map updates when you change your selection. As an aside: this was all controlled by the city teams. There was no global notion of “uberX” (which became extremely problematic later — another post for another time). City teams could add whatever they wanted to the slider — the tooling on the backend allowed them to provide the name, rates, and the necessary image assets for both the slider and the map; the client apps simply displayed what the server told them to. This is how city teams were able to do things like UberKITTENS without involving an app release.
- Confirming — you have set the pickup location and are on the confirmation screen. Here you can switch your payment method, get a fare estimate, enter a promo code, etc. Note: This step only exists client-side; the server doesn’t model this step (and rightfully so). Again, most users quickly clicked the “Request” button without doing much else on this screen.
- Dispatching — you hit the “Request” button on the confirmation screen and have requested a ride. Once the server gets the request, it will start matching you with a driver. We eagerly move you into this state on the client as soon as the button is tapped; it may take a few seconds for the request to hit the server and to acknowledge that this is where you should be in the sequence. You remain on this step until the server says that a driver has accepted the trip or kicks you back to “looking.” Until the redesign of the address bar launched, this screen was the black grid on which you could draw.
- On trip — a driver has accepted the trip and is en route to your pickup location, or you’re already in the car en route to your destination.
There are lots of other potential steps in the flow (e.g. surge pricing requires confirmation above a certain threshold, payment method rejected, outstanding balance due, Uber doesn’t service that area, etc.), but the ones listed above represent the typical case.
Complexity
In the Rider app there was a class called UBRequestViewController
, where most of the logic to handle these steps lived. In reality, it could have just been called UberViewController
, because it contained most of the logic of the app. This made sense at the time — the team was small, the supported features were simple, etc. Over time, however, this class began to bloat. Support for additional payment methods was added (e.g. PayPal, Alipay), some of which introduced additional steps. In 2014 uberPOOL launched, which greatly increased the complexity of the app. In addition to the greatly-expanding feature set, the team also began to grow — we were adding a dozen new iOS engineers every month.
At its peak, this class contained over 6,000 lines of code.
Massive View Controller is right. pic.twitter.com/bQjPRKRHsk
— Tyler Stromberg (@aqua_geek) October 7, 2015
One of the most tenured iOS engineers on the team:
[…] we don’t say it but we are all secretly scared to ever touch the request view controller!
