这篇文章是本系列的第九篇系列报道了优步的移动工程团队如何开发了代号为Carbon的最新版司机应用程序,这是我们拼车业务的核心组件。除了其他新功能外,这款应用还能让我们超过300万的司机合作伙伴找到车费、指路和追踪他们的收入。2017年,我们结合司机合作伙伴的反馈开始设计新应用程序,并于2018年9月开始投入生产。
我们的司机应用程序是优步和司机合作伙伴之间最重要的日常沟通工具。该应用程序向司机展示他们可以在哪里接下一个乘客,把乘客送到他们想去的地方的最有效路线,以及他们每次旅行能赚多少钱。
在许多其他新功能中,我们最新版本的司机应用程序在最后一点上有了很大的改进,即我们所说的实时收入跟踪(Real-time Earnings Tracker)。实时收入跟踪是一种向司机展示他们每次旅行、每天和每周赚了多少钱以及其他功能的方法。依靠我们的司机合作伙伴的直接反馈,我们设计了这个功能,不仅显示他们每次驾驶积累了多少钱,还提供了他们在平台上的收入的完整图景。
实时收益跟踪UI包括一系列卡片,覆盖在应用程序上的元素,显示诸如最近的旅行结果和每日收益等内容。司机可以从三种不同的模式中进行选择,如下图1所示,这让他们可以实时查看自己的收入,回顾之前的旅行和驾驶总结,并在平台上庆祝关键时刻。
通过我们的包容性设计过程,我们最初将该应用作为最小可行性产品(MVP)发布,并使用该版本收集司机和合作伙伴的反馈。在这一阶段中,我们为实时收入追踪器添加了所需的功能,包括隐私模式(Privacy Mode),它可以让司机在应用程序的主屏幕上隐藏他们的实时收入,更好的滑动功能,以及优雅的错误处理,如下图2所示。实时收益追踪的成功可以从以下事实来衡量:86%的司机在接送乘客时使用它,我们看到每日汇总的流量显著增加。
虽然实时收入追踪系统中显示的大多数信息都是基于司机的活动自动显示的,但我们也与Uber的其他团队合作,如激励团队和新司机保障团队,以允许为我们的司机合作伙伴提供更多的互动和应用内支持。对于这些团队,我们收集了他们的反馈,并为添加新卡片制定了跨产品、设计和工程的集成指南。
实时收益系统的挑战
在我们的驱动程序中显示实时收益需要与许多后端服务交互,包括行程请求、行程完成、行程存储和收益处理。虽然我们重新设计了UI,但我们仍然需要在应用中包含多个接触点,如上一次旅行卡、每日旅行卡、旅行历史和收入主页。
在设计实时收益追踪器之前,我们确定了在我们的驱动程序的上一个版本中实时收益显示的三个可能的挑战:数据延迟和可靠性、数据一致性和信任度以及产品相关性,概述如下:
- 数据时延和可靠性:之前的司机应用程序在主地图屏幕上以卡片形式显示实时收益。该应用程序设计为每次行程后立即更新,因此必须从后端实时提取数据。这些频繁的拖拽会导致服务器负载问题,有时会导致收益显示系统中断。
- 数据一致性:我们的收益显示数据来自多个不同的来源和服务,这些数据并不是同时更新的。应用程序中的一个触点可能显示过时的数据,而另一个则显示更新的数据,导致与司机合作伙伴沟通的信息缺乏一致性。为了为司机合作伙伴提供更好的用户体验,我们需要这些输出在整个应用程序中对齐。
- 产品相关:我们的用户研究显示雷竞技是骗人的,司机和合作伙伴认为收入和激励高度相关。然而,之前的应用将这两个显示分离开来,在屏幕右上方的小按钮中显示收益卡和奖励,如下图3所示:
实时收益跟踪框架
考虑到我们之前在之前版本的司机应用程序中构建收入显示的经验,并见证了司机-合作伙伴实时跟踪平台的价值,我们在设计实时收入跟踪背后的框架时设定了以下目标:
- 进行数据推,而不是数据拉一流的公民,减少服务器请求。
- 让数据一致性成为一流公民。
- 设计可伸缩和可扩展的体系结构,以支持新的服务和卡片集成。
为了帮助实现这些设计目标,我们在一些现有的Uber平台、基础设施和架构上构建了实时跟踪器框架。
与后端接口
现有的实时api网关作为我们的应用程序和后端服务之间的接口。我们利用这项服务作为追踪卡的唯一真相来源数据模型需要通过Uber的推送管道或HTTP拉请求与框架集成,如下面的图4所示。
使用Realtime-API Gateway作为真相的来源大大简化了新的后端集成到框架中。
以下是数据模型的片段及其解释:
| 枚举CardType{ 浏览=1, 公告=2, BROWSE_AND_BULLETIN =3., 不知道=4 } (rtapi.mobile。unknownCaseFallback =”未知的”) struct TrackerCard { 1要求:字符串cardID, 2要求:双优先级, 3.要求:保龄球,是否是可用的。 4:可选的TrackerCardPayload有效载荷, 5:可选CardType, 6: optional . timestampinsec expiresAt, 7: optional . timestampinsec lastUpdatedAt, 8:可选的OutageState, 9:可选保龄球shouldForceSwitchStatusMode, 10:可选双statusModePriority } // cardID -在Tracker框架中识别卡片的唯一真相源,每次引入一个新的Tracker卡片时,都需要一个新的cardID //优先级-对于实时收益跟踪浏览卡的移动排名和显示,每次应用程序从服务器得到响应,移动排名系统执行排名并更新实时收益跟踪浏览卡的显示顺序 // payload -填充应用UI的数据应该存在 // cardType -区分实时收益跟踪浏览卡和实时收益跟踪公告卡,以不同的实时收益跟踪模式显示 // expiresAt—当实时收益跟踪卡需要失效时,后端服务需要设置此字段以使特定的卡失效。后端服务不应该发送push到过期卡片,因为如果在同一过期时间收到太多调用,它可能会出现加载问题。 // lastUpdatedAt -每个服务在填充数据时需要设置该字段,当后端服务处于中断状态,而卡片数据缓存在移动端时显示该字段 |
集成后端服务
为了确保我们的数据模型尽可能准确,集成到这个框架中的每个后端服务都需要导入Real-time Earnings追踪卡实时api库中的数据模型。我们还强烈建议其他团队引入的特性与之集成优步的实时更新推送管道。
为了使在驱动程序中添加新卡具有可扩展性和可扩展性,集成新卡需要在其中添加新字段TrackerCardPayload是框架的数据有效负载模式,如下面的代码片段所示,以及设计特定的有效载荷数据模型(例如,TrackerRecentTripsCard)用于在驱动程序的UI中填充数据:
| TrackerCardPayload { 可选TrackerRecentTripsCard TrackerRecentTripsCard 可选TrackerDailyEarningsCard TrackerDailyEarningsCard 可选TrackerWeeklyEarningsCard TrackerWeeklyEarningsCard 可选TrackerDxGyProgressCard TrackerDxGyProgressCard 可选TrackerDxGyCompletionCard TrackerDxGyCompletionCard //未来的卡片类型将包含在这里 } TrackerRecentTripsCard { 要求字符串标题 可选字符串formattedTotal 可选字符串formattedRequestAt 可选字符串vehicleStatusDescription 可选字符串callToAction 可选字符串bulletinTitle 可选字符串lastTripUuid } |
在大多数情况下,有效负载应该来自后端,并由移动UI直接使用。
用rib构建实时收益跟踪器
我们构建新的驱动程序使用肋骨优步的开源跨平台移动架构。事实证明,这种体系结构对于实时收益跟踪器的三种不同模式(状态、浏览和公告)所需的复杂转换非常有用。rib架构让我们可以将实时收益跟踪器扩展,这样我们就可以在未来添加更多的显示卡。
Real-time Earnings Tracker rib树包括四个rib和两个插件,描述如下:
- TrackerEntry肋:该RIB表示实时收益跟踪器中的状态模式,是Active的子RIB。当驾驶伙伴轻按或接收到公告模式触发时,Tracker RIB将作为TrackerEntry的全屏子程序附加。
- 追踪肋:这个RIB用作BrowseTracker和BulletinTracker RIB的容器。
- BrowseTracker肋:这个RIB表示实时收益跟踪器的浏览模式,是应用程序UI中的浏览卡的容器,如每日摘要、每周摘要和最后一次旅行。
- BulletinTracker肋:该RIB代表实时收益跟踪器的公告模式,在应用程序中显示公告卡,显示诸如最后一次行程处理的时间和司机的各种里程碑。它处理触发特殊公告的推送事件。
- BrowseCardPlugin BulletinCardPlugin:任何卡显示在实时收益跟踪是一个插件,所以卡可以关闭而不影响核心功能。具体来说,浏览模式集成将基于插件的浏览卡(如每周摘要卡和每日摘要卡)连接到核心功能中。公告卡,如First Trip和uberPOOL Trips解锁里程碑,桥接基于插件的公告卡到公告模式集成的核心功能。
前端核心业务逻辑
前端的核心业务逻辑发生在一个名为TrackerDataManager的组件中。该组件从不同的上游来源获取数据流,例如收益和激励,使用聚合、排名和验证等操作操作数据,然后根据它们将它们发送到不同的实时收益跟踪模式流cardType编号,如下图6所示:
每个数据流输入到TrackerDataManager包含实时列表收益追踪卡。为了保证整个应用程序的数据一致性,每个集成后端服务都需要有自己的数据管理器来管理其实时收益跟踪卡。例如,RealtimeEarningsManager管理与收入相关的卡片,包括上次旅行、每日总结和每周总结。RealtimeIncentiveManager处理奖励相关的卡片,包括任务跟踪。
每个流的数据管理器需要处理拉和推逻辑,并且是自包含的,以保证数据的一致性和最新的。以收益为例,RealtimeEarningsManager将被创建为活动范围中的一个单例,并将实时earningsstream作为依赖项传递给TrackerDataManager。
遵循作用域隔离的概念,我们只希望将最少的数据传递到正确的作用域。为此,我们将TrackerDataManager的输出分离为三个数据流,代表三种实时收益跟踪模式。每个流将被传递给相关的RIB消费者来填充数据:
- TrackerStatusModeStream
- TrackerBrowseModeStream
- TrackerBulletinModeStream
| / / / @CreateMock 公共协议TrackerStatusModeListener:类{ 函数更新(设置selectedItem: BrowseCardContext) } / / / @CreateMock 公共协议TrackerStatusModeStream:类{ var设置selectedItem:可观测的<BrowseTrackerRankingItem> {得到} varhasSortedValidItems:保龄球{得到} vargetBulletinCardPush:可观测的<TrackerCard> {得到} varprivacyStatus:可观测的<TrackerPrivacyStatus> {得到} } / / / @CreateMock 公共协议TrackerBrowseModeStream:类{ vardailyDetails:可观测的< (EarningsDetails] > {得到} varearningsError:可观测的<错误> {?得到} varearningsTrackerCardsWrapper:可观测的< (EarningsModelWrapper<TrackerCard>] > {得到} varincentivesErrorByType:可观测的< (IncentiveCardID:错误] > {得到} varprivacyStatus:可观测的<TrackerPrivacyStatus> {得到} varsortedValidItems:(BrowseTrackerRankingItem) {得到} vartrackerCards:可观测的< (TrackerCard] > {得到} 函数更新(privacyStatus: TrackerPrivacyStatus) } / / / @CreateMock 公共协议TrackerBulletinModeStream:类{ varbulletinCard:TrackerCard?{得到} } |
平台的改进
在将激励机制集成到我们的实时收益跟踪器之后,我们从激励机制团队收集了关于现有实现的有用反馈,比如要求更好的集成完整性和更干净的API。我们能够进一步提高集成效率,完善平台,使新产品和新功能的集成更快更安全:
- 使用枚举类型在添加新卡时确保编译时安全,保证高集成完整性。
- 改进代码隔离和API设计,使添加新卡不会影响核心功能。
- 提供基本的UI模板和基本卡片rib,完全删除样板UI和业务逻辑代码,以提高开发人员的工作效率。
实时收益追踪的未来
我们平台上的各个团队都采用了实时收益追踪系统,以提高收益透明度和司机与合作伙伴的参与度。到2018年下半年,实时收益追踪系统在其三种不同模式中集成了24项功能:
- 状态模式:上次行程,每日总结,连续行程进度,任务进度,新司机保证进度,忠诚进度,收入误差,奖励误差,新司机保证进度误差,忠诚进度误差。
- 浏览模式:最后一次行程,每日总结,连续行程进度,任务进度,新司机保证进度,忠诚进度,收益错误,奖励错误,新司机保证进度错误,忠诚进度错误。
- 通讯模式:最后一趟完成,连续一趟完成,任务完成,新驱动保证完成。
最近,我们将Uber Pro程序集成到实时收益跟踪程序中,以帮助庆祝我们的司机合作伙伴的成就,如下面的图7所示。
2019年,我们计划在实时收益跟踪中引入更多新功能,以进一步改善我们平台上的司机-合作伙伴体验。
优步司机应用程序系列文章的索引
- 为什么我们决定重写优步的司机应用
- 在rib中构建Uber的新司机应用程序
- 优步新司机应用如何克服网络延迟
- Uber Eats的现金支付规模
- 如何在不危及整个业务的情况下发布应用重写
- 为司机建立可扩展和可靠的地图接口
- 工程优步Beacon:匹配车手和司机在24位RGB颜色
- 为驱动首选项设计一个安全的、可伸缩的、服务器驱动的平台
- 在我们的新驱动程序中建立实时收益
- 活动/服务作为一种依赖:反思Uber新司机应用的Android架构
致谢
我们要感谢Nico Hinderling (iOS工程师)、Robert Khoury(后端工程师)、Roger Ho (Android工程师)和Shuang Yin (Android工程师)在Real-time Earnings Tracker平台和应用中所做的工作。
对开发每天被数百万人使用的移动应用程序感兴趣吗?考虑加入我们的团队安卓或iOS工程师!






