架构安全,可扩展和服务器驱动的平台,用于带肋骨的驱动程序偏好

0.
架构安全,可扩展和服务器驱动的平台,用于带肋骨的驱动程序偏好

这篇文章是一个八分之一系列涵盖优步的移动工程团队如何开发出最新版本的我们的驱动程序应用程序,代号为碳,碳,是我们执教业务的核心组成部分。在其他新功能之外,该应用程序让我们的人口超过300万司机合作伙伴查找票价,获得指示并跟踪其收入。我们在2017年开始与我们的司机伙伴的反馈结合设计新应用程序,并于2018年9月开始向其推出生产。

优步经营的600多个城市中的每一个司机合作伙伴面临独特的城市特色。例如,旧金山,我们公司总部设有一个由城市响起的大湾,桥梁数量有限。巴黎的巨大城市地区每天都会看到它中心的大量游客。同样,城市与孟买,雅典和里约热内卢一样多样,都具有独特的特征,可以使他们达到挑战。鉴于这些城市风景的多样性,我们希望让我们的全球市场对司机合作伙伴定制他们的平台的经验尽可能多,让他们能够将超级融入他们的生活中。

我们通过向驱动程序应用程序添加一些简单的偏好来开始努力,例如过滤调度,乘坐或食品交付请求的能力,从我们的平台到仅限Uberx或Uber,或者是否接受市场中的现金旅行在哪里可用。Furthering this work, we added a feature to let driver-partners specify areas they would like to accept rides in based on their schedule and geographic convenience (for instance, a driver-partner might want to be back in their neighborhood by 6 p.m. to pick up their child from soccer practice, or need to be downtown by 8:30 a.m. for work).

驱动程序首选项应用屏幕
图1:我们新驱动程序应用程序中的首选项集线器让驱动程序合作伙伴自定义其体验,为所有用户创造更大程度的满意度。

为了最好地了解全球用户的需求,我们依靠我们城市运营和安全团队等团体,这对当地条件进行了贴心了解。利用他们的见解,我们为我们的新驱动程序应用程序的偏好中心构建了,使这些团队能够轻松地添加对其城市用户有意义的驱动程序应用程序首选项。通过为驾驶员提供更多的偏好来选择,这些团队可以为其城市的司机伙伴创造更安全和更方便的体验。

为了实现偏好中心的快速开发和安全的实验,我们将平台作为一组可重复使用的肋骨具有由我们的后端系统完全驱动的接口和业务逻辑的组件。优步开源移动架构的插件结构允许本地修改不会威胁核心功能,防止冲突和依赖性问题。随着不同的特点团队,RIBS的灵活性,易于采用的插件设计出现了更多机会,通过允许团队借助支持后端服务并使用现有组件来提供新的偏好来降低移动采用成本。

接口小部件

在Preferences Hub中为优步的团队提供一个标准的界面小部件库,让他们能够快速响应城市运营团队关于新的偏好要求的请求。创建这些小部件的目标是使它们易于实现,并且足够通用性,可以应用于广泛的用例。

驱动程序首选项应用程序屏幕与代码片段
图2:一个切换开关可以让团队实现简单的开/关选项,司机可以在应用中选择。

驱动程序首选项应用程序屏幕与代码片段
图3:多选择窗口小部件允许团队实现更复杂的偏好,例如此示例,允许驱动程序合作伙伴选择他们收到的乘坐请求的目的地。

图2和3,以上,展示了两个可重用的接口组件:切换窗口小部件(例如,启用/禁用CASM TRIPS),以及多选择窗口小部件(例如,选择首选的下拉区域)。通过这种方式,移动应用程序采用后端驱动的方法来显示每个首选项,并在驾驶员命中保存之前保持选项选项卡。此时,该应用程序将首选项发送到后端,调整此特定用户的调度偏好。

组件图
图4:虽然我们为明显的用例包括了预构建的小部件,但我们设计了Preferences Hub,以允许定制的接口组件来支持未来的需求。

开箱即用的通用小部件可以用于绝大多数首选项,但是preferences Hub体系结构背后的关键一点是,它是可伸缩和可定制的。我们无法预测未来的需求,所以我们还添加了对构建定制组件的支持,这些组件看起来可能与我们目前提供的小部件非常不同。下面的图5显示了一个定制的多选界面组件,用于提高选择行程类型首选项的可用性

驱动程序首选项应用屏幕
图5:此自定义接口组件可增强选择跳闸类型的可用性。类似于我们的标准小部件,它将其集成到应用程序并由后端供电。

构建一个安全可扩展的平台

将我们的应用的这一领域开放给远程团队,让他们更深入地了解当地情况是很好的,但现在我们要考虑另一个问题:他们应该把代码放在哪里?想象一下最简单的场景,我们有一个类负责所有的业务和路由逻辑,由后端控制,如下所示:

如果偏好。id = =“trip_type_pref”{
//跳闸类型的自定义小部件呈现代码
//跳闸类型的自定义窗口小部件业务逻辑

}其他的如果偏好。id = =“dropoff_areas_pref”{
//堕落区域的自定义小部件呈现代码
//辍学区域的自定义小部件业务逻辑

}其他的{
//渲染通用的多个选择小部件
//通用窗口小部件业务逻辑

}

此方法不可缩放,每次添加新组件时,该类变大。持续的变化也承担了宣传错误的风险。当您的平台被世界各地的数百万人使用时,一个简单的错误可能会产生严重的后果

为了避免if / eles噩梦和臃肿的文件,但为他人提供安全的开发工作流程,以便插入我们的偏好平台,我们利用优步的开源肋骨架构及其插入框架。

与肋骨的代码隔离

我们设计了肋骨来鼓励代码隔离,让每个团队、特性或组件都有自己的工作区。例如,上面显示的定制的旅行类型偏好组件让司机选择是接受乘客还是送餐,或者两者都接受,不需要与任何其他组件交互。它被隔离在自己的世界中,减少了对冲突或潜在bug泄漏到其他组件的担心。

下面的代码示例展示了如何在肋骨中实现组件。正如你所看到的,它与类似的组件隔离:

如果偏好。id = =“trip_type_pref”{
triptypeprefrouter = triptypeprefbuilder.build()
Router.AttachChildPrefrouter(Triptypeprefrouter)
}其他的如果偏好。id = =“dropoff_areas_pref”{
dropfofareasprefrouter = dropoffareasprefbuilder.build()
Router.AttachChildPrefrouter(DropFofareasPrefRouter)
}其他的{
genericMultiSelectRouter = genericMultiSelectBuilder.build ()
router.attachChildPrefRouter (genericMultiSelectRouter)
}

在Ribs之前,我们的移动架构中的每个新组件处理了其所有渲染逻辑并在同一类中配置某些业务逻辑。含有肋骨,我们已经强制了渲染和业务逻辑的隔离,完全达到每个组件的自己的肋骨,为更清晰的代码制作。但是,我们仍然存在开发人员的问题,每当需要添加新组件时,我们仍然会对偏好中心的核心代码进行更改,而IF / ELSE NAVERMARE仍然存在。为了最大限度地减少偏好中心平台内部代码的更改,我们利用插件。

安全与插件

首选项集线器使用插件来制作有关要使用的组件的运行时决定。它通过强制开发人员来创建与我们的组件创建插件来解决上述问题首选项普朗因点如下图6所示:

肋骨树图
图6:PreferenceShubRib包含一个插件点,允许开发人员添加不干扰Code Core.e代码的单个应用程序组件。

从更高的级别缩小并查看应用程序的肋骨架构,如图7所示,我们可以看到首选项集线器本身是另一个肋骨内的另一个插件点的插件。换句话说,首选项普朗因点是UBER应用程序中众多嵌套插件之一,帮助我们降低代码复杂性,同时保持应用程序可扩展。

肋骨树图
图7:驱动程序应用程序的此肋条图显示了我们如何嵌套插件点,允许多个团队为不干扰他人干扰的应用程序构建功能。

记住上面的IF / else陈述吗?使用Ribs插件架构,我们的代码现在如下所示:

plugin = preferencespluginpoint.createplugin(用于:偏好)
路由器= plugin.build ()
router.attachChildPrefRouter(路由器)

虽然这段代码似乎非常简单,但我们仍然需要确定在使用时为特定偏好构建的组件createplugin.函数。我们通过强制执行每个插件来实现这一目标,以符合公开的共享协议可象当地函数。让我们使用dropoffareapreferences班级作为示例:

班级DropoffAreasPrefPluginpluginInterface.{
初始化(依赖性:首选项代表依赖性){
极好的.init(pluginswitch:Dropoffareaspref.) { 语境
返回DropoffAreasPreferenceComponentBuilder(依赖:依赖)
}
}
覆盖fun可象当地为了偏好:偏好){
返回偏好。id = =“dropoff_areas”&& preference.type ==。多种选择
}
}

后端的偏好响应将为我们提供ID和类型,所以Dropoffareaprefplugin.我们定义了这一点可象当地功能对于这些特定描述符有效。

让我们现在回溯,看看我们使用肋骨完成的内容来实现偏好中心:

  1. 我们强制执行代码隔离,以便在不了解其他人的情况下,可以建立组件,大大减少了一个泄漏到另一个错误的错误的机会。
  2. 我们消除了对偏好中心核心代码进行任何更改的必要性。要添加新组件,我们只需将其作为一个数组项添加到插件点,提供编译时间安全。

虽然这解决了两部分挑战,但我们仍然有一个问题来解决。我们如何在引入新组件时维护整个应用程序的持续可靠性和性能?解决方案:肋骨框架的另一个关键部分,插件交换机。此组件显示为枚举值Dropoffareaspref.在上面的代码示例中,需要初始化插件。开发人员指定的枚举值将映射到字符串值,并且必须在我们的中明确启用实验平台去工作。

在下面的示例代码中,我们使用我们的实验平台启用插件,这使我们可以将功能部署到用户的子集并获得关于其疗效的分析:

“实验”:[
“plugin_switch_dropoff_areas_preferences”:true
]

在运行时和作为的一部分createplugin.呼叫,我们会核对实验平台,甚至在核对之前可象当地函数以确定是否启用了特定插件,并应创建。如果我们观察到应用程序崩溃,这会让我们禁用特定插件。当偏好中心呼叫时createplugin.为此,我们不再返回崩溃的组件,返回下一个合格和适用的组件,如下图8所示。

应用程序流程图
图8:我们的插件架构允许我们启用或禁用组件,如果新组件无法令人满意运行,则会启用或禁用组件非常有用的功能。

将所有这一切放在一起,我们现在有一个偏好的集线器,是后端驱动的,可自定义,安全,并准备支持其他团队的驱动程序首选项。

Preferences Hub的理念和架构设计自此影响了优步司机应用程序中的几个中心风格的功能。例如,促销中心,我们的司机合作伙伴可以在这里查看各种即将到来的促销活动,结合了引入新推广类型时不需要更改核心应用代码的好处,以及在需要时实现定制界面组件和逻辑的灵活性。

在更高的层次上,我们构建Preferences Hub的方法可以作为一个例子,说明整个行业的产品团队如何考虑为最佳的灵活性和易用性设计他们的平台。与我们的驱动合作伙伴一样,产品需求也在不断变化。未来的产品需求通常是不确定的,因此团队必须在开发时考虑敏捷性、开放性和实验性。

向前进

就像我们的驾驶员应用程序的其他功能一样,总有改进的地方,我们会继续听取驾驶员合作伙伴的意见,以改进Preferences Hub。

例如,在将来,我们计划为每个偏好提高接口组件,为超链接和富文本添加支持以提供更多上下文。例如,如果驱动程序无法选择特定的首选项,我们希望能够包括弹出文本来告诉它们为什么,并且可能提供用于注册新产品或功能的链接。

Uber驱动程序应用程序系列中的文章索引

  1. 为什么我们决定重写优步司机应用
  2. 在肋骨中构建优步的新司机应用
  3. 优步新司机应用如何克服网络滞后
  4. 在优步缩放现金支付
  5. 如何运送应用程序重写,而不会冒险整个业务
  6. 为驱动程序构建可扩展和可靠的地图界面
  7. 工程优步灯塔:匹配乘客和司机在24位RGB颜色
  8. 为驱动程序首选项构建一个安全的、可伸缩的、服务器驱动的平台
  9. 将实时收益跟踪器建立在Uber的新驱动程序应用程序中
  10. 活动/服务作为依赖项:在优步新驱动程序应用程序中重新思考Android体系结构

有兴趣每天开发数百万人使用的移动应用程序吗?考虑加入我们的团队作为一个安卓或者iOS.工程师!

横幅照片作者Jeshoots.com.Unsplash

注释

没有帖子展示