Keep 自 2015 年 2 月上线以来,现在已影响了超过 8000 万人的运动习惯。作为一家初创公司,Keep 在媒体上并不算十分活跃。外界关注到 Keep 大多是因为 Keep 的用户增速、公司融资速度,最近的则是苹果公司 CEO Tim Cook 参观 Keep,以及 Keep 发布 4.0 新版本宣布由『移动健身教练』向『自由运动场』转型。归根结底,Keep 被人关注的根本是用户对 Keep 产品的认可,而受人喜爱的产品背后必然要有可信赖的技术开发做支撑。

接下来的这篇文章,是 Keep 技术团队对外的首次分享,包括 Tim Cook 来访时与 Keep 技术团队之间的互动,技术团队的工作流程以及 iOS 技术上的一些分享。另外,如果你有兴趣加入 Keep 的技术团队,可以在文末查看招聘信息。

目录

Tim Cook 的来访

3 月 21 日 Tim Cook 亮相位于亮点设计中心的 Keep 办公室,在王宁的陪同下参观了 Keep 的办公室和 GYM。

首先 Tim Cook 驻足前台观看了『自律给我自由』的宣传片。

Image of Front

随后 Tim Cook 来到技术团队的办公区,当途经 iOS 团队工位时,热心的询问关于 iOS 开发上的一些问题。Keep 客户端负责人在向 Tim Cook 简单介绍了正在开发的 4.0 版本之后,提到有很多模块已经采用 Swift 编程时,Tim Cook 表示很开心,鼓励 Keep 继续积极使用苹果推出的新技术,并加倍努力做出更棒的产品。

Cook Talk with iOS Team

乘车离开后 Tim Cook 在微博上写道:「An inspiring visit with Wang Ning and his team at Keep. Congratulations on 80,000,000 downloads and helping people get and keep healthy! 初遇 @王宁同学 和他的 @Keep 团队,深受鼓舞。祝贺你们喜获 8,000 万下载,更要为你们帮助每个人收获和保持健康而喝彩! ​」。

4.0 版本发布上线

最新版本 Keep 4.0 已发布上线,此次更新包含了以下功能:首页结构和数据中心界面升级;支持了户外骑行、跑步机跑步并添加了跑步路线;新增了直播和私信功能;个人主页改版,支持『运动日记』生成。

Keep 4.0

截止目前,Keep 已经集合了全国 8000 万用户,覆盖全国一、二线城市本科及以上高学历、高薪白领阶层的年轻群体,包括明星、运动教练、达人团队等,其中超过 6 成都是 90 后年轻用户,随时随地为他们提供运动生活体验服务。

究竟是什么吸引了 Tim Cook 前来参观,究竟是什么吸引了 8000 万用户的喜爱,本文将从 Keep 技术团队和 iOS 技术这两部分来介绍。

技术团队

Keep 技术团队主要由后台、运维、数据、前端和客户端组成,接下来会从敏捷的开发流程、高效的工具使用、高标准的产品质量和多方位的成长路线来给大家介绍 Keep 技术团队的全貌。

敏捷的开发流程

Keep 的开发流程是基于 Scrum 框架建立的。该流程要求在特定的一段时间内,输出确定的需求,在开发中需求尽量不要变更,开发人员快速完成开发。在一般情况下 Keep 的 Product Owner 和 Scrum Master 都是产品经理(除了技术推动的一些技术优化需求),大需求中涉及多端协同开发的功能会指定技术同事来负责沟通和协调。

目前的 Keep 迭代周期为两周,发版也保持两周一更新。这样既能让用户对产品保持新鲜,也不会让团队内部时间安排太过紧张。从每两周的周三开始一个新的 Sprint, 在新的 Sprint 的第二周开始具体的需求讲解和评审,并在下周周三完成迭代。下图描绘了 Keep 目前迭代周期的重要时间点和大概流程。

Development Flow

在执行 Sprint 流程时,必要的沟通会议是不可或缺的。会议的预订采用 Google Calendar 邀约的方式。目前主要固定会议分为以下三种:

  • 计划会议:规划下一个 Sprint 的开发任务。产品经理给开发人员讲解需求后,开发人员将需求拆解成子任务,并对任务时间进行评估。最后双方基于优先级和开发时间得到一个 Sprint 计划的开发任务列表。
  • 每日站会:开发团队互相了解进度。主要关注:昨天做了什么,今天要做的任务,遇到了什么问题。会议一般简短,控制在十分钟以内,无需涉及太多细节。
  • 回顾会议:总结和复盘开发过程中的问题。展示上一个 Sprint 的成果,回顾产品线上数据,讨论其中的非业务相关的问题,并讨论解决方案。

在了解完基本的 Scrum 流程模型后,那么具体 Scrum 中是如何进行任务拆分的。下面来看任务拆分环节。

产品经理和开发人员首先就需求实现的意义和可能性进行讨论,以便对需求进行筛选;然后对确定要开发的 Task 进行拆分。一般来说涉及多端的大 Task 会拆分为 UI Task,Server Task,Android Task,iOS Task,Web Task,以及 QA Task 六大子 Task,其中 UI Task 和 Server Task 可能会先行一周,给客户端和 Web 前端开发联调留足时间。

子 Task 被分配到具体技术组后,首先在组内会将子 Task 再次拆分为子任务,分发给开发 Owner,一般以 Point(1 Point 代表一天)为单位来拆分出最小粒度单位,原则上被拆分的 Task 完成时间最好不超过 2 Points;然后组内同事对开发 Owner 提出的设计方案进行评估,得出拆解完的子任务和对应的估点时间表;最后统计每个开发人员的开发总时间,再做任务上的合理调整。

任务拆分环节之后,开发人员会在下一个迭代进行功能开发。在整个 Sprint 开发过程中,开发人员在每日站会上同步每天的进度和棘手问题,把握现有的开发节奏。下图为需求拆分基本流程。

Product Decomposition

迭代完成后,会先在一周内进行内部测试和灰度测试。内部测试覆盖规模大致为 500 人,灰度测试的覆盖规模增加到 2000 人,一方面验证内测的 Bug 是否被解决,另一方面避免遗漏概率低于 0.1% 的 Bug。最后在下周二提交 App Store 和各大应用商店,iOS、Android 同步上线。

高效的工具使用

工具是第一生产力,Keep 技术团队非常重视对工具的使用。

团队常用且不限于的工具有以下:Phabricator, BearyChat (早期使用Slack) , Seafile, Google 企业套件 (Google Doc,Google Mail,Google Calendar ),Reveal,Alfred,ResuceTime,OhMyZsh,Paw 等。这里仅例举 Phabricator 和 Google 企业套件的使用情况。

Phabricator 是 Facebook 开源的一个开发流程工具,集成了项目管理、代码审计、代码管理等功能。Keep 技术团队的日常工作任务安排全部由 Phabricator 完成;时代码都托管在 Phabricator 的 Diffusion 上,并配合 Arcanist 工具进行 Code Review;Keep 也利用Phabricator 的 Maniphest 模块来创建和指派任务;此外, Phabricator 提供了诸多 Application 供团队使用,比如 Phame 中可以写 Blog,公司可以维护自己的 Wiki。Wiki 的编写不限于技术同事,根据公司内部的 Wiki 文案撰写说明所有同事都可以发布 Wiki,例如工作居住证的办理流程就是行政同事利用 Markdown 编辑的 Wiki。下图为公司所有公告资源均被整理到 Wiki 上,达到资源共享,提升办工效率。

Phabricator

Keep 已引入了企业应用套件 Google Apps For Business。无论是会议预订、技术文档撰写都通过 Google 这一系列软件来完成。例如会议预订可以先确定邀约的人当下 Calendar 是否方便,技术方案评估前会提前在 Google Doc 上讨论然后再组织开会确定方案。

高标准的产品质量

Keep 团队对数据十分重视,很多决策都是基于 A/B 测试做出的决定。一般来说新产品需求都会加上对应的埋点,每次产品会议回顾的时候,会分析上线版本数据的一个概况,同时产品经理会根据数据做出对应的调整。

另外一方面,分析数据不是万能的。Keep 团队还会在每上线版本之后进行用户反馈的收集和处理,不断的调整优化产品。

数据的关注不仅仅停留在产品层面上。在技术方面也做了诸多监控,比如上传下载的成功率,Bug 率,API 监控等数据。

Keep Data

一个优秀的技术团队一定是对代码质量有着高品质的要求。在代码 Review 方面来看,Review工作是技术成长的最好方式。Keep 做到良好的 Review 首先基于 Commit 的细粒度提交,技术团队内部规定:每次提交不应过大,保持代码功能单一的职责。但整体的提交应该包含一个已完成的完整功能, 未完成的功能不应该 Commit,代码作者在每次提交之前都应该自己过一遍代码,走一遍冒烟测试,确保基本的功能是完整的。

其次 Keep 代码的每个 Commit 都必须经过 Code Review。我们做法是强制在 Phabricator 代码库上限制了不能直接合入,必须经过 Review。

在选取合适 Reviewer 方面,功能改动和扩展时 Reviewer 选择模块原作者或者同一组的同事。复杂功能或牵涉到算法相关的 Review, 通常需要和 Author 一起进行 Review。对于超大型 Diff,本组内同事再一起拉会议室进行 Review。

多方位的成长路线

《Google 是如何运营的》曾提到, 人才即我们的『创意精英』才是公司的最大核心竞争力。由此可见,人才的培养非常重要。

对于新入职的同事,Keep 技术团队一般会指定一名 Mentor 来引导和熟悉公司业务流程,进而融入到团队中;对于初级工程师,Mentor 也负责指导功能实现设计和前期代码 Review 工作。

另外,每个迭代后的例会也是团队交流的重要一环。例会内容分为几个部分:简要介绍当前周期每个人任务安排,上期 Task 技术总结回顾,并抽取上期较有价值部分或者近期研究内容进行分享。

除了团队内部分享之外,也会组织和外界技术团队进行交流合作,例如 iOS T 社区。iOS T 社区是一个闭门的 iOS 技术沙龙,经常会举办线下交流活动。 Keep 曾作为主办方进行了 IM 实战、Clang 分享以及 iOS 测试相关的分享。下图为大家对议题的热烈讨论。

Conversation On T Salon

值得一提的是,由于和 Google Wear 以及 Apple 的合作,Keep 也得到了今年 WWDC 和 Google I/O 会议的名额。

Cook 此次访华在 Keep 特意和 iOS Team 开发人员进行了交流,所以,大致聊完 Keep 技术团队的组成和工作流程后,对技术团队中 iOS 开发再进行重点介绍。

iOS 技术

目前 Keep iOS 团队一共有 9 名成员。从业务上划分为 TC,SU,RT 三大块。TC (Training Course) 包含课程列表、参加训练、训练过程和课程表等训练健身的相关功能。SU (Social & User) 包含了社区、动态、消息、登录注册、相机、直播等功能。RT (Running Track) 目前有户外跑步、跑步机、骑行、跑步路线等。在了解完 iOS 团队情况和业务划分后,本文从 iOS 基本架构模型说起,随后描述技术选型和实现的一些细节,最后从技术展望的角度简单谈谈之后的发展和规划。

架构模型

Keep iOS 基本架构模型设计如下所示

Architecture of iOS

上图模型从下到上依次分为 Core, Service, Business 三层:

  • Core 层主要包含网络请求、基础通用模块、数据存储以及第三方服务模块,这些模块接口直接提供给上层服务。
  • Service 层包含了各种包装好的服务给业务层调用,比如本地日志系统、统计埋点以及第三方服务的封装等等。这一层承上启下,连接了 Core 层和 Business 层。
  • Business (SU/TC/RT) 的解耦以 KEPMedium 模块作为共同依赖组件,其核心实现是采用 Runtime 利用反射 Class 动态调用达到解耦的效果。 需要特别指出的是,由于项目庞大,在 Business 中首先需要将具体业务细化为子业务模块,比如图示的 Timeline 模块和 Live 模块;然后子业务内部再划分 MVC/MVVM ,但业务相关的工具类需要单独抽出;另外, Core 层和 Service 层的部分模块被要求放到私有仓库中,用 Carthage 作为Framework 为日后 Keep 其他 App 提供基础依赖。

技术实现

最开始 Keep 项目的 UI 编写主要采用 Storyboard 和 XIB,因为当时正处于苹果积极推崇 StoryBoard 的阶段。直至 2016 年5 月份,由于 Xcode 升级导致了 Storyboard 兼容性上的一些问题,外加项目工程大,导致 Storyboard 打开更耗费系统资源、编译时间更长,因此之后选取了 Masonry 作为 AutoLayout 主要开发库,同时资源图片采用 PDF 矢量图。

IDE 的选择

Tim Cook 来 Keep 参观时曾询问到 Xcode 能否满足当前的开发需求。作为 Apple 推出的官方 IDE,Xcode 对苹果特有的 Storyboard、XIB、plist 等文件类型均支持地比较全面,但在代码提示、自动补全等功能方面,同专攻 IDE 的 JetBrains 等公司推出的类似工具相比还略显逊色,例如 AppCode。iOS 开发团队也曾尝试过 AppCode,感受是:纯写代码较顺畅,静态检查也超赞,内置的 Git 操作、Refactor 等功能都非常好用;但 AppCode 对 Swift 和 Objective-C 混编、XIB 等支持的并不佳。目前开发团队中编译器的选择主要依据个人喜好,在纯写代码时更加偏向于 AppCode。

对 Swift 的态度

在 Swift 发布初期,Keep 项目即引入了 Swift 代码,但仅有一部分边缘模块采用 Swift 编写。主要考虑到 Swift 语言不够成熟,有可能存在一些隐形的坑;而且当时人手并不充裕,担心用一门不熟悉的语言而降低开发效率。事实证明当时的决定是正确的,随后 Swift 2.0 和 Swift 3.0 的两次大改动,给使用老版本 Swift 编写的应用带来了不小的升级工作量。但随着 Swift 3.0 的发布,Swift API 逐渐稳定,之后基本不会出现较大改动。所以目前 Keep 项目中新的业务模块几乎都用 Swift 编写,因为与 Objective-C 相比,Swift 语言更简洁,语法更 Modern。另外,团队中偶尔一些脚本、爬虫等项目也直接用 Swift 编写。

编译的优化

由于需求众多, Keep 项目逐渐庞大,导致编译时间加长,需要对其进行优化,iOS 团队主要从以下几个方面入手:

  1. 尽可能减少宏的定义,使用静态常量代替。
  2. 删除无用的头文件引用,采取 @class@import module 方式代替。
  3. 减少 Storyboard、XIB 的使用,因为 Storyboard 需要编译 Copy 等过程。
  4. 第三方库尽量使用静态库 Framework。

优化过后,整个工程编译时间从 15 分钟缩短至 7 分钟左右,而且随着组件化的细分,相信这个时间还会继续缩短。另外,业务模块相互独立后,Business 中各个业务也将单独拆成独立 Project 进行编译,使业务人员开发时只需编译自己的模块,开发效率更高。

自动化流程

iOS 团队采用 Jenkins + Xcodebuild + Fastlane 的方式,编写了打包上传 App Store、发布内测、灰度的自动化流程工具,并在公司的 Mac Pro 上部署了这一工具。当然除了打包之外,还部署了其他一些自动化服务,比如前台接待系统,办公网络抓包工具等等。

『前台接待系统』是 iOS 团队成员在业余时间,用 Swift + Spring Boot + Mysql 开发的一个自动接待工具。快递小哥来了之后只需进行扫码就可用短信通知快递收件人,基本替代了收发快递的工作,前台人员工作量明显减少了。像这种常用工具的搭建在 Keep 技术团队中非常常见,也是探索新技术的一种方式。

展望规划

在编程语言选择方面, iOS 开发团队会持续使用 Swift 来开展新的业务和重写旧的业务。另外近期也打算使用 RxSwift + Alamofire 重新编写网络层,逐步替代原有的 AFNetworking。

另外组件化的细粒度拆分还需进一步进行,实现各个业务组件可单独编译运行;Apple Watch 等外设提供的训练和跑步功能进行丰富和优化。

客户端性能优化也是今年的工作重点。iOS 开发团队会继续完善内部 KEPProtectKit 模块,降低崩溃率,监控和优化 FPS,减少网络延迟,提高 Web 页面加载速度,缩短冷启动时间,并加大单元测试的覆盖量,结合 Jenkins 更好的完成自动化测试和分析。

结尾

Keep 创立至今,其高速增长已不是什么秘密。但一般外界都是从 Keep 用户发展、产品形态、融资情况等方面报道。本文以 4.0 版本发布为契机,从 Keep 技术团队内部的工作流程、高效工具的使用、对人才重视以及部分技术实现等方面进行介绍,为大家展示了 Tim Cook 拜访的 Keep 背后的一个拥有相同价值观、崇尚效率并务实的团队。Keep 的愿景是打造出一个『自由运动场』,让更多人勇敢和坚定地迈出运动的第一步,将运动融入生活,更好的认知自我,追求更高的目标,最终让世界动起来!

如果你喜欢我们这样的团队,如果你热爱运动,那么,快到碗里来吧 :)

【 iOS 开发工程师 】

  • 职责:
    1. 负责 Keep 跑步或社区业务线的业务开发和重构工作;
    2. 负责新技术的研究和调研工作。
  • 要求:
    1. 2 年以上工作经验,本科以上学历;
    2. 有丰富的业务开发和一定的重构经验。

【 数据开发工程师 】

  • 职责:
    1. 负责 Keep 的数据流水线、用户画像和用户流失分析等系统的设计和开发;
    2. 负责推荐、反作弊的数据分析,为算法提供数据支持。
  • 要求:
    1. 2 年以上工作经验,本科以上学历;
    2. 熟练掌握 Java/Python/Scala 中至少一门语言,熟悉 Hadoop,Spark,Hive,Storm,Kafka 等开源项目。

【 Java 开发工程师 】

  • 职责:
    1. 参与 Keep 课程、社区和商业化等核心业务的研发工作;
    2. 参与基础服务和中间件等平台项目的研发工作。
  • 要求:
    1. 两年及以上 Unix/Linux 平台下高性能服务器端架构设计与开发经验,本科以上学历;
    2. 熟练掌握 Java/Go 等后端开发语言,了解 JVM 的运作机制;
    3. 熟悉 Docker、MC、Redis、MySQL、MongoDB、HBase 等基础组件源码和模块开发, 有大规模在线服务开发经验者优先。