iHealth 团队的最佳实践

昨晚(8月31日周三)我去清华那里听了一场由毛豆网组织的技术讲座,题为《硅谷最新的 React/Redux 和 Meteor 共存之道》。

主讲人叫 Vivian Hou,中科大化学本科,普林斯顿计算化学博士,然后,转行干软件开发,作为全栈软件工程师加入 iHealth Labs,他的老板 Kevin G. Zhang 说她将是公司新项目的主导者。

Kevin 曾是清华学霸,曾是社交阅读平台剪客的创始人,然后,作为 CTO 加入 iHealth Labs,不仅将 Meteor 嵌入公司的技术架构,而且致力于在中国推广 Meteor。

在现场可以嗅出 Kevin 有一定的知名度,我孤陋寡闻,用 Meteor 这么长时间了都没听说过这个人。随手搜了一下,发现自己听过他的演讲,去年他们曾在 Meteor Devshop 介绍了 iHealth 的开发框架。

以上是一些背景信息,下面进入主题,我概述一下讲座中提到的技术内容。

从讲座标题可以看出,React/Redux 和 Meteor 的结合是其团队当前认可的最佳实践。我深表认同。

但这其中有转折。

在 Meteor 1.2 版本之前,也就是我口中的经典模式,其团队使用的是 Meteor + Blaze,这是必然的,当时没有其他选择。在实践中遇到一些问题,当应用愈加庞大,模板内的重新渲染条件愈发难以控制。可以理解,Blaze + Tracker 是傻瓜式的,没那么讲究,真要想细致调控倒也不是不行,但那就失去了 Blaze 易用的优势。复杂系统引发界面渲染的性能问题,他们考虑换一套前端方案。

Meteor 1.2 版本的发布允许他们换到 React 这来。数据的单向流动使得系统内的数据流更加清晰,用 Vivian 的原话说,React 帮助他们解决了界面渲染的性能问题。不过,另一个问题出现了,React 的数据单向流动机制不仅可以让父级组件将数据自然地传给子级组件,而且当数据发生变动时,子级组件会自发重新渲染,但是,不同级别的组件之间该如何沟通呢,这里面有很多方法,嗯,与其说是方法,不如说是一种 hack 甚至是 trick,当系统变得复杂,那些方法的副作用会让开发者在 debug 过程中生不如死。

因此,iHealth 团队引入 Flux 以集中管理状态。这里面的内容我略过了,因为大部分和下一段相似,总之,他们后来发现了新欢,名为 Redux,原因是它的实现原则更简单 —— 1.数据和状态保存在有且只有一个对象(Object)里, 2.这个对象是只读的, 3.通过 pure function 对对象进行操控。什么是 pure function?就是不管在何种情况下,相同的输入产生相同的输出,这就类似科学实验,实验过程是固定死的,只有经受住反复的试验,且得到相同的试验结果,它才能被科学界认可。在这一环境下的实验过程就是 pure function.

好,iHealth 弃 Flux 投 Redux,原因说过了,实现的机制差不多,但原则更有约束性。虽然约束多了,但在复杂系统中这就意味着代码更加易于维护。Redux 掌管所有的数据源和所有的组件状态,当某一组件的事件被激发,它会向 Redux 报告,并使用相对应的 pure function 对数据进行操作,返回一个新的对象(Object),并将其导入相对应的组件,用户界面会在 React 下重新渲染,于此完成整个事件。

用 Kevin 的原话说,Redux 让整个事件的定义变得复杂了,让整个数据流动于更多的地方,看似降低开发效率、影响系统性能,实则意义重大。

  1. 用户界面(UI)层与业务逻辑层的分离。试想,负责 UI 的人专心调试 UI,负责逻辑的人专心构建逻辑,两者的分离不仅大大降低了沟通成本,而且能够在初期发现单一组件在某一状态下出现的问题,避免在项目末尾醉死于 debug。如何做到,借助 React Storybook 工具,UI 可将组件进行视觉呈现,负责业务逻辑的工程师写测试让机器自动检查。比如,Airbnb 团队出品的 react-dates 就是榜样。

  2. 可积累的组件。试想,当前项目的某一组件不仅可以应用到同一项目的另一个特性中,而且可以迁移到新项目。这意味着UI工程师的劳动或者说绝大部分劳动可被积累下来。从另一个角度看,开源组件是一个超大型武器库,只要你在这个大背景下 —— 即 React —— 跨公司之间的协作便在无意识中完成了。这也相当于 JavasSript 生态的魅力之一吧。

  3. 更易于团队协作与维护的代码。Kevin 认为慢就是快,对独立开发来说使用 Redux 是慢了,但对一个团队来说,解决了协作与维护的问题,整体来看,反而更为高效。Redux 的只读原则使得每一次状态变更都能够保存下来,方便开发者对状态进行回退,以此进行更有针对性的 debug.

就我个人分析,iHealth 团队之所以选择 React/Redux/Meteor 三者共存作为最佳实践,有三点原因:

  1. 依赖 Meteor 已久。iHealth 是做智能医疗设备的,当初选择 Meteor 我猜便是看重其敏捷开发和实时特性,不仅方便团队开发原型,而且方便实现实时连接的物联网。短时间内,放弃 Meteor 太冒险,因此想方设法将其与新趋势连接起来。

  2. React/Redux 是趋势。React 负责界面渲染,Redux 负责状态统一管理,这几乎已被 JavaScript 生态认定为标配。因此与其说是 iHealth 的最佳实践,不如说是 JavaScript 生态的最佳实践。如果你想保持与这个行业前沿的相关性,那么学习 React 和 Redux 则几乎是必须的了。

  3. 分工合作。iHealth 团队分布全球,跨时区协作,这里面存在着极大的沟通成本,而上面提到的用户界面(UI)层与业务逻辑层的分离,至少让这两方面的工程师们能够异步协作了。

iHealth 追求的是团队分工下的高效协作,我所在的公司 FAMI 追求的是独立开发者自身的高效开发。它俩各有利弊,我求同存异,大型复杂的项目势必要专业分工,中小型项目则不需要那么复杂的人员配置。相通的地方是,皆在使用工具让自己尽可能的降低成本、提升效率。我在《掌握 Meteor 的经典模式后对你来说意味着什么》一文中提到过,这是软件为世界做出的贡献,我想,软件是文字与货币之后最伟大的软发明吧,不仅伟大,而且正陆续将那二者颠覆。