在 AnDevCon 的尾声, Doug Bateman 主持了一个小组专注于如何才能开发一个扩展到全球数百万用户的Android 应用程序。内容包含团队管理、测试和可测性设计、功能和发布管理、支持、开源贡献和可选架构等等。
该活动是由 NewCircle Training 组织并分享了以下专家的见解:Howard Harte from Cyanogen, Inc.; Jake Wharton from Square; Ty Smith from Twitter’s Fabric team; Juan Gomez from Eventbrite; Mike Hines from Amazon; Larry Schiefer from HiQES; and Dave Smith from Possible Mobile.
你是如何管理团队来支持大量的功能开发?
Ty 简短地描述了 Twitter Fabric 团队从最初 15 人到 Twitter 收购 Crashlytics 后增长到 60 人如何负责许多的功能开发。总之,他们的组织保持不变是基于围绕独立功能创建较小的团队,然后确保这些团队至少每周进行交流。Juan 强调自动化测试等过程的重要性,以确新团队成员提交的代码不破坏任何东西。
在将新功能推向海量用户之前你们是如何进行测试的?
根据 Mike 的说法,你不必将一组更新一次性地推向所有用户。你可以将一个更新推向一小部分用户。亚马逊使用一个内部框架来做 A/B 测试并能够找出哪些功能使用率下降,通过它就能确定将哪些功能推向所有用户。Ty,从另一方面来说,在开发 SDK 的时候 A/B 测试不是一个好的选择,因为开发人员期望更多地是稳定性,他们不喜欢新功能推送多来后一段时间后被取消。所以,从这方面讲,这完全决定于开发人员的反馈、与开发人员合作和重点人群等等。
你们的测试策略是什么?你们使用哪些工具?
在 Howard 的情况下,考虑到 CyanogenMod 支持一百多种设备,重度测试依赖于用户在自己的设备上使用它并进行反馈。Jack 解释说,在 Squre 进行三种测试:在提交到主仓库之前要进行单元测试(数千个),通过异步运行慢速的机器测试来检测 app 的各个流程,最后是手动测试。有趣的是,Square 的开发人员尝试使用他们的 app 模拟所有咖啡和午餐的购买。Juan 再次强调了自动化测试的重要性,尽管他们也依赖于专门的 QA 团队。他们曾经使用 Robotium 作为工具,而是现在切换到了 Espresso 。
在回答观众提出的一个问题时,Jake 提出了自己对于 Robotium 的看法,它是围绕基本的 Android Instumention API 的包装,所以它并没有解决你在测试异步操作时的基本问题。例如你不应该进行一个新的测试直到确保所有与前一个相关的任务已经完成。Espresso,从另一方面来看,采用了一种新的方式,即在清除了主循环的所有消息之后就可以进行一个新的测试。除此之外,他还说,如果你使用了与网络相关的 library,你可以这样说:不要进行新的测试,直到没有网络活动。Espresso 还有一些明确的 API 来使得你能够进行更高级别的测试。
在 Fabric,Ty 说,他们正在从 JUnit 迁移到 Robolectric 。Robolectric 提供了不需要与 Android 框架进行深度交互的最快的方式去进行测试。在 Android Framework 是必须的地方,它通过创建 shadow classes 来和 contexts 和 activities 进行交互从而更好地完成工作。Robolectric 能使得测试运行地很快,因为它运行在本地 VM 上,这非常重要因为 Fabric 团队在 CI 流程内的每次提交都进行单元测试。在设计方面,Ty 介绍了他们在代码架构方面的努力,代码的高可测试性正是归功于它,基本上遵循单一职责原则,mocking classes,例如网络访问 classes,从而使得基本可对一切独立测试。
Jake 插入再次说,他们在一些必须和 bundle 或者 intent 再或者一些 UI Views 交互的情况下同样使用 Robolectric。在这样的情况下,通常的做法是将核心代码包装进 interface,由此就可以被 JUnit 测试。Robolectric,相反,使得能够通过 shadow classes 直接调用该代码。Square,Jake 继续说,一直在接触 Robolectric 并在将要发布的下一个版本中减少 shadow classes 的数量,目的是使用尽可能多的真实 Android 代码。它主要的优点是更接在 Android 设备上真实地操作。最后,Jake 提出了人们为何总是想方设法使用 Robolectric 在 JVM 进行所有的测试,因为它很快,但是这不是 Robolectric 的初衷。对于 Jake 来说,最大的优点是它提供了一个安全网和一些代码位所以你能够轻松地通过一些 Android superclass 运行你的代码。
你如何设计你的程序的可测试性?
Juan 说,理想的情况是,你想要通过架构一些东西使得通过一些 mocking 的帮助就可以进行自动测试。有一些设计模式和 libraries 能够帮助解耦你的代码使得它有更高的可测性。在 Eventbrite,他们用自己的框架做 mocking 和依赖注入,同时他们也在调研 Mockito 。Juan 说,有时候,当有地方与 Android framework 交互的时候得到一个干净的单元用来测试并非易事,但有办法使这个过程不那么痛苦。
Ty 接着说,在编写一个 SDK 时,他们不能使用依赖注入模式,基本上是由于要保持尽可能轻量化的意图,使用像 Dagger 这样的依赖注入工具不符合需求。当有与 Android activities 或 fragments 进行交互时,Fabric 的开发人员正在尝试将业务逻辑与 activities 本身解耦,因此前者可以在隔离中进行测试。根据 Ty 的说法,你要尽可能地将 activities 排除在测试之外,这就是他们通过一个单例 controller 将 activities 和它们的依赖绑定在一起的意图。
最后,Jake 提供一个稍微不同的观察角度,可测性设计是重要的,但也需要在你用来测试的抽象、它们的数量、mocks 和最终的目的也就是发布你的 app 之间找到平衡。所以你也想做一些简单的事情将事情完成。你想抽象,你想要一个干净的分离,但有时你只是把一些代码放在那里去使用,也许你可以返回来再提高它。因此,可测性设计可以看作是一个渐进的过程。
如何在嵌入式级别进行测试?
Larry 说,如果你在嵌入式级别工作,使用内核级别的驱动程序,或 HAL,你不会有和在 JVM 中可用的相同的框架或模式。在他的公司,他们尝试使用相同的模块化原则来构建驱动程序或 libraries 并抽象成组件使得能够提取到一个专有的测试框架。对于驱动程序,他们把它们放在内核空间,并依赖于一系列的应用空间测试,所以他们知道的驱动程序在内核空间是可靠的。
你在使用什么替代的设计方法?
Jake 讲述他们如何跳上使用 fragments 的行列来管理自己的用户界面,但发现它试图为太多人做太多的事情,对于如何做事它没有足够的“能力”,同时它很复杂并由许多毛病。最后,当他们明白自己实际上在通过试图使用一个单独的 activity 来管理一堆 fragments 来滥用这个系统的时候,他们移除了它。这限制了系统,所以他们决定执行自己的代码来管理视图。事实上,fragments 只是一种管理你的视图的方式,驱动它们显示或隐藏。这使得 Square 工程师可以简化他们的代码,每一个新的版本可以让他们看到他们的崩溃率下降,这得感谢摆脱了 fragments。Jake 说,当你在一段时间中只需处理几个的时候,fragments 可能是合适的。
有人在开发 apps 的时候使用反应式编程或者 reactive java?
Jake 再次率先表达了他使用 RxJava 的感受。简单地说,问题是,RxJava 是一个框架,而不是一个 library,这意味着你要在你的 app 中做很多工作来整合其 API,你几乎绝对不希望它在你的 activities、views 和 services 中,因为它实在是太多了。在 Square,他们使用内部 helpers 也使用 RxAndroid ,它的部分属于 RxJava。RxAndroid 将使 RxJava 的异步观察模型更容易接入 Android 的世界。
当你有世界范围的用户时,你如何适配 Android?
关于通过本土化与国际化来支持全球用户的使用的重要性,Mike 给出他的观点。这到头来体现在准备好例如从右到左书写支持,或像德语一样可以有非常长的词语能够让任何用户界面无效。抽象并使用资源文件也很重要。Mike 说支撑起一个庞大用户基础的有趣的一面是支持人员和工程师之间的互动。支持人员通常可以为你所开发的功能提出有趣的用户故事,但随着规模的增加,他们也会建议使用从未想到的一些功能。但有时,那些新的故事真的很棒!
对 Ty 来说,当支持一个全球用户基础,设备和操作系统碎片化成为一个重要的因素,因为你会希望你的 SDK 支持最广泛的设备,但是你没有选择他们。因此,能够逐步降低你的功能同时使用最小量的资源来运行是很重要的,特别是对于新兴市场。Juan 强调了同样地概念,他总是给应用程序在低分辨率或缓慢的设备留有余地,因为很多美国以外的用户就是这样的。此外,Howard 说,通常哪些地方的设备没有太多内存。
你能介绍一下你的组织如何与开源社区进行交流吗?
Mike 说,在亚马逊,他们有一个小组负责处理开源贡献和回馈开源社区。会有一个程序,工程师将他们想要回馈提交的代码提交给亚马逊的律师,所以他们可以检查任何涉及的知识产权。Mike 说,这是一个非常棘手的业务,所以不要让工程师当律师!
Jake 提供了相当不同的观点:在 Square,这个过程完全是工程师驱动的。他们也有一个合法或许可审查,但没有人会说:“嘿,这看起来不错,你应该开源。”Square 没有正式的程序,除了为了开源使用共同审查以评估代码,最终,如果它被认为是适当的,就会被提交到开源仓库。Square 和开放源社区之间的关系是紧密的,既是由于 Square 有许多贡献,也由于外部用户提交的 pull requests。杰克说,他们甚至为了感谢一些人的 pull requests 而雇佣了他们。
Howard 说,Cyanogen 也与开源社区有很好的关系,约有 9000 人有来自社区的贡献。关于开源社区的一个好处是你可以审查它以确保它是安全的并且不是为了牟利而开源。
你认为什么是不可缺少的开源库?
Dave 解释说,他的公司没有贡献大量的开源代码,虽然他们使用了很多。当然,他们很注重代码的许可证,所以有时候他们不匹配许可证就不得不重新实现。Dave 说,他们的大量使用一些 Square 的 libraries 例如 Picasso 、 Retrofit 和 Dagger。
Larry 认为,让客户了解可能使用一个给定的开源库是很重要的,所以他们明白有什么含义,并给他们一个机会去决定什么对他们是最好的。
如何分析有助于开发更好的 apps?
Ty 指出,有很多不同的分析方法。例如前面提到 A/B 测试可以让你对产品的功能做出重要的决定。Ty 说,Fabric 是一个强大的分析平台,虽不像 Google Analytics 那样灵活,但会为高层次的决定提供足够的信息,例如,用户数,崩溃数等等。
对 Jake 来说,app 的分析显然是有好处的,但对他来说,收集他们用作运维也很重要。他解释说,为调查运维调用,他们记录了每个功能调用的频率,所以当他们检测到一个给定功能的高调用率,他们可以尝试提高它,从而提高应用程序和运维。这种方法也有助于在一个应用程序的用户基数增长的时候保持运维水平不变,并且不需要雇用更多的运维人员。
最后 Dave 增加了他的观点,观察分析对他们的客户是非常重要的,基本上是因为分析帮助推动收入,他们经常在一些应用程序种使用最多七个分析包。分析是他们决定 apps 应该向哪个方向走的数据来源。
你最喜欢的学习安卓的资源是什么?
Ty 说,Android 文档是非常棒,并且还有很多杰出的书籍,他最喜欢的一本是“The Busy Coder’s Guide to Android Development”。Haward 说,网上也有几个主题的丰富的介绍。
对于杰克来说,很难找到很好的高级内容。他说,对于初学者来说有很多好东西,但有时也没有太多关于新框架的信息或者更深入的资料。所以,当你到达一个中间的水平,很难找到资料来更进一步提高自己。
Larry、Mike 和 Dave 都同意导师帮助新手快速进步的重要性。在他们的公司会配对初级开发人员与高级开发人员从而得到快速提高。
怎样才能让我们的设计师了解 Android?他们似乎只了解 iOS…
Dave 有一个相当激进的方法,建议设计部门的几个人使用 Android 手机一段时间。他认为这是设计师理解交互模型而不只是看截图的唯一方式。另一方面,Juan 强调开发人员努力给设计师提供正确的信息的重要性。他回忆起一个例子,他买了几本谷歌的 material 设计书,并给了他们的设计师。
这里有线上的小组讨论记录完整版。
Sergio de Simone是一名 iOS 独立开发者和顾问。Sergio 作为软件工程师在不同的项目和公司中工作超过了 15 年,包括不同的工作环境例如 Siemens、HP 和小的初创公司。目前,他专注于移动平台的开发和相关的技术。
查看英文原文: Lessons Learned by Scaling Android Apps - AnDevCon Panel Summary
感谢张龙对本文的审校。
给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ , @丁晓昀),微信(微信号: InfoQChina )关注我们,并与我们的编辑和其他读者朋友交流(欢迎加入 InfoQ 读者交流群)。
评论