「2019 JSConf.Hawaii - Brie.Bunge」大规模应用 TypeScript

特别说明

这是一个由 simviso 团队对 JSConf.Hawaii 中关于 TypeScript 相关话题进行翻译的文档,内容并不是直译,其中有一些是笔者自身的思考。分享者为 Brie.Bunge,Airbnb(爱彼迎)高级前端工程师。前端

现以下,TypeScript 已然兴起,若是各位小伙伴大家公司还未将开发迁移到 TypeScript 下,亦或正在迁移或者已经迁移了,那么不妨一块儿透过本文来看看 Airbnb 是如何作到大规模应用 TypeScript 的。react

视频地址:git

视频翻译版权归 simviso 全部,未经许可严禁转载程序员

前端公众号github

1、前言

你们好,个人名字是 Bree,在 Airbnb 工做。typescript

在大公司中进行大的改革很难,这须要去说服不少人,同时又须要涉及大量的代码迁移。npm

我想要和你们分享的是,咱们是如何将 TypeScript 应用到 Airbnb 的。编程

我感谢大家能在这里,我知道大家彻底能够披着时髦的毛巾在海边娱乐。后端

但我但愿你们都能从中受益,不管你是否正在为你的公司进行重大改革,这均可以做为一种案例进行研究。不管你如今是否正在积极的进行 TypeScript 迁移,咱们都将讨论一些能够帮到你的工具和技术。数组

或许,你已经听过一些 TypeScript 的内容,但想了解更多。

首先,咱们会介绍 TypeScript 是什么?规划化又意味着什么?提议使用 TypeScript 的过程又是如何?

基于这些问题和疑问,我会给出相应的解答。咱们该经过什么样的迁移策略将 JavaScript 逐步迁移到 TypeScript。

请你们快速举手示意一下以方便我知道大概有多少人以前使用过 TypeScript。酷,有这么多人。

还有一部分人没有举手。那么,让咱们快速介绍一下,这样每一个人都在同一块儿跑线上了。

2、快速介绍

假如咱们有这么一个 greeter 方法,它接收一个 name 参数,而后返回 'Hello' + name

因此,若是咱们传入的是 JSConf,它会和睦的说 Hello JSConf。

将刚才的代码用 TypeScript 来表达就是这个样子。

能够看到它们很像,惟一的区别是咱们在它的参数这里使用了类型注释。

因此若是咱们在咱们的 TypeScript 项目中使用这个函数同时咱们传入一个字符串,能够看到编译一切正常。

可是在下图的状况下,若是咱们传递的参数类型不是字符串,而是一个字符串数组,那么 TypeScript 就会给咱们一个报错,即字符串数组不能分配给 string 类型的参数。

咱们不须要再经过点击刷新页面这一流程来从咱们的控制台中查看错误并肯定该错误所发生的位置。能够看到,在咱们输入后,当即就从编辑器中获得了这个错误。

咱们也能够表达其余对象类型,具体如图

这个接口描述了一个包含名字和姓氏的 person 对象。同时,你能够定义更复杂的构造类型。

TypeScript 一般带有一个编译器,当出现问题时就能够立马告诉你。它还有一个能够与编辑器挂钩的语言服务器,能够帮咱们进行自动编译,提供重构相关提示等等。

再看个例子,如图

例子中,咱们已经将咱们的 React 高阶组件 withStyles 进行了类型绑定。因此它能够自动对数百个 CSS 属性进行联想,包括内联文档。

牛逼吧!这样一来我就没必要再来回翻阅文档页面了,我在编辑器中就能获得全部属性。

经过使用 TypeScript,咱们在编码时能作更多的事情。

这仅涉及了 TypeScript 很是基础的一些功能,但却让你了解到它捕获类型错误的能力,以及支持它的工具。

3、规模化应用

关于 TypeScript 是什么的内容就到此,那关于规模化应用这一部分呢?

一、具体规模场景

规模化会改变咱们的交流方式。

之前我在小团队的时候,在那若是你想用 TypeScript。“是的,听起来很酷,那咱们用吧。”

但当你的团队规模达到数百位工程师、同时代码量也愈来愈多时,交流方式则会发生改变。

咱们将进行改革,咱们提议在咱们的主仓库中使用 TypeScript,并让它成为前端开发的主要语言。

改革影响的人越多,那必须迁移的代码也越多。

让咱们来量化一下咱们所说的规模。如图

Airbnb 拥有大量的 JS 代码,咱们的主仓库中有超过 200W 行的 JS 代码,以及 100 多个内部 npm 包。

这些都是分离的仓库,经过打包到内部的 npm 注册中心的,这样就能跨仓库共享了。

这真的有不少代码,我甚至能看到一些 Backbone 的影子。能够想下 JavaScript 走过了多少年,它在 Airbnb 这也走过了十年之久,因此咱们也有大量的开发在维护这些代码。

目前公司有超过 1300 名的开发,其中有 200 个是前端,这些前端工程师大多数都参与了主仓库的贡献。

这些数字描绘了咱们当时提议使用 TypeScript 所面临的困境。

那么,它在如此规模下咱们须要作什么呢?

每月,咱们都会举行一次有趣的会议,公司全部前端工程师都会聚在一块儿,一块儿讨论新的前端技术和模式。

为了能够作到深思远虑,咱们起草了份提案,它概述了诸如优势、权衡、替代方案、弃用策略以及长期拥有者等事项。

你们会权衡这些提议的利弊,咱们会站在团队的角度去决定向前迈出这步是否有意义。

这确保了咱们能够做为一个集思广益的团队,对所作的事情作出深思熟虑的决定,避免在没有正当技术理由的状况下就“上车”了。

从 2016 年起,Airbnb 已经在一些小规模团队中探索使用 TypeScript。

在 2017 年的前端调查中,静态类型系统的呼声最高。

基于这些,Joe 和我起草了一个关于 TypeScript 的提案,并将它交给前端工做组,这项提案详细说明了为何在 Airbnb 使用 TypeScript 是有意义的。

让我来说讲主要的缘由。

Airbnb 的使命是:

让每一个人在哪都有归属感

用户每遇到的一个问题均可能致使咱们背道而驰,对于你正在开发的产品也是如此,而TypeScript 能够帮助咱们减小 bug 的发生。

TypeScript 还为开发人员提供大量的生产力效益和工具,像咱们以前看到,自动编译和重构。

使用 TypeScript,工程师能够更安全快速的迁移代码。在 Airbnb,咱们引入了 GraphQL 和 Apollo ,它容许咱们在 GraphQL 模式中直接生成 TS 声明。

这意味着咱们能保证端到端的类型类型,由于先后端本质上使用的数据类型共享了同一申明。后端工程师可以在不影响客户端的状况下对 API 进行修改,而前端工程师则能够明确哪些数据将从服务器返回。

类型不匹配一直是咱们的主要 bug 所在。所以,这种端到端的类型安全性是一个主要的卖点。

这听起来很棒,但对于咱们的初步提案,还有不少问题和疑虑。让咱们更深刻地了解其中的一些。

咱们的 mono repo(译者注:mono repo 意为代码都在一个仓库)是依赖咱们内部 npm 包的。

为了得到自动完成和类型检查,咱们须要先将它们转换为 TypeScript 吗?

这就是咱们面临的困境,咱们的 TypeScript 项目依赖 JS npm 包,咱们如何拿到那些包的类型定义?

这彷佛的确须要先将那些包转换成 TypeScript。

但这有个问题,因为维护人员不容许咱们对它转换,或许他们不肯这么作吧。由于在咱们提案的早期阶段,咱们也不肯定是否能继续推动下去。

但从另外一方面来说,使用 TypeScript 是为了让开发人员在有一个更好的开发体验,咱们须要 TypeScript 提供的类型安全性。

那么咱们该如何解决这个看似鸡和蛋的问题呢?

二、解决方案 - 申明文件

TypeScript 有一个称为声明文件的特性,即扩展名为 .d.ts 的文件,咱们能够为 JavaScript 文件定义类型。

让咱们来看一个例子,继续拿咱们前面提到的 greeter 方法来作说明,如图

它上面是对应的.d.ts文件。方法里没有实现细节,它只描述了类型。TypeScript 将它们组合到一块儿,这样,编译时使用的是这个声明文件,而运行时使用的则是这个原生的 JS 文件。

因此,让咱们回到刚才咱们提到的问题(要不要一开始就作转换),看看声明文件是如何提供帮助的。

固然,若是这个项目已经转换成 TypeScript 了,那么则不必再去生成一个 .d.ts 文件来做为 TypeScript 构建时的一部分了。

但我认为这不止一种选择,相反,咱们能够将声明文件放在咱们的 TypeScript 项目中。

另外一个选择则是,咱们能够建立一个分离的 npm 包,将申明文件丢到那。

这很好,由于如今咱们能够跨仓库共享声明文件。

这就比如 @types/react 中的类型定义。你安装 react 的同时,你也能够安装 @types/react 做为其类型定义的包。

@types/reactDefinitelyTyped 5000 多个包中的一个,它由一个社区专门进行维护。

咱们主库中绝大多数的公共依赖都在 DefinitelyTyped 中定义了。

TypeScript 社区活跃也是它的一大卖点。咱们也回馈了一些力量,我相信在座的各位也作过贡献,谢谢啦。

公共 npm 包已经有 DefinitelyTyped 作定义了,但那些内部包该怎么办呢?

咱们经过建立一个独立的 npm 做用域对 DefinitelyTyped 作了一个内部镜像,因此当你 install @types/* 时,其实是 install @airbnb-types/* 的。

这个仓库的设置跟 DefinitelyTyped 差很少,因此咱们能在那加上本身的类型定义,而后在内部发布。

咱们开源了一个入门的工具包(types-starter),若是你对这些设置感兴趣能够看下。它里面没有任何类型定义,它只教你如何配置,以便你测试并发布本身的类型定义。

那么,TypeScript 究竟能帮忙避免多少 bug 呢?咱们看张图

近期,一个叫作 “该不应作类型定义” 的研究代表,在选择 TypeScript 的 github 仓库中,有 15% 的 bug 获得了避免。

在咱们内部,有个记录生产环境事故的流程。这个流程的本意并非为了责怪谁,而是要从错误中进行学习,这样咱们以后就不会再犯相似的错误。

因此我坐下来读了六个月的总结报告,看这些报告颇有意思,其中我最喜欢看到的莫过于 未捕获的异常危险的参数计算 等。

好吧,或许这些报错的名字没有让人那么激动。

不管如何,我将这些错误归类为与 JavaScript 相关或无关,以此肯定哪些错误能够经过使用 TypeScript 来避免。

4、案例讲解

让咱们一块儿看个例子,看看使用 TypeScript 能带来哪些帮助。

一、参数传递

咱们对共享组件 Input 作些修改,经过一些设置来还原 bug,用户没法提交表单是由于它再也不经过验证。

组件 Input 的更改前的简化版本具体如图

它接收一个 onBlur 变量,并将其直接传递给 input 元素。所作的改变就是添加一个新的 onBlur 事件处理。

但这存在一个不明显的bug,你能发现它吗?就是事件参数再也不传递给 onBlur 事件属性。

这就致使了在好几个仓库中都出现了这同一个问题。Input 组件做为 Redux Form 的一部分使用,指望传递参数是 event 或 value,以便验证正常工做。

若是没有该参数,表单将再也不经过验证,这就意味着提交按钮始终处于禁用状态。

TypeScript 在这是如何帮到咱们的呢?

咱们从文档中能够看到 Redux Form 有类型约束,onBlur 事件属性必须传递一个 event 或 value 类型参数。所以,若是咱们使用了作了 TS 申明的 Redux Form,那么在函数调用那则能够看到一个不传递事件参数的报错。具体如图

二、其它特性

另外一类常见的问题就是涉及严格的空值检查,即便用属性来构造或尝试调用可能为 nullundefined 的内容。你可能之前有见过这个错误,如图

另外一种是类型不匹配。当咱们尝试使用彼此不匹配的类型时,TypeScript 就会提示咱们。 因此如今咱们对常见的检查出来的问题有了更好的理解,TypeScript 能够帮助预防这种 bug。

三、日志数据

那事故日志中表现出来的整体百分比是多少呢?

38%!

咱们发现有 38% 的事故致使了生产阶段的bug。

这些对咱们用户产生实际影响的 bug,可使用 TypeScript 来阻止,这对咱们来讲是个巨大的发现。

它有助于作案例复现。以前,咱们复制了一些 bug 事件,并向你们展现了 TypeScript 所给出的 error 提示,而后对 bug 进行修复。

的确,咱们能经过写测试案例来捕获这些,但经过静态类型检查则能够再额外加一层保护。

所以,若是你所在的公司也有相似的历史,那你可能就有必要和那些玩过 TypeScript 的小伙伴一块儿看看我说起的这些问题在大家代码中所占比例了。

四、团队推动

那么团队是否但愿切换到 TypesSript 呢?咱们在几个团队试用了 TypeScript,专门针对以前没有使用过 TypeScript 的团队来获取更多的使用反馈。咱们帮他们设置好 TypeScript 环境,而后收集他们的反馈。

在用了一段时间后,咱们向他们发送了一份调查问卷,询问他们是否应该继续使用 TypeScript?

从上图能看出,答案是很是确定的。

咱们建议使用金丝雀模式来测试新技术或模式,前端工做组的开发也是基于这种形式来进行的。因为它是独立的,因此它很容易就能回滚到以前的版本。

这样对提案也颇有帮助,由于咱们能够判断团队是否真的喜欢使用 TypeScript。

固然,可能还会有一些别的担心。

  • 构建时间如何?

关于构建时间上的担忧,咱们测过了,发现并无明显的影响。

  • eslint rule 如何处理?

在咱们主仓库中启用了超过 500 条的 eslint 规则,配合 @typescript-eslint/parser 使用。

  • 弃用策略如何?

咱们很高兴的发现它们中的大多数都能工做,因此若是咱们未来咱们要弃用 TypeScript 的话,咱们能够剥离类型,最后获得大体相同的 JS 代码。

因此咱们逐一记录、思考、跟进,而且针对提出的问题和担心找到解决方法。与质疑的人合做并听取他们的意见对咱们来讲很是重要。

最后这些质疑的人大部分都转向来支持咱们,咱们的提案也由于他们的反馈变得更加健壮。

在充分解决了这些问题以后,针对全部前端工程师咱们又作了份《咱们是否应该采用 TypeScript?》的调查。结果如图

在收到确定的回答后,咱们有足够的证据向前推动,并经过这项提案。

5、渐进式迁移

在此基础上,咱们逐步扩大了采用范围。

此时,咱们已经度过了 Pilot 试验阶段,这对于验证 TypeScript 和打好基础是颇有用的。

咱们已经解决了早期的矛盾,并改进了工具和文档,因此以后的团队成员会更容易入门。

咱们一直都与使用 TypeScript 的团队保持着联系,并帮助他们解决一些问题,好比更好的默认属性优先级处理。

在这个阶段,咱们内部的 TypeScript 社区也获得了发展,但大部分 Airbnb 的员工还不知道 TypeScript,这意味着更多的人能够去帮助和回答他们的问题。

接下来,咱们会进入到 Beta 测试状态。

团队能够选择使用它,为了帮助团队,咱们建立了内部文档和风格指南,并举办了一些学习课程。

咱们建了一些聊天组,内部的 Stack Overflow 组、谷歌 Email 主题小组、GitHub 组等,供组内成员交流,咱们想确保人们能获得他们须要的帮助。

最后一步是将 TypeScript 彻底普及化。

此时就意味着它是稳定状态,每一个人都应该开始使用它, 咱们目前正在努力地去接近这个目标。

剩下的步骤就是巩固风格指南、文档、增强内部培训和迁移更多代码。

到目前为止,咱们大约有 50% 的团队使用 TypeScript,在主仓库中,有 10% 的文件已经被转换成 TypeScript。经过这种渐进的方法,使团队迁移至 TypeScript 的过程更加顺畅。

若是从第一天开始就要求每一个人应该使用 TypeScript, 那么接下来的每一个人都会遇到一样的问题。

相反,咱们先在小范围内使用 TypeScript ,而后总结一些经验技巧,当咱们进行大规模推广时,这些经验技巧也会用得上。

6、迁移策略

咱们已经探索出了几种将代码迁移至 TypeScript 的方式。

一、混合使用

咱们最初的迁移策略的是混合使用 JS/TS。

让咱们来看看,在主仓库中这个策略是如何进行的。

这是我在 airbnb.com 上找到的一个简化版本,而且给它们起了一个比较合理的名字, 因此这里不存在公司的隐私信息。 让咱们放大 homes 项目,看看使用混合策略转换它会是什么样子。

咱们添加了一个 TypeScript 配置文件,并将各个文件从 js 重命名为 ts,或 jsx 重命名为 tsx。

TypeScript 报错了,那咱们动手去修复他们吧。

TypeScript 的一个很棒的特性是,在编译和运行以前,并不须要转换全部代码。这个配置选项(allowJS)容许 JS 和 TS 文件共存,在这一点上,咱们能够看到网站仍能继续运行。

咱们不须要暂停开发而去迁移整个项目,咱们能够一步步来,咱们能够挨个迁移文件。咱们会重复这个过程,直到整个项目被迁移。

二、迁移技巧

在关于迁移的话题上,我想花些时间和你们分享一些咱们认为有用的技巧。

  • any 大法

第一个是 $TSFixMe,咱们经过 TypeScript 的 any 类型添加了一个全局类型别名,这意味着它能够为任何类型。

咱们将它称之为 $TSFixedMe,代表在代码向 TypeScript 迁移完成后,再来将类型修正。

平时最佳实践是避免使用 any,由于它会形成类型安全丢失,但它在迁移过程当中会颇有帮助。

  • @ts-ignore 注释

使用 @ts-ignore 注解能够作到忽略下一行错误。

正确地输入一个文件可能涉及一些深层依赖链解析 — 相似于复杂对象。

咱们能够尝试经过首先转换子文件来避免这种状况,但有时这是不可避免的。

所以,$TSFixedMe@ts-ignore 注释可以帮助拆分这些内容,同时则会增长这些检查工做。

这些都是暂时的,咱们计划添加类型覆盖工具,在咱们后面作类型改进时提供帮助。

  • 类型组合

在 JSX 中,咱们在 React 组件上使用 propTypes 进行运行时类型检查。

在将 jsx 转换为 tsx 的时候,咱们能够删除 propTypes 直接用 TypeScript,也能够在 propTypes 基础上添加 TypeScript。

在咱们所分享的 React 项目中,咱们想保留传参类型,以便别人使用的时候仍然能够得到运行时检查。

为了不重复两次类型声明,那就须要与这些类型保持同步。咱们建立了一个 Props 类型,经过它将给定的 propTypesdefaultProps 来派生出一个 TypeScript 类型。

这样,propTypesdefaultProps 组合并获得这个最终类型,如图

若是你好奇它是如何工做的,你能够查看我在 git 上分享的 代码片断

三、All-in TS 策略

最近咱们已经在使用 修订迁移策略 All-in TS 进行实验, 让咱们回过来再看看这个 homes 项目,而后对它们进行使用 All-in 策略,而后在看它工做怎么样。

咱们从 JS 形式的文件开始,咱们把全部的文件都改为TS形式的。

而后让项目编译,可能咱们使用一些比咱们想要的更宽松的类型,但其实咱们已经开启了TS最严格的检查配置。

而后咱们接下来再继续改进类型,移除 $TSFixedMe 以及 @ts-ignore 语句,这与 JS/TS 混合策略相比起来有一些优点。

经过类型逐步改进比经过文件逐步改进更为简单(两种策略的对比)。

若是你正在开发一个新功能,你只须要关注新添加的类型,而后简单的修复这个它便可。而不是先转换整个文件来修复全部错误,而后再添加你所须要类型。

不用重命名文件也意味着更方便查看。

有时候,若是一个文件在一次提交时被重命名,而后在别的提交中修改。他们会在 code review 中单独出现,程序员必需要合在一块儿看才能知道变化了什么。

后一种策略还能清楚地知道缺乏哪些类型。

TypeScript 类型推导能力十分强大,咱们能够在编写代码的时候大量使用它。为了经过编译,有些文件须要对 TS 作一些调整,TS 就能够推断出剩余部分。

还有就是开发者们可能有一个固定的思惟模式,他们并不会根据文件扩展名来切换思惟。

因而就出现了:为何我不能在这里添加类型?为何我不能在那里获得编译错误的疑问(JS/TS 混用)?之类的问题。 那些类型在全部文件中均可以添加、使用、检查。

四、大型项目迁移策略(AST)

译者注:若是有小伙伴想更多的了解 AST,能够参考我以前的文章《AST 与前段工程化实战》

上面的方案听起来都很不错,可是咱们该如何迁移咱们整个代码呢?

对于大规模代码修改而言,Codemods 是一种十分强大的工具。

拿最简单的形式来讲,就比如是咱们在咱们的项目中所使用的全局搜索和替换,你也许在你以前的 IDE 里面干过这件事

这些 Codemod 库能够经过正则来替换,但它们很不稳定,可能会因细微的代码风格变化而终止。

或者咱们可使用以前某人已经讲过的抽象语法树。

这就是这段代码用 AST 来表达的形式。从上图能看到,左侧的代码都一一对应着右侧抽象语法树上的节点,因此为了好玩,咱们想写一个 Codemod 来反转代码中的全部标识符。

咱们将咱们的代码做为输入参数, 根据这个建立出 AST, 修改 AST 而后产生新的代码。

这里的关键是咱们以编程方式进行此更改。若是你手上须要修改的文件数并很少的话,咱们能够一个个的去修改, 但若是一旦文件数量达到数千个以上,这种手动去修改的想法可能会使人感到十分心累。

所以咱们 Airbnb 采用了 Facebook 的 jscodeshift 来进行这种大量的代码重构,这个转换库能够捕获咱们刚刚对该 AST 进行的修改而且反转标识符。

咱们找到与标识符对应的全部节点,用名字反转,用新节点去替换这些节点,而后获得新的代码。如图

Missy Elliott(歌手)也将会咱们感到自豪,因此咱们反转了它。你们笑了,很棒!

我在演讲就像 Joy Division 作的那样,咱们拿到了代码而且从新改装,找到了成员的标识符而后翻转它。(这段分享者直接现场唱起了 Rap,手动扣 6)

AST explorer 这个网站没法帮你掌握好说唱技巧,但能够帮助你查看你的 Codemods。

在这个网页下,它有一个能够经过源代码输出对应的 AST 的功能,以及在你对代码的改变同时反映到AST树上。

我也在 DefinitelyTyped 提交了关于 jscodeshift 的 PR,这样的话能够来下降你们在使用 TypeScript 与 Codemod 的交互门槛。

五、方案总结

在将 JavaScript 代码迁移到 TypeScript 时,有这几种模式。

对于 React 组件,咱们一次次的将静态类属性移动到 class body里面。建立一个 PropsType 表示 React 生命周期方法。

咱们将它们编码为Codemod,以便咱们能够在更多代码上重复运行它们。

咱们经过使用一个叫做 TS Migrate 的工具来将它们进行打包,这个工具的功能是传入一个 JS 项目,而后获得一个编译好的 TS 项目。

随着时间的推移,你仍然须要慢慢找到类型,但它为你提供了一个工做前提。

咱们将此工具应用于咱们的内部公共的 React 组件库,如今在咱们的网站上已经频繁地使用。

咱们有内部的类型定义库(DefinitelyTyped),可是由于 React 公共组件库的快速发展,因此作到与时俱进地更新太难了,因此,咱们想直接从源码类型出发,这也是咱们迁移 TS 的第一个目标。

咱们已经将超过 3W 行以上的代码都作了 TypeScript 化。

大家可能认为咱们整个团队花了四周的时间才能完成这个。事实上,咱们用了一套咱们本身的 Codemod 工具,仅需数分钟就完成了。

咱们使用来自 propTypes 的类型信息,同时使用 $TSFixMe,并基于此来继续进行优化。

但即使如此,咱们也生成了有意义的 TS 声明文件,这样咱们能够在其余仓库中进行使用。

在这个例子中,咱们能够看到须要合并的代码行数多的有点可怕。

经过使用TypeScript编译器以及在可视化回归测试的帮助下,咱们将在 CI 上运行测试。

经过这些测试我能够很自信的说,个人这些改变不会对原来的系统产生任何不利的影响,固然咱们还能确保咱们的站点仍旧在正常工做。并不须要回滚代码,难以想象吧。

咱们如今已经将 TS Migrate 运用在其它的一些地方,同时也在不断优化和迭代它。咱们计划在之后会将它运用于更多的 JS 代码上。

咱们打算以后将它开源,这样大家也能将它运用在大家的本身的代码迁移上。

7、总结

感谢大家听我讲了这么久, 我想给你一些咱们能够从 TypeScript 迁移中得出关键点,而且是能够普遍应用的。

在大型组织中实施变革多是一项挑战,但强有力的事实依据和相关问题和担心的解决,可使咱们信服。

采用逐步变化的方式有助于减小摩擦并证实其价值。

一条明确的迁移路线能帮助团队更好的转向新的模式,同时好的工具也能促进这个过渡的过程。

我之因此开始这个工做,是由于以前有个产品组对个人工具感到失望。当我得知公司内部其余人也有这种改变的想法的时候,我便与他们合做并将之进行下去。

与其怨天尤人不如接受现状,只有经过行动才能发生积极的改变。

因此我鼓励你去追求那些可让你对组织充满激情的事情,让你和你周围的人的生活变得更好。

感谢你们的倾听,同时感谢 AirBnb 为这个项目做出贡献的每个人,尤为是台下的 Joe 和 Mohsen。还有对其余一些优秀的 Airbnb 工程师表示感谢。

感谢你们的倾听。

相关文章
相关标签/搜索