Top Banner
Uber’s New Mobile Architecture Uber Mobility April 19th, 2017
77

Uber's new mobile architecture

Jan 21, 2018

Download

Engineering

Dhaval Patel
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Uber's new mobile architecture

Uber’s New Mobile Architecture

Uber Mobility

April 19th, 2017

Page 2: Uber's new mobile architecture

Why a new architecture?Tuomas Artman

Page 3: Uber's new mobile architecture

Uber’s entire mobile team 4 ½ years ago

Page 4: Uber's new mobile architecture
Page 5: Uber's new mobile architecture
Page 6: Uber's new mobile architecture

“What if we changed everything?”

Page 7: Uber's new mobile architecture

99.99% availability of core flows

Enable global roll-back of core flows to a

guaranteed working state

Testing as a first-class citizen

Architectural goals

Page 8: Uber's new mobile architecture

99.99% availability of core flows

Enable global roll-back of core flows to a

guaranteed working state

Testing as a first-class citizen

Support Uber’s growth for years to come

Narrow and decouple functionality as much

as possible

Architectural goals

Page 9: Uber's new mobile architecture

99.99% availability of core flows

Enable global roll-back of core flows to a

guaranteed working state

Testing as a first-class citizen

Support Uber’s growth for years to come

Narrow and decouple functionality as much

as possible

Provide rails for both design and code

Consistency in engineering, consistency in

UX

Architectural goals

Page 10: Uber's new mobile architecture

99.99% availability of core flows

Enable global roll-back of core flows to a

guaranteed working state

Testing as a first-class citizen

Support Uber’s growth for years to come

Narrow and decouple functionality as much

as possible

Provide rails for both design and code

Consistency in engineering, consistency in

UX

Monitoring is a first-class citizen

Automatic analytics, logging, debugging, and

tracing

Architectural goals

Page 11: Uber's new mobile architecture

99.99% availability of core flows

Enable global roll-back of core flows to a

guaranteed working state

Testing as a first-class citizen

Support Uber’s growth for years to come

Narrow and decouple functionality as much

as possible

Provide rails for both design and code

Consistency in engineering, consistency in

UX

Monitoring is a first-class citizen

Automatic analytics, logging, debugging, and

tracing

De-risk experimentation

Application framework with Plugin API

Architectural goals

Page 12: Uber's new mobile architecture

99.99% availability of core flows

Enable global roll-back of core flows to a

guaranteed working state

Testing as a first-class citizen

Support Uber’s growth for years to come

Narrow and decouple functionality as much

as possible

Provide rails for both design and code

Consistency in engineering, consistency in

UX

Monitoring is a first-class citizen

Automatic analytics, logging, debugging, and

tracing

De-risk experimentation

Application framework with Plugin API

Make magic

Performance second to none, graceful

degradation on low-end devices and networks

Architectural goals

Page 13: Uber's new mobile architecture

Copyright Tsahi Levent-Levi

Multiplatform architectureDouble the effectiveness of teams

Page 14: Uber's new mobile architecture

Timeline

Page 15: Uber's new mobile architecture

RIB Architecture Application Framework

Dependency management

Reactive data flows

Scoping

CompartmentalizationAnalytics

UI Components

Mapping

Testability Experimentation

Plugins

Threading model

Storage

Location services

Logging

Monitoring

NetworkingRouting

Code gen

Business-logic driven

Open source

Page 16: Uber's new mobile architecture

Deep Scope HierarchiesTony Cosentini

Page 17: Uber's new mobile architecture

Dealing with State

Lots of apps have tricky asynchronous, state issues

At Uber, this compounds quite a bit

Uber’s apps have a lot of asynchronous state, from multiple data sources

150+ contributors

Page 18: Uber's new mobile architecture

Scopes?“The lifecycle in which an object exists.”

Page 19: Uber's new mobile architecture

App Scope

Page 20: Uber's new mobile architecture

RiderAppDelegate / RiderApplication {

PickupRequestManager

DestinationRefinementStream

DriverLocationMapLayer

… and a lot more stuff…

}

Page 21: Uber's new mobile architecture

What’s so bad about this?

Page 22: Uber's new mobile architecture

Stability and Code Quality Impact

Objects that live longer than

necessary are exposed to more

state they don’t need.

In Uber’s apps in particular, many of

these stateful objects observe

different streams of data. This

means these objects might get

frequent updates even when they

aren’t being used.

class DriverIsOnTheirWayToaster {private boolean isOnTripAndHasNotBeenNotified;

public DriverIsOnTheirWayToaster(TripStateStreamtripStateStream) {

tripStateStream.subscribe({ (state, driver?) ->if (state == ON_THEIR_WAY {isOnTripAndHasNotBeenNotified = true;showToast(driver!.name);

} else if (state == OFF_TRIP) {isOnTripAndHasNotBeenNotified = false;

}})

}}

Page 23: Uber's new mobile architecture

Input and dependency contracts are diluted

When objects live at app scope,

they cannot have very rigid inputs

and dependencies.

Why does this class take an

optional AuthToken if it’s really

required?

How does this hurt testing?

public class AuthenticatedNetworkRequester {private AuthToken? authToken;

public void makeRequest() {networkClient.makeRequest(authToken!)

} }

Page 24: Uber's new mobile architecture

Other Issues

While most of the classes are very simple, having lots of objects around for the

entire duration of the app’s lifecycle is not super efficient.

Classes can grow to not have a clear purpose.

Although it wasn’t as bad as some of the examples, there was no standard way

to “scope” singletons and objects to different lifecycles of the app.

Page 25: Uber's new mobile architecture

Previous Rider App Scope Hierarchy

Page 26: Uber's new mobile architecture

How do we improve this?

Page 27: Uber's new mobile architecture

Improvements

Lots of our bugs are state related.

A pattern or framework to encourage creating objects only when relevant would help here.

The view hierarchy doesn’t really line up with business logic.

We should create a hierarchy based on business logic states, which does not necessarily map to

what is on the screen.

There was no easy, consistent way to create your own scopes.

Page 28: Uber's new mobile architecture

ScopesBased on business logic

Page 29: Uber's new mobile architecture

Scopes

Root doesn’t know anything - it can’t

make any assumptions.

Root

Page 30: Uber's new mobile architecture

Scopes

LoggedIn knows that you have valid

non-null authentication credentials.

Dependencies created and provided

here can take non-null credentials

without having to make any

assumptions.

Root

LoggedIn

Page 31: Uber's new mobile architecture

Moving AuthenticatedNetworkRequester to LoggedIn Scope

public class AuthenticatedNetworkRequester {private AuthToken? authToken;

public void makeRequest() {networkClient.makeRequest(authToken!)

} }

Page 32: Uber's new mobile architecture

Moving AuthenticatedNetworkRequester to LoggedIn Scope

AuthToken is now guaranteed to be

available.

Other objects that depend on

AuthenticatedNetworkRequester

need to be in a logged in state to

use it.

If a dependency requires

AuthenticatedNetworkRequester

outside of the LoggedIn scope, it’s

now a compile error.

public class AuthenticatedNetworkRequester {private AuthToken authToken;

public void makeRequest() {networkClient.makeRequest(authToken)

} }

Page 33: Uber's new mobile architecture

Scopes

OnTrip knows that the user is logged

in and on a trip.

Dependencies created and provided

here can take non-null credentials and

all data related to a trip without having

to make any assumptions.

Root

LoggedIn

OnTrip

Page 34: Uber's new mobile architecture

Moving DriverIsOnTheirWayToaster to OnTrip Scope

class DriverIsOnTheirWayToaster {private boolean isOnTripAndHasNotBeenNotified;

public DriverIsOnTheirWayToaster(TripStateStreamtripStateStream) {

tripStateStream.subscribe({ (state, driver?) ->if (state == ON_THEIR_WAY {isOnTripAndHasNotBeenNotified = true;showToast(driver!.name);

} else if (state == OFF_TRIP) {isOnTripAndHasNotBeenNotified = false;

}})

}}

Page 35: Uber's new mobile architecture

Moving DrvierIsOnTheirWayToaster to OnTrip Scope

Now DrvierIsOnTheirWayToaster is

exposed to much less state - it’s

easier to understand, and less

prone to bugs.

class DriverIsOnTheirWayToaster {

public DriverIsOnTheirWayToaster(Driver driver) {showToast(driver.name);

}}

Page 36: Uber's new mobile architecture
Page 37: Uber's new mobile architecture

Composable single-responsibility units

Yi Wang

RIB

Page 38: Uber's new mobile architecture

Massive ViewController/Fragment

Page 39: Uber's new mobile architecture

RIBComposable Single-responsibility Units

Page 40: Uber's new mobile architecture

RIBComposable Single-responsibility Units

Page 41: Uber's new mobile architecture

RIBComposable Single-responsibility Units

Page 42: Uber's new mobile architecture

RIBComposable Single-responsibility Units

Page 43: Uber's new mobile architecture

RIBComposable Single-responsibility Units

Page 44: Uber's new mobile architecture

RIB Tree & Inter-RIB CommunicationComposing RIBs into features

Page 45: Uber's new mobile architecture

RIB Tree & Inter-RIB CommunicationComposing RIBs into features

Page 46: Uber's new mobile architecture

RIB Tree & Inter-RIB CommunicationComposing RIBs into features

Page 47: Uber's new mobile architecture

RIB Tree & Inter-RIB CommunicationComposing RIBs into features

Page 48: Uber's new mobile architecture

RIB Tree & Inter-RIB CommunicationComposing RIBs into features

Page 49: Uber's new mobile architecture

View(Controller) TreeComposing RIBs into features

Page 50: Uber's new mobile architecture

What about other architectures?

MVC

● Massive ViewController

● Locked in view tree and business tree

MVVM

● Massive ViewModel

● Locked in view tree and business tree

VIPER

● Logic separation based on view

● Locked in view tree and business tree

Page 51: Uber's new mobile architecture

What did RIBs give us?

● Rider app broken up into more than 500 RIBs

○ Many are reused with multiple parts of the tree

● All RIBs have less than 300 lines of code per class

● All business logic well unit-tested

Page 52: Uber's new mobile architecture

Brian Attwell

Plugins

Page 53: Uber's new mobile architecture

● Support Uber’s growth for years to come?

● Provide rails for both design and code

● De-risk experimentation

Architectural goalsConsider three of our architectural goals:

Page 54: Uber's new mobile architecture

Support Uber’s growth for years to come

RIBs give us code isolation

We want more code isolation

Page 55: Uber's new mobile architecture

Code Isolation Example

Page 56: Uber's new mobile architecture

Code Isolation Example

Page 57: Uber's new mobile architecture

Code Isolation Example

Page 58: Uber's new mobile architecture

Code Isolation Example

Page 59: Uber's new mobile architecture

Code Isolation Example

Page 60: Uber's new mobile architecture

Support Uber’s growth for years to come

Provide rails for both design and code?

De-risk experimentation

How do Plugins play into Architectural goals?Consider three of our architectural goals:

Page 61: Uber's new mobile architecture

Home Screen

Page 62: Uber's new mobile architecture

Interface:Router<? extends MapComponent> { }

Example:NearbyVehiclesMapLayer

PresentLocationMapLayerCurbsidePickupMapLayerDestinationRefinementMapLayer

Home Screen

Page 63: Uber's new mobile architecture

for (HomeMapLayerPlugin plugin: plugins) {attachChild(plugin.buildRib(component));

}

Home Screen

Page 64: Uber's new mobile architecture

Interface:ViewRouter<?> { }

Example:SnapchatCardRouter

RatingCardRouterTransitConnectionRouterEatsCardRouterPaymentsCardRouter

Page 65: Uber's new mobile architecture

Interface:interface LocationRowProvider {

Observable<SearchResult[]> query(input); }

interface SearchResult {String tag();Router buildRouter(parent);

}

Example:CalendarResultsPlugin

SavedLocationsPluginGeoSearchResultsPluginFriendsLocationPlugin

Page 66: Uber's new mobile architecture

Observable.combineLatest(plugins).subscribe(BindLocationRowsConsumer)

Page 67: Uber's new mobile architecture

@Override

protected void didBecomeActive() {

for (Work worker : mainScopedPluginManager.get()) {

work.start();

}

}

Viewless plugins

Page 68: Uber's new mobile architecture

Interface:interface MenuPlugin {

MenuCategory menuCategory();Router buildRouter(MenuPluginComponent)

}

enum MenuCategory { TOP, BOTTOM }

Example:PaymentMenuPluginFreeRidesPluginHelpPlugin

Page 69: Uber's new mobile architecture

Almost all features in the app can be

written as code that plugs into the

core of the app.

Page 70: Uber's new mobile architecture

80% of Rider’s Application Layer written as Plugins

Page 71: Uber's new mobile architecture

New plugin points and changes to core get

extra code reviewers added automatically.

Page 72: Uber's new mobile architecture

Support Uber’s growth for years to come

Provide rails for both design and code

De-risk experimentation?

How do Plugins play into Architectural goals?Consider three of our architectural goals:

Page 73: Uber's new mobile architecture

Derisking Experimentation

Roll out all new features as plugins

Every plugin is initially A/B tested

Every plugin can be disabled from our servers

UI tests ensure the app is still functional when all plugins disabled

Page 74: Uber's new mobile architecture

De-risking Experimentation

Page 75: Uber's new mobile architecture

Engineers want to reuse existing plugin points and now know where the

build new features

We’ve prevented six outages in production by disabling plugins

Statically ensured code isolation between the architecturally significant core

of the app and the app’s features

ResultsFrom using plugins

Page 76: Uber's new mobile architecture

Development Velocity

Able to sustain 500 diffs/week per platform

Diffs landed per week doubled after finishing the four month rewrite

Crash Free Rate

Immediately after releasing the new app, crash rate was better than the old app

iOS crash free free rate of 99.99% and climbing

Android crash free rate of 99.9% and climbing

Performance

App starts 50% faster

Developer Happiness

78.5 developer NPS score improvement

ResultsFrom the new architecture

Page 77: Uber's new mobile architecture

Thank you

Proprietary and confidential © 2016 Uber Technologies, Inc. All rights reserved. No part of this document may be

reproduced or utilized in any form or by any means, electronic or mechanical, including photocopying, recording, or by any

information storage or retrieval systems, without permission in writing from Uber. This document is intended only for the use

of the individual or entity to whom it is addressed and contains information that is privileged, confidential or otherwise

exempt from disclosure under applicable law. All recipients of this document are notified that the information contained

herein includes proprietary and confidential information of Uber, and recipient may not make use of, disseminate, or in any

way disclose this document or any of the enclosed information to any person other than employees of addressee to the

extent necessary for consultations with authorized personnel of Uber.

eng.uber.comgithub.com/uber