50万奖金+官方证书,深圳国际金融科技大赛正式启动,点击报名 了解详情
写点什么

花了四年迁移到 TypeScript,我们总结出了这些经验教训

  • 2019-12-16
  • 本文字数:3475 字

    阅读完需:约 11 分钟

花了四年迁移到TypeScript,我们总结出了这些经验教训

四年多以前,一家名为 Heap 的创业公司开始使用TypeScript取代CoffeeScript。尽管公司内部的工程师普遍都很喜欢 TypeScript,但迁移的速度还是很慢,当时也没有一条明确的途径可以实现 100%的 TypeScript 代码库。本文是 Heap 公司在迁移过程总结出的经验教训,希望对广大开发者有所帮助。



实际上,如果说我们的目标是完全切换到 TypeScript 上,彼时我们却走在了错误的道路上。我们当时正在添加 TypeScript 代码,但我们添加 CoffeeScript 代码的速度却更快。TypeScript 和 CoffeeScript 的目标都是同一个 Node.js 运行时,我们希望这个运行时可以简化过渡工作,虽然大家都在期待转型,但我们却并没有积累那么多动力,我们也没有向着彻底抛弃 CoffeeScript 的未来前进。


在 2019 年初,我们又一次开始了从 CoffeeScript 切换为 TypeScript 的努力。这一次,我们决定让迁移工作恢复生机,这需要我们重新考虑转换现有代码的策略。在这样的理念引导下,我们有了一套新的指导原则。我们依照这些原则,将一个看似棘手的难题变成了一个易于管理、易于理解的过程,并设法显著改变下面这些曲线的形状:



那么我们是怎么做到的呢?本文就是我们的经验之谈。

人和技术同等重要

我们重新开始这项工作时最重要的体会就是,成功的迁移必须以人为本,要关注的不只是技术。作为工程师,我们很容易被技术潮流以及(尤其是)迁移的细节所吸引:我们都觉得迁移到 TypeScript 可以增强对代码的信心,并且都非常乐意花费大量时间来精心调整 TypeScript 配置。


事实证明,更重要的因素在于等式中人员的这一侧:我们如何让同事认同这种新范式?这个问题还引发了其他许多疑问。例如:在这个新模型中,我们如何让开发人员干劲十足?为了突出新范式的优势,有哪些障碍或摩擦是可以消除的?


沿着这些问题的思路,我们开发了一种新的迁移流程,并对其感到非常自豪。

开发体验必须明显改善

我们很快意识到,要让整个团队都参与进来,必须让开发人员体会到,他们在编写 TypeScript 时会更有效率。如果团队只是将迁移看作是从一种语法换成另一种差不多的语法,他们永远都不会产生认同感。如果迁移之后他们的日常工作效率并没有提升,那么就算工程师们往往更喜欢编写类型化代码,也敌不过旧习惯的巨大惯性。


我们首先找出代码库中有哪些区域在转换后将带来生产力的大幅提升,因为我们知道,有计划地转换文件比随机转换更具说服力。例如,我们的数据访问层(“ORM”)无处不在,并且大多数文件都会以某种方式来使用它。在数据访问层中引入类型会产生效率层面的乘数效应。今后转换的几乎所有文件都将从类型完善的数据库模型和实用工具中受益。


我们还将工具链和配置作为优先事项来对待。大多数开发人员使用的编辑器就是那么几种而已,因此我们创建了可以直接使用的编辑器配置,添加了调试配置,从而可以轻松设置断点和单步执行代码。


最后,我们整理了一套取得共识的 linting 规则,这些规则使我们能够在整个组织中以统一的样式编写代码,并让开发人员对迁移行动更加满意。


当团队开始看到这些转换工作的成果时,整个项目也就得到了认可,前进动力也会更足了。当我们的工程师开始将类型化数据访问视为必不可少的工具后,他们就能更好地意识到,代码库的其它部分也会平稳地转换完毕。

打破阻碍转换的技术障碍

当我们开始分析 TypeScript 的推广模式时,有一件事情很明显:对我们的工程师来说,使用 TypeScript 并不是一个无缝的过程,他们经常需要导入特殊的实用工具(ts-node/register)或创建 CoffeeScript 中间层文件,仅仅是为了导入这些 CoffeeScript 代码的 TypeScript 等效内容。简而言之,确实存在一个关于互操作的故事,但是它需要大量的样板,并且需要经历太多的尝试和错误才能走上正轨。


这些摩擦点是阻碍迁移的主要因素吗?很难说,但是我们知道,阻力最小的途径是一种强大的力量,如果我们想让人们支持转换,就需要使 TypeScript 成为简单而明显的选择。


为此我们优先做了一些工作,允许开发人员在任何服务或组件中编写 TypeScript。无论是后端、前端、脚本还是 devops 任务,我们都希望工程师能够使用 TypeScript 来编写代码,并使它正常工作。我们最后使用了 NODE_OPTIONS 环境变量与-r ts-node/register,以便现有的工作流(使用 coffee 命令运行 CoffeeScript 文件)能继续运作。

确保转换过程简单、安全和自动化

语言迁移可能会带来风险:CoffeeScript 和 ES6/TypeScript 之间一些看似等效的语法可能根本就不是一回事。开发人员可能会认为转换是重构(或更糟的是重写)的好机会,但这会让迁移工作本来就有的风险雪上加霜。


为了减轻这种风险,我们需要一个规范的流程来转换文件,其不会引入回归,也不会诱导工程师去做多余的事情。这个流程还要能快速执行。


我们确定了一个分为两部分的流程:首先自动转换 CoffeeScript 文件,然后立即手动添加基本类型注解和与 linter 相关的更改。关键在于抵制(不管是什么方式)重构代码的诱惑。这样一来,转换工作就成为了简单、遵循安全规则的机械活动,不会影响运行时行为。


对于初始转换而言,我们使用了将.coffee 文件转换为.ts 文件的脚本。在幕后,我们使用 decaffeinate(https://decaffeinate-project.org/)来从 CoffeeScript 转换为 ES6 JavaScript。由于所有 ES6 JavaScript 在语法上都是有效的 TypeScript,因此我们有了一个正常工作的文件。(我们发现 decaffeinate 是一种非常成熟且可靠的工具。)我们用 Git 历史中的一次独立提交来表示这一步骤。


不过这项工作尚未完成。我们在严格模式下使用 TypeScript,因此“隐式 any”等功能都已关闭。我们利用这个转换窗口为无法进行类型推断的事物创建了类型注解。我们避免在此阶段使用 any,而选择了更严格的 unknown。此阶段的目标是实施不会导致运行时行为变化的更改。我们没有做出任何形式的重构,而只是做了最小限度的工作,来让代码进入准备编译、lint 和通过测试的状态。


如果模块的依赖项已经转换为 TypeScript,则几乎不需要做任何工作:大多数类型是通过导入的模块来处理的。这样最后会产生滚雪球效应,转换的模块越多,转换工作就会变得越来越容易和安全。


第二个步骤也是一次独立提交;这大大简化了代码审核过程,因为在 decaffeinate 的步骤完成之后,审阅者可以轻松地看到所做的更改。


整个流程都记录在一份 TypeScript 转换指南中。Heap 的所有开发人员都可以在最短 5 分钟内,转换一个文件并打开拉取请求将其合并。

给团队成员提问和讨论的去处

应对这种迁移意味着要让你的同事们放弃一种舒适而有效的工作方式。这里的理念是,新方法将带来更多的生产力。但是要达到这一目标需要付出时间和精力。我们最不想看到的是一种失败的转换模式:在这种模式下,开发人员最后会陷入破损的工具、混乱的错误消息以及难以理解的编译器错误的烂摊子中。因此,我们的下一个优先事项是想办法引导整个团队提升专业水平。


为此,我们在 Slack 中创建了一个 #typescript 频道,让遇到困难的开发人员能够获得帮助。推动迁移工作的开发人员可以随时在频道里回答问题,监测常见的问题和障碍。如果同样的问题不断重现,他们就会知道哪些地方应该着重改进。


开发人员需要知道,他们所遇到的任何语言和工具问题都将得到及时解答。我们决定让“TypeScript 冠军”在完成他们自己的工作之前优先处理同事的问题。虽然这减慢了他们的工作进展,但同时也消除了迁移中面临的许多潜在的重大障碍。

追踪进度

从一开始,我们就知道不可能在一夜之间完成迁移任务,并且可能需要一年或更长时间才能完成此过程。这也是很好的:我们认为进步比完美更重要。


我们发现,长时间跟踪我们的工作进展是很有意义的。我们可以观察一段时间内的稳定进展,进而了解我们是否仍在进步。我们使用 Grafana 来可视化代码行数。下面是另一个可视化图像,显示了随时间推移的文件计数:


领导要尊重工程师

不幸的是,在这类项目中取得成功最重要的因素之一是领导是否愿意为你提供执行这些任务的空间。在我们的案例中,迁移项目是自下而上的工作:一开始,我向团队负责人和工程经理提出计划,一旦获得批准,我们就可以自由地找出实现此目标的最佳方法。虽然我们正在讨论的转换将涉及成千上万行代码,但迁移是 100%内部驱动的。


一般来说,这类项目的最佳拥护者往往是那些每天都在使用有问题工具的团队。在 Heap,我们很幸运地遇上了认同这种理念的领导层,他们也认同领导力在对工程师赋权并最终摆脱困境时是非常有意义的。在继续迁移的过程中,我们希望继续学习,并利用这些知识来简化下一个大型项目。


原文链接https://heap.io/blog/engineering/migrating-to-typescript


2019-12-16 15:473951

评论

发布
暂无评论
发现更多内容

【字体反爬】猫X眼YingShi,我们又来欺负你了,用到了 OCR 识别技术

梦想橡皮擦

Python 爬虫 7月月更

业务出海,灵感乍现前要先「把手弄脏」

融云 RongCloud

洞见科技纪凯:隐私计算助力「全链路」金融客户经营

洞见科技

隐私计算

尚硅谷SSM新版视频教程发布

小谷哥

不懂点儿统计学,《星球大战》白看了

图灵教育

统计学 贝叶斯定理

7月《中国数据库行业分析报告》发布!居安思危,安全先行

墨天轮

数据库 腾讯云 阿里云 国产数据库 数据库安全

单元测试,写起来到底有多痛?你会了吗

C++后台开发

网络编程 单元测试 后端开发 Linux服务器开发 C++开发

架构实战营模块七作业

Geek_Q

如何用度量数据驱动代码评审的改善

思码逸研发效能

数据分析 研发效能 科技 效能度量

深圳web前端技术学习费用是多少?尚硅谷前端培训

小谷哥

华为云:一切皆服务,共建全场景智慧金融

极客天地

如何学习好web前端开发技术知识

小谷哥

视频聊天源码——一对一直播系统源码

开源直播系统源码

软件开发 直播系统源码 开源源码

6W+字记录实验全过程 | 探索Alluxio经济化数据存储策略

Alluxio

数据湖 数据膨胀 降本增效 Alluxio 大数据 开源

纯css实现:如何做个完美的平行四边形

南极一块修炼千年的大冰块

7月月更

李宏毅《机器学习》丨4. Deep Learning(深度学习)

AXYZdong

机器学习 7月月更

零基础如何学习大数据开发知识

小谷哥

直播预告 | 7月22日《开源安全治理模型和工具》线上研讨会

安势信息

开源安全 SCA工具 开源软件供应链 SBOM SLSA

商城异地多活架构设计

泋清

#架构训练营

NFT链游戏系统开发元宇宙GameFi搭建

薇電13242772558

dapp NFT 元宇宙

ModuleNotFoundError_No_module_named通俗的解释和方法

和牛

测试

国产操作系统生态建设,小程序技术来帮忙

Speedoooo

小程序 国产操作系统 小程序容器 桌面应用

CSDN Meetup 回顾 丨从数据湖到指标中台,提升数据分析 ROI

Kyligence

数据分析 指标中台

openGauss内核分析:查询重写

华为云开发者联盟

数据库 后端 查询 SQL语言 openGauss内核

TMECH发表优必选运控技术最新进展:实现人形机器人高鲁棒性行走

优必选科技

大数据开发技术入门学习方法有哪些

小谷哥

21条最佳实践,全面保障 GitHub 使用安全

SEAL安全

GitHub 安全

LP流动性质押挖矿系统开发详细程序

开发微hkkf5566

带你认识一下数仓的分区自动管理

华为云开发者联盟

数据库 后端 分区

ES6 类聊 JavaScript 设计模式之创建型模式

devpoint

JavaScript 设计模式 工厂模式 7月月更 创造性模式

如何有效规避代码被“投毒”?

安势信息

许可证 代码安全 开源软件 安全合规检测 开源软件供应链

花了四年迁移到TypeScript,我们总结出了这些经验教训_架构_Luke Autry_InfoQ精选文章