近期 Jetpack Compose 发布了 1.0 版本,带来了一系列用于构建 UI 的稳定 API。今年早些时候,我们发布了 API 指南,介绍了编写 Jetpack Compose API 的最佳实践和 API 设计模式。经过多次迭代公共 API 接口 (API surface) 之后形成的指南,其实没有展示出这些设计模式的形成过程和我们在迭代过程中决策背后的故事。
本文将继续带您了解一个 "简单" 的 Button 的 "进化之旅",来深入了解我们是如何迭代设计 API,使其简单易用又不失灵活性。这个过程需要基于开发者的反馈,对 API 的可用性进行多次的适配和改进。
在上一篇文章中,我们通过开发者反馈、API 一致性和可发现性三个方面,和大家探讨了 Button API 的迭代过程。本文将进一步为大家展示 Button API 是如何在原有设计上逐步优化演变成为今天的设计。
映射开发者的工作框架
△ material.io 中的 Material Button
我们从开发者活动中得到了一个关键启示 —— 大多数开发者不太熟悉 Material Button 中的命名习惯。比如,很多开发者无法区分 ContainedButton 和 OutlinedButton:
ContainedButton 是什么意思呢?
更清楚地描述角色
研究发现,另外一个令人困惑的点是两个已存在的 Button 的版本: 一个 Button 可接受一个 String 类型的参数作为文本,而一个 Button 可接受一个可修改的 lambda 参数,表示通用内容。这么设计的本意是从两个不同的层次来提供 API:
带有文本的 Button 更简单一些,更加易于实现
更高级的 Button,它其中的内容更具开放性
它允许自定义内部的 TextStyle 而无需使用 lambda 重载的版本。
我们提供 String 的本意是希望能够简化那些最简单用例的实现,但是这样却阻碍了开发者使用带有可组合的 lambda 的重载,转而要求 String 重载增加额外功能。这两个单独 API 的存在,不仅造成了开发者的困惑,也表明了带有原始类型的重载的确存在一些根本的问题: 他们接受了原始类型,比如 String,而不是可组合的 lambda 类型。
单步代码
紧耦合的副作用
Button(backgroundColor = Color.Purple) {
// 任何可组合内容都可以写在这里
}
Button(backgroundColor = Color.Purple) {
Row {
MyImage()
Spacer(4.dp)
Text("Button")
}
}
△ 带有横向排列的图片和文本的 Button
展望未来
我们对 Button API 所做的修改数量之多,在讨论 Button 的会议中所付出的时间之多,以及收集开发者的反馈所投入的精力之巨大,足以惊人。话虽如此,我们对 API 整体的效果非常满意。事后看来,我们看到在 Compose 中 Button 变得更具可发现性、可定制性,最重要的是它促进了组合式思维。
fun Button(
onClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
elevation: ButtonElevation? = ButtonDefaults.elevation(),
shape: Shape = MaterialTheme.shapes.small,
border: BorderStroke? = null,
colors: ButtonColors = ButtonDefaults.buttonColors(),
contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
content: Unit RowScope.() ->
) {
// 实现体代码
}
△ 1.0 Button AP
1.0 Button AP
https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose/material/material/src/commonMain/kotlin/androidx/compose/material/Button.kt;l=96?q=Button.kt
重要的是认识到,我们的设计决策都基于下面这句口号:
让简单的开发变得简单,让困难的开发变得可能。*
*这里出自著名的技术类书籍: 英文版:《Learning Perl: Making Easy Things Easy and Hard Things Possible》(Randal L. Schwartz、Brian D Foy 和 Tom Phoenix 著),中文版:《Perl 语言入门》(盛春译)
我们尝试通过减少重载,并将 "样式" 扁平化处理,使开发变得更加简单。与此同时,我们改进了 Android Studio 的自动补全功能,来帮助开发者提高效率。
这里我们希望特别提出在整个 API 设计过程中的两个要点:
API 的设计是一个迭代的过程。在 API 最初的迭代中就达到完美的状态是几乎不可能的。有一些需求容易被忽视。作为一个 API 的作者,您需要做出一些假设。这其中包括开发者背景的不同,所带来的不同思维方式¹,最终影响了开发者探索和使用 API 的方式。适配调整是无法避免的,这是好事,不断迭代可以得到可用性更高并且更加直观的 API。
在迭代一个 API 设计时,您最有价值的工具之一是开发者使用 API 体验的反馈循环。对我们的团队来说,最关键的是去理解开发者所说的 "这个 API 太复杂了" 意味着什么。当错误调用 API 时,通常会降低开发者的成功率和效率,从中所获得感悟,会帮助我们更深入理解 "复杂 API" 的意思。我们不断迭代的关键驱动力是我们要设计易用且出色的 API。为此,创建开发者反馈循环,我们使用了多种研究路径 —— 现场编程活动²,和需要开发者提供体验日记³ 的远程途径。我们已经可以理解开发者是如何处理 API,以及他们为打算实现的功能,找到正确方法所采取的路径。诸如工程师思维方式 (Programmer Thinking Styles) 和认知纬度 (Cognitive Dimensions) 这类框架中的支柱,有助于我们跨职能团队保持语言思维上的一致,不仅表现在审核、沟通开发者反馈中,也涉及到 API 设计讨论。尤其是,当评估用户体验和功能性之间的关系时,这个框架帮助我们塑造了为选择和权衡所做的讨论。
来自 Android Developer UX 团队的 Meital Tagor Sbero 受到角色模型和思维方式 (personas & Thinking Styles) 的设计和认知维度框架 (Cognitive Dimensions Framework) 的启发,开发了工程师思维方式框架 (Programmer Thinking Styles Framework)。该框架使用开发者在限定时间内所需 "解决方案的类型"的动机和态度,帮助开发者确定 API 可用性的设计思路。它兼顾了普通工程师的工作方式,并且针对高强度开发任务优化了可用性。
我们通常使用这种方式评估 API 特定方面的可用性。比如,每个活动会邀请一组开发者使用 Button API 来完成一系列开发任务,这些任务会特意暴露一些 API 的特征,而这些特征是我们希望收集反馈的目标。我们通过放声思考法,来获得更多关于开发者所追求的和开发者所设想的信息。这些活动中还包含研究者通过一些随访的问题,来进一步了解开发者的需求。我们会回顾这些活动,从而确定开发者在编程任务中促成成功或者导致失败的行为模式。
我们通常使用这种方式来评估 API 在一段时间内的可用性和易学习性。这种方式可以通过倾听开发者在常规工作中的反馈,来捕捉遇到困难的瞬间和受到启发的瞬间。在这个过程中,我们会有一组开发者开发由他们自选的特定项目,同时也确保他们会使用我们希望评估的 API。我们会结合开发者通过自行提交的日记,和由研究人员基于认知维度框架 (Cognitive Dimensions Framework) (示例) 所组织的深度调查,以及专访活动来帮助我们确定 API 的可用性。
Meital Tagor Sbero
https://www.linkedin.com/in/meitaltagor/
角色模型和思维方式 (personas & Thinking Styles)
https://medium.com/inclusive-software/tagged/thinking-styles
认知维度框架 (Cognitive Dimensions Framework)
https://www.researchgate.net/profile/Marian-Petre-4/publication/200085937_Usability_Analysis_of_Visual_Programming_Environments_A_%27Cognitive_Dimensions%27_Framework/links/02bfe50fbf23476730000000/Usability-Analysis-of-Visual-Programming-Environments-A-Cognitive-Dimensions-Framework.pdf
示例
https://arxiv.org/pdf/1703.09846.pdf
问题提出和建议反馈
https://issuetracker.google.com/issues/new?component=612128&template=1253476
Google 用户体验调研
推荐阅读
点击屏末 | 阅读原文 | 即刻了解使用 Jetpack Compose 打造更出色的应用