ActionCard 模式将应用程序屏幕 UI、导航(路由)逻辑和其他应用程序逻辑简化为简单、分离的元素。UI 元素称为卡片,关联的可重用逻辑元素称为操作。卡片和操作一起配置以创建应用程序屏幕和功能。每个屏幕都由服务器驱动的卡片数据模型提供支持。
此处描述的 ActionCard 模式实施是我们的团队利用优步工程方面的知识以及我们自己的大量试验和错误的结果。其结果是一种模式,使我们能够在多个屏幕和应用程序中快速推出新功能,并专注于快速迭代。
ActionCard 模式使我们能够降低复杂性并消除冗余。我们希望它可能对其他想要快速前进的团队有所帮助。
在 Uber 组建专门的会员工程团队之前,功能(Eats Pass 和 Uber Pass)由多个团队实施,这些团队也专注于其他多种产品。当我们发现一个重要的机会,可以通过提供更丰富的会员体验来为超过 1 亿的月度活跃用户提升 Uber 体验时,这一切都发生了变化。
我们新的专门会员团队的目标是将会员功能的相对简单的实现(仅由几个屏幕组成)扩展为一组丰富的功能,这些功能将集成到 Eats、Rides 和 Postmates 应用程序的用户体验中.
图 1:旧会员功能屏幕
图 2:未来的会员功能屏幕
当我们审查上面屏幕中的逻辑和布局并将它们与我们 12 个月的时间表进行比较时,我们的主要挑战立即很明显是构建许多具有独特布局的不同屏幕,并支持这些屏幕上的不同行为。
移动工程师已经花费太多精力编写新布局和集成业务逻辑。每个屏幕都需要一个新的实现。构建供用户在一系列屏幕之间导航的流程需要每个流程的独特实施。
我们的移动团队永远无法在我们计划的有限时间内交付所有这些,我们当然也没有时间进行 A/B 测试和迭代。我们有一个积极的路线图来增强 Uber 体验的几乎每个部分,目标是达到 1000 万会员。
我们只有 12 个月的时间来转变 Eats 和 Rides 应用程序的会员体验并实现这一目标。实现这一点的唯一方法是找到一种更有效的方法来提供所有这些功能。
我们着手看看是否可以通过执行以下操作将可重用性单位减少到一张卡片和一个动作:
卡片是具有单一用途的单个 UI 元素。这可以像显示图像或富文本一样基本。它们由 BaseUI 支持,还包含复杂的视图,如列表视图或消息视图。
所有卡模型都遵循相同的简单结构。它们包含卡片的 viewModel,通常会扩充单个已经存在的标准 UI 视图。以及当用户与卡片交互或点击卡片时可以执行的可选关联操作(某些卡片支持多个操作)。
示例卡模型:
操作是当用户点击按钮或与 UI 交互时发生的事情。例如,导航到新屏幕、进行购买或更新首选项。
图 3:动作模型
图 4:ActionCard 屏幕
图 5:ActionCard 屏幕数据/布局结构
在内部,为了构建 CardScreen 配置,我们使用称为 DisplayConfig 的后端 GUI 工具。一旦在后端对动作和卡片模型进行编码,就可以使用 DisplayConfig 轻松地将它们排列或添加到新屏幕(我们实现 DisplayConfig 的更多细节是另一篇文章的主题)。
图 6:用于创建 16 个屏幕的完整卡片集
图 7:从卡片构建的会员屏幕
我们充分利用了 Uber 各个工程团队的综合经验。我们将我们的知识应用于解决基于真实用例的问题,并注重简单性。
其结果是 ActionCard 模式的强大实现,使我们能够支持跨多个应用程序和超过上述 16 个屏幕的强大功能集。使用 ActionCard 模式,我们能够启动复杂的流程,执行各种操作,并允许用户根据选择进行导航。
我们改进了这种模式,将可重复使用的元素从整个屏幕减少到单个卡片或操作。我们最大限度地 遵循了DRY原则,避免了编写无数行冗余代码。
ActionCard 模式从根本上来说很简单。它涉及呈现卡片屏幕和处理操作。卡片模型使 CardViewable 膨胀,动作模型提供 ActionFlow 所需的数据。ActionFlows 处理动作的执行,无论是启动新屏幕还是执行 API 并使用响应更新状态。
ActionFlow 使用包含卡片模型和相关元数据的 CardScreenPresentation 对象更新 CardScreenPresentation。CardViewableProvider 从卡片模型中生成 CardViewable,并将它们返回给 CardScreenPresenter,CardScreenPresenter 会呈现它们。
图 8:渲染卡片屏幕的数据流
包含显示卡片屏幕所需的所有卡片(以及相关操作)和元数据的模型。分析事件将使用元数据将点击、展示和其他事件与此特定的卡片屏幕配置相关联。
这是用于渲染所有卡片屏幕的渲染器。我们当前的渲染器实现有两个 Ccrds 列表:一个从上向下滚动(主卡),另一个固定在底部并向上堆叠(底部固定卡)。以后可能需要多个不同的presenter;然而,这个单一的 CardScreenPresenter(如下)目前足以满足我们所有的用例。
图 9:卡片屏幕呈现器
每个卡片模型都包含呈现 CardViewable 所需的数据。它们还包含相关动作的动作模型。
CardViewable 是卡片的实际可渲染视图。
图 10:MessageCard 示例
用于从卡片模型构建 CardViewable 的工厂。
每个动作模型都有执行动作所需的数据。操作可以将用户导航到另一个屏幕,如 openHelp 或 openCheckout,或者是改变用户状态的专门操作,如 makePurchase 或 changeDefaultPaymentMethod。
ActionFlow 使用来自动作模型的数据来执行动作。ActionFlows 可以启动新屏幕或可以处理其他类型的操作,包括发出网络请求以进行购买。
ActionFlowProvider 为特定操作提供 ActionFlow。专门的处理程序处理针对特定上下文的操作,例如只能在特定应用程序上或在指定上下文中起作用的操作。
图 11:进行购买
图 12:维护一小组易于重用的简单卡片
制作简单的卡片,然后将它们堆叠起来以创建更复杂的布局。这最终导致卡片数量减少。它大大减少了必须在 CardViewable 中维护的布局数量。它还实际上会增加可以创建的新屏幕的数量,而无需制作更多卡片。从简单的 RichTextCard 元素和 ImageCard 开始,然后根据需要添加基本的 UI 组件。为每张卡使用通用名称,这样当卡可用于多种不同用途时,您就不会描述特定的业务功能。
保持布局简单。在每张卡片中管理多个布局会使卡片的更改变慢,因为每次进行小的更改时都必须测试所有其他布局。我们的许多基本 UI 组件在内部处理各种布局,因此一张卡片可以支持相当多的布局,而无需向 CardViewable 本身添加任何布局逻辑。
CardViewables 可以根据卡片模型中可用的元素调整其呈现方式,但尽可能避免在布局逻辑中使用 if/else 逻辑或更糟糕的 switch 语句。如果事情变得复杂,只需制作一张新卡。从长远来看,这将使一切变得更加简单。
最好的布局是已经在您的应用程序的许多地方使用过的布局。尽可能在 CardViewable 中嵌入标准 UI 组件。
使用具有可配置高度和可选背景颜色的间隔卡来定义卡之间的空间。这消除了任何特殊的间距逻辑。
ActionFlow 是卡片框架中的操作处理程序。一旦编写完成,ActionFlow 就可以处理任何屏幕上的操作。ActionFlows 可以启动屏幕、更新屏幕状态以及进行购买或取消订阅等操作。虽然可以在其他地方添加操作处理,但最好使用 ActionFlow 处理所有操作。
任何操作都应该能够由任何 UI 元素处理。
CompletionAction 是在另一个 ActionFlow 完成后执行的普通操作。CompletionActions 是 SuccessActions 或 FailureActions,它们通常会更新屏幕以显示新状态或在完成购买或取消订阅等操作后将用户导航到另一个位置。任何动作都可以有一个 CompletionAction。CompletionActions 链接在一起,可以在不添加额外代码的情况下引入复杂的流程和动态行为。
经常用作 CompletionActions 的动作:
分析应完全集成到您的 ActionCard 实施中,以便默认捕获每一次展示、点击和用户旅程。将分析事件内置到框架中的一个好处是它们几乎总是准确和完整的,即使在测试新功能时您也可以依赖经过良好测试的分析逻辑。
水合屏幕的端点必须提供一个唯一标识符,该标识符可用于识别来自该特定卡片屏幕配置的印象和点击事件。
图 13:动态流程
上面的调查由RadioOptionGroupCard组成。无线电选项一起由一张卡片呈现,该卡片处理用户选择的动态更新状态。
Continue 按钮开始禁用,并在用户做出初始选择后变为启用。UpdateCards 操作通过更新按钮的卡片模型来处理切换“继续”按钮的启用状态。
UpdateCards 操作用于根据用户选择更新其他卡片的状态。UpdateCardsActionFlow 可以包含更新状态所需的任何复杂逻辑。在这里,我们使用一个简单的 ActionFlow,它只是将卡片模型替换为启用状态模型。
图 14:动态卡片更新
RadioOptionGroupCard 和 SubmitSurveyActionFlow 共享一个流。此流包含有关所选选项的数据和用户输入的文本。ActionFlow 提交调查并根据选项 ID 将用户导航到下一个屏幕。我们使用一个通用的 ActionCardData 流来促进这种类型的逻辑,以便它在任何需要的地方都可用。
图 15:动态流第 1 部分
CompletionActions 在动作模型中被实现为 successAction 和 FailureAction。ActionFlows 在执行了指定的 Action 后完成。如果该操作打开了卡片屏幕,则在该屏幕消失时完成。
以下是 CancelMembershipAction 的示例,它同时具有 successAction 和 failureAction CompletionActions。
如果 CancelMembershipAction 成功,它将通过 NavigateBackAction 完成。NavigateBackAction 以 ReloadAction 完成。这是通过在 NavigateBackAction 中嵌套 ReloadAction 来实现的(可以在需要时使用这种方法导航其他级别)。
图 16:动态流程第 2 部分– CancelMembershipAction->successAction(NavigateBackAction-> successAction(RefreshAction))
下图显示了 (1) 从 MangeMembership 屏幕导航到 EndMembershipScreen,(2) 实际取消会员资格,(3) 将用户返回到 ManageMembership 屏幕,以及 (4) 重新加载 EndMembership 屏幕以显示新取消的会员国。
图 17:完整的取消会员流程
ActionCards 是简单的本机 UI 元素,易于创建、维护和调试。没有复杂的后端依赖控制布局逻辑。没有中间层。一些框架通过将逻辑推到后端来解决布局或动态流的问题。我们通过简单地减少可重用性元素并将操作与 UI 完全解耦来解决了这个问题。
大多数新屏幕需要创建 1 张甚至零张新卡片。我们团队的工程师不再花费大量时间编写/维护布局。如果一个可以完美完成所有事情的布局引擎可用,它对我们的生产力影响很小,因为我们花在布局上的时间很少。
ActionCards 为具有动态屏幕状态的可配置屏幕提供动力。它们允许启动新流程并在使用刷新屏幕完成任务后返回用户。他们这样做不需要编写新的移动代码。
ActionCard 模式为我们团队的移动工程工作带来了极大的简单性。我们继续积极推出,现在能够专注于构建新功能的元素,这些元素实际上是新的。通常,这意味着只需创建一张卡片和操作即可启动新功能。我们能够仅通过更改配置进行 A/B 测试,并且迭代速度比以往任何时候都快。我们默认内置了强大的分析功能,因此我们可以轻松观察我们工作的影响。
我们希望我们在本文中分享的经验对其他希望在有限资源下更快发展的小型团队有所帮助。
此处描述的所有内容都是 Uber Membership Mobile 团队的共同工作。以下团队成员在构建/完善此设计模式方面均发挥了重要作用:Aleksandr Nikiforov、Alok Sharma、Ameya Daphalapurkar、Andrew Paul Simmons、Dan Deng、Francisco Medina Bravo、Jessica Thrasher、Justin Muller、Omkar Sawant、Philip Donald、 Sam Hollingsworth、Sergey Evseev和李翔!特别感谢Zachary Thompson在一开始就推动我们走得更远并实施最灵活和动态的框架版本,并感谢Or Weizman在这个雄心勃勃的项目中支持我们!我们真的跨 3 个移动应用程序重建了一切,如果没有他的支持,我们不可能完成这一切!
作者:
Andrew Paul Simmons
Andrew Simmons is a Mobile Product Engineer at Uber and is an architect of the ActionCard design pattern used by the Membership Team.
出处:https://www.uber.com/en-US/blog/developing-the-actioncard-design-pattern/
页面更新:2024-04-21
本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828
© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号