React Native工程中TSLint静态检查工具的探索之路

背景

建立的代码规范没人遵守,项目中遍地风格迥异的代码,你会不会抓狂?

通过测试用例的程序还会出现Bug,而原因仅仅是自己犯下的低级错误,你会不会抓狂?

某种代码写法存在问题导致崩溃时,只能全工程检查代码,这需要人工花费大量时间Review代码,你会不会抓狂?

以上这些问题,可以通过静态检查有效地缓解!

静态检查(Static Program Analysis)主要是以不运行程序的方式对于程序源代码进行检查分析的技术,而与之相反的就是动态检查(Dynamic Program Analysis),通过实际运行程序输入测试数据产生预期结果的技术。通过代码静态检查,我们可以快速定位代码的错误与缺陷,可以减少逐行阅读代码浪费的时间,可以(根据需要)快速扫描代码中可能存在的漏洞等。代码静态检查可以在代码的规范性、安全性、可靠性、可维护性等方面起到重要作用。

在客户端中,Android可以使用CheckStyle、Lint、Findbugs、PMD等工具,iOS可以使用Clang Static Analyzer、OCLint等工具。而在React Native的开发过程中,针对于JavaScript的ESLint,与TypeScript的TSLint,则成为了主要代码静态检查的工具。本文将按照使用TSLint的原因、使用TSLint的方法、自定义TSLint的步骤进行探究分析。

一、使用TSLint的原因

在客户端团队进入React Native项目的开发过程中,面临着如下问题:

  1. 由于大家从客户端转入到React Native开发过程中,容易出现低级语法错误;
  2. 开发者之前从事Android、iOS、前端等工作,因此代码风格不同,导致项目代码风格不统一;
  3. 客户端效果不一致,有可能Android端显示正常、iOS端显示异常,或者相反的情况出现。

虽然以上问题可以通过多次不断将雷点标记出,并不断地分享经验与强化代码Review过程等方式来进行缓解,但是仍面临着React Native开发者掌握的技术水平千差万别,知识分享传播的速度缓慢等问题,既导致了开发成本的不断增加和开发效率持续低下的问题,还难以避免一个坑被踩了多次的情况出现。这时急需一款可以满足以下目标的工具:

  1. 可检测代码低级语法错误;
  2. 规范项目代码风格;
  3. 根据需要可自定义检查代码的逻辑;
  4. 工具使用者可以“傻瓜式”的接入部署到开发IDE环境;
  5. 可以快速高效地将检查工具最新检查逻辑同步到开发IDE环境中;
  6. 对于检查出的问题可以快速定位。

根据上述要求的描述,静态检查工具TSLint可以较为有效地达成目标。

二、TSLint介绍

TSLint是硅谷企业Palantir的一个项目,它是一款可以检查TypeScript代码可读性、可维护性以及功能性错误的静态检查工具,当前许多编辑器(Editors)和构建系统(Build Systems)支持这一工具,同时支持自定义编写Lint规则、配置、格式化等。

当前TSLint已经包含了上百条规则,这些规则构筑了当前TSLint检查的基础。在代码开发阶段中,通过这些配置好的规则可以给工程一个完整的检查,并随时可以提示出可能存在的问题。本文内容参考了TSLint官方文档https://palantir.github.io/tslint/。

2.1 TSLint常见规则

以下规则主要来源于TSLint规则,是某些规则的简单介绍。

TSLint规则示例

2.2 常用TSLint规则包

上述2.1所列出的规则来源于Palantir官方TSLint规则。实际还有多种,可能会用到的有以下:

TSLint规则示例

我们在项目的规则配置过程中,一般采用上述规则包其中一种或者若干种同时配置,那如何配置呢?请看下文。

三、如何进行TSLint规则配置与检查

首先,在工程package.json文件中配置TSLint包:

TSLint规则示例

在根目录中的tslint.json文件中可以根据需要配置已有规则,例如:

TSLint规则示例

其中extends数组内放置继承的TSLint规则包,上图包括了airbnb配置的规则包、tslint-react的规则包,而rules用于配置规则的开关。

TSLint规则目前只有true和false的选项,这导致了结果要么正常,要么报错ERROR,而不会出现WARNING等警告。

有些时候,虽然配置某些规则开启,但是某个文件内可能会关闭某些甚至全部规则检查,这时候可以通过规则注释来配置,如:

/* tslint:disable */

上述注释表示本文件自此注释所在行开始,以下的所有区域关闭TSLint规则检查。

/* tslint:enable */

上述注释表示本文件自此注释所在行开始,以下的所有区域开启TSLint规则检查。

/* tslint:disable:rule1 rule2 rule3... */

上述注释表示本文件自此注释所在行开始,以下的所有区域关闭规则rule1 rule2 rule3…的检查。

/* tslint:enable:rule1 rule2 rule3... */

上述注释表示本文件自此注释所在行开始,以下的所有区域开启规则rule1 rule2 rule3…的检查。

// tslint:disable-next-line

上述注释表示此注释所在行的下一行关闭TSLint规则检查。

someCode(); // tslint:disable-line

上述注释表示此注释所在行关闭TSLint规则检查。

// tslint:disable-next-line:rule1 rule2 rule3...

上述注释表示此注释所在行的下一行关闭规则rule1 rule2 rule3…的检查检查。

以上配置信息,这里具体参考了https://palantir.github.io/tslint/usage/rule-flags/。

3.1 本地检查

在完成工程配置后,需要下载所需要依赖包,要在工程所在根目录使用npm install命令完成下载依赖包。

IDE环境提示

在完成下载依赖包后,IDE环境可以根据对应配置文件进行提示,可以实时地提示出存在问题代码的错误信息,以VSCode为例:

TSLint规则示例

本地命令检查

VSCode目前还有继续完善的空间,如果部分文件未在窗口打开的情况下,可能存在其中错误未提示出的情况,这时候,我们可以通过本地命令进行全工程的检查,在React Native工程的根目录下,通过以下命令行执行:

tslint --project tsconfig.json --config tslint.json

(此命令如果不正确运行,可在之前加入./node_modules/.bin/)即为:

./node_modules/.bin/tslint --project tsconfig.json --config tslint.json

从而会提示出类似以下错误的信息:

src/Components/test.ts[1, 7]: Class name must be in pascal case

3.2 在线CI检查

本地进行代码检查的过程也会存在被人遗忘的可能性,通过技术的保障,可以避免人为遗忘,作为代码提交的标准流程,通过CI检查后再合并代码,可以有效避免代码错误的问题。CI系统可以为理解为一个云端的环境,环境配置与本地一致,在这种情况下,可以生成与本地一致的报告,在美团内部可以使用基于Jenkins的Castle CI系统, 生成结果与本地结果一致:

TSLint规则示例

3.3 其他方式

代码检查不止局限上述阶段,在代码commit、pull request、打包等阶段均可触发。

  • 代码commit阶段,通过Hook方式可以触发代码检查,可以有效地将在线CI检查阶段强制提前,基本保证了在线CI检查的完全正确性。
  • 代码pull request阶段,通过在线CI检查可以触发代码检查,可以有效保证合入分支尤其是主分支的正确性。
  • 代码打包阶段,通过在线CI检查可以触发代码检查,可以有效保证打包代码的正确性。

四、自定义编写TSLint规则

4.1 为什么要自定义TSLint规则

当前的TSLint规则虽然涵盖了比较普遍问题的一些代码检查,但是实践中还是存在一些问题的:

  1. 团队中的个性化需求难以满足。例如,saga中的异步函数需要在最外层加try-catch,且catch块中需要加异常上报,这个明显在官方的TSLint规则无法实现,为此需要自定义的开发。
  2. 官方规则的开启与配置不符合当前团队情况。

基于以上原因其他团队也有自定义TSLint的先例,例如上文提到的tslint-microsoft-contrib、tslint-eslint-rules等。

4.2 自定义规则步骤

那自定义TSLint大概需要什么步骤呢,首先规则文件根据规范进行按部就班的编写规则信息,然后根据代码检查逻辑对语法树进行分析并编写逻辑代码,这也是自定义规则的核心部分了,最后就是自定义规则的使用了。

TSLint规则示例

自定义规则的示例直接参考官方的规则是最直接的,我们能这里参考一个比较简单的规则”class-name”。

“class-name”规则上文已经提到,它的意思是对类命名进行规范,当团队中类相关的命名不规范,会导致项目代码风格不统一甚至其他出现的问题,而”class-name”规则可以有效解决这个问题。我们可以看下具体的源码文件:https://github.com/palantir/tslint/blob/master/src/rules/classNameRule.ts。

然后将分步对此自定义规则进行讲解。

TSLint规则示例

第一步,文件命名

TSLint规则示例

规则命名必须是符合以下2个规则:

  1. 驼峰命名。
  2. 以’Rule’为后缀。

第二步,类命名

规则的类名是Rule,并且要继承Lint.Rules.AbstractRule这个类型,当然也可能有继承TypedRule这个类的时候,但是我们通过阅读源码发现,其实它也是继承自Lint.Rules.AbstractRule这个类。

TSLint规则示例

第三步,填写metadata信息

metadata包含了配置参数,定义了规则的信息以及配置规则的定义。

  • ruleName 是规则名,使用烤串命名法,一般是将类名转为烤串命名格式。
  • description 一个简短的规则说明。
  • descriptionDetails 详细的规则说明。
  • rationale 理论基础。
  • options 配置参数形式,如果没有可以配置为null。
  • optionExamples 参数范例 ,如没有参数无需配置。
  • typescriptOnly true/false 是否只适用于TypeScript。
  • hasFix true/false 是否带有修复方式。
  • requiresTypeInfo 是否需要类型信息。
  • optionsDescrition options的介绍。
  • type 规则的类型。

规则类型有四种,分别为:”functionality”、”maintainability”、”style”、”typescript”。

  • functionality : 针对于语句问题以及功能问题。
  • maintainability:主要以代码简洁、可读、可维护为目标的规则。
  • style:以维护代码风格基本统一的规则。
  • typescript:针对于TypeScript进行提示。

第四步,定义错误提示信息

TSLint错误信息

这个主要是在检查出问题的时候进行提示的文字,并不局限于使用一个静态变量的形式,但是大部分官方规则都是这么编写,这里对此进行介绍,防止引起歧义。

第五步,实现apply方法

apply主要是进行静态检查的核心方法,通过返回applyWithFunction方法或者返回applyWithWalker来进行代码检查,其实applyWithFunction方法与applyWithWalker方法的主要区别在于applyWithWalker可以通过IWalker实现一个自定义的IWalker类,区别如下:

TSLint

其中实现IWalker的抽象类AbstractWalker里面也继承了WalkContext

TSLint

而这个WalkContext就是上面提到的applyWithFunction的内部实现类。

TSLint

第六步,语法树解析

无论是applyWithFunction方法还是applyWithWalker方法中的IWalker实现都传入了sourceFile这个参数,这个相当于文件的根节点,然后通过ts.forEachChild方法遍历整个语法树节点。

这里有两个查看AST语法树的工具:

  • AST Explorer: https://astexplorer.net/
    对应源码: https://github.com/fkling/astexplorer
  • TypeScript AST Viewer: https://ts-ast-viewer.com/
    对应源码: https://github.com/dsherret/ts-ast-viewer

AST Explorer

优点:

在AST Explorer可以高亮显示所选中代码对应的AST语法树信息。

缺点:

  1. 不能选择对应版本的解析器,导致显示的语法树代码版本固定。

TSLint

  1. 语法树显示的信息相对较少。

TSLint

TypeScript AST Viewer

优点:

  1. 解析器对应版本可以动态选择:

TSLint

  1. 语法树显示的信息不仅显示对应的数字代码,还可为对应的实际信息:

TSLint

每个版本对应对kind信息数值可能会变动,但是对应的枚举名字是固定的,如下图:

TSLint

从而这个工具可以避免频繁根据其数值查找对应信息。

缺点: 不能高亮显示代码对应的AST语法树区域,定位效率较低。

综上,通过同时使用上述两个工具定位分析,可以有效地提高分析效率。

第七步,检查规则代码编写

通过ts.forEachChild方法对于语法树所有的节点进行遍历,在遍历的方法里可以实现自己的逻辑,其中节点的类为ts.Node

TSLint

其中kind为当前节点的类型,当然Node是所有节点的基类,它的实现还包括StatementExpressionDeclaration等,回到开头这个”class-name”规则,我们的所有声明类主要是class与interface关键字,分别对应ClassExpressionClassDeclarationInterfaceDeclaration, 我们可以通过上步提到的AST语法树工具,在语法树中看到其为一一对应的。

TSLint

在规则代码中主要通过isClassLikeDeclarationisInterfaceDeclaration这两个方法进行判断的。

TSLint

其中isClassLikeDeclarationisInterfaceDeclaration对应的方法我们可以在node.js文件中找到:

TSLint

TSLint

判断是对应的类型时,调用addFailureAtNode方法把错误信息和节点传入,当然还可以调用addFailureAtaddFailure方法。

TSLint

最终这个规则编写结束了,有一点再次强调下,因为每个版本所对应的类型代码可能不相同,当判断kind的时候,一定不要直接使用各个类型对应的数字。

第八步,规则配置使用

完成规则代码后,是ts后缀的文件,而ts规则文件实际还是要用js文件,这时候我们需要用命令将ts转化为js文件:

tsc ./src/*.ts --outDir dist

将ts规则生成到dist文件夹(这个文件夹命名用户自定),然后在tslint.json文件中配置生成的规则文件即可。

TSLint

之后在项目的根目录里面,使用以下命令既可进行检查:

tslint --project tsconfig.json --config tslint.json

同时为了未来新增规则以及规则配置的更好的操作性,建议可以封装到自己的规则包,以便与规则的管理与传播。

总结

TSLint的优点:

  1. 速度快。相对于动态代码检查,检查速度较快,现有项目无论是在本地检查,还是在CI检查,对于由十余个页面组成的React Native工程,可以在1到2分钟内完成;
  2. 灵活。通过配置规则,可以有效地避免常见代码错误与潜在的Bug;
  3. 易扩展。通过编写配置自定义规则,可以及时准确快速查找出代码中特定风险点。

TSLint缺点:

  1. 规则的结果只有对与错两种等级结果,没有警告等级的的提示结果;
  2. 无法直接报告规则报错数量,只能依赖其他手段统计;
  3. TSLint规则针对于当前单一文件可以有效地通过语法树进行分析判定,但对于引用到的其他文件中的变量、类、方法等,则难以通过AST语法树进行判定。

使用结果及分析

在美团,有十余个页面的单个工程首次接入TSLint后,检查出的问题有近百条。但是由于开启的规则不同,配置规则包的差异,检查后的数量可能为几十条到几千条甚至更多。现在已开发十余条自定义规则,在单个工程内,处理优化了数百处可能存在问题的代码。最终TSLint接入了相关React Native开发团队,成为了代码提交阶段的必要步骤。

通过团队内部的验证,文章开头遇到的问题得到了有效地缓解,目标基本达到预期。TSLint在React Native开发过程中既保证了代码风格的统一,又保证了React Native开发人员的开发质量,避免了许多低级错误,有效地节省了问题排查和人员沟通的成本。

同时利用自定义规则,能够将一些兼容性问题在内的个性化问题进行总结与预防,提高了开发效率,不用花费大量时间查找问题代码,又避免了在一个问题上跌倒多次的情况出现。对于不同经验的开发者而言,不仅可以进行友好的提示,也可以帮助快速地定位问题,将一个人遇到的经验教训,用极低的成本扩散到其他团队之中,将开发状态从“亡羊补牢”进化到“防患未然”。

作者简介

家正,美团点评Android高级工程师。2017 年加入美团点评,负责美团大交通的业务开发。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/479238.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

做一个好的搜索引擎有多难

文|见鹿知乎本文已获作者授权,禁止二次转载前言搜索引擎是个极其复杂的系统工程,搜索引擎上并不会大力出奇迹,需要一点点打磨。在搜索引擎上,q-u相关性计算是基础,但仍需要考虑其他很多因素,其中…

Android官方开发文档Training系列课程中文版:分享简单数据之添加简单的分享行为

原文地址:http://android.xsoftlab.net/training/sharing/shareaction.html 从Android4.0开始,使用ActionProvider可以更方便的在ActionBar上实现一个有效的、用户友好的分享按钮。一个ActionProvider一旦依附到了ActionBar的菜单条目上,它会…

开源开放 | OpenKG组织发布第二批并更新近十个新冠知识图谱开放数据集

2020年2月11日,世界卫生组织宣布了新型冠状病毒肺炎官方正式命名为 COVID-19,21日国家卫健委决定与世界卫生组织保持一致,中文名称不变。随着关于新型冠状病毒病毒疫情的不断发展,有关疫情的各类信息也在不断更新。OpenKG 紧随疫情…

事件抽取中的“门面技术”:事件名称生成浅谈

6月10日,“网信中国”微信公众号发布消息称:微博热搜榜、热门话题榜暂停更新一周,这使得很多热榜平台都受到波及,而在吃瓜之余,我们更进一步地思考热点榜单以及热点名称生成背后的技术,并发出两连问&#x…

保障IDC安全:分布式HIDS集群架构设计

背景 近年来,互联网上安全事件频发,企业信息安全越来越受到重视,而IDC服务器安全又是纵深防御体系中的重要一环。保障IDC安全,常用的是基于主机型入侵检测系统Host-based Intrusion Detection System,即HIDS。在HIDS面…

LeetCode 1154. 一年中的第几天

1. 题目 给你一个按 YYYY-MM-DD 格式表示日期的字符串 date,请你计算并返回该日期是当年的第几天。 通常情况下,我们认为 1 月 1 日是每年的第 1 天,1 月 2 日是每年的第 2 天,依此类推。每个月的天数与现行公元纪年法&#xff…

数据有偏差,照样能学对!20年前就有这么强的算法了?

文 | 白鹡鸰给小铁比了个心编 | 小轶背景“每个人都依赖自己的知识和认知,同时又为之束缚,还将此称为现实;但知识和认识是非常暧昧的东西,现实也许不过是镜花水月——人们都是活在偏见之中的,你不这样认为吗&#xff1…

论文浅尝 | 基于图卷积网络的跨语言图谱实体对齐

论文笔记整理:谭亦鸣,东南大学博士生,研究兴趣:知识图谱问答本文提出了一种基于图卷积网络的跨语言实体对齐方法,通过设计一种属性 embedding 用于 GCN 的训练,发现GCN能同时学习到特征 embedding 和属性 e…

大众点评搜索基于知识图谱的深度学习排序实践

1. 引言 挑战与思路 搜索是大众点评App上用户进行信息查找的最大入口,是连接用户和信息的重要纽带。而用户搜索的方式和场景非常多样,并且由于对接业务种类多,流量差异大,为大众点评搜索(下文简称点评搜索)…

论文浅尝 \ 联合知识图谱实例和本体概念的通用表示学习

论文笔记整理:周虹廷,浙江大学研究生。研究方向:知识图谱,图表示学习等。论文链接:http://web.cs.ucla.edu/~yzsun/papers/2019_KDD_JOIE.pdf本文是发表在KDD 2019上的关于知识图谱表示学习的论文。现有知识图谱表示模…

手握顶会顶刊论文,自信满满面试算法岗竟被刷?

2020国内深度学习框架领域百花齐放。各大公司也都陆续推出了自己的框架,大大推动了深度学习的发展。深度学习俨然已经渗入到我们生活中的每个角落,给生活带来极大便利。深度学习能够针对生产生活所面临的复杂问题,给出高准确率、操作简易、成…

LeetCode 110. 平衡二叉树(二叉树高度)

1. 题目 给定一个二叉树,判断它是否是高度平衡的二叉树。 本题中,一棵高度平衡二叉树定义为: 一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。 示例 1: 给定二叉树 [3,9,20,null,null,15,7]3/ \9 20/ \15 7 返回 true 。…

人物志 | 美团技术委员会前端通道主席洪磊:爱折腾的斜杠青年

洪磊,2013年加入美团,目前是美团外卖事业部终端组的负责人,也是美团技术委员会前端通道主席。在加入美团之前,洪磊的职业生涯可以用“跌宕起伏”来形容。他就读于中南财经政法大学,曾任职于雅虎中国,先后担…

论文浅尝 | 可建模语义分层的知识图谱补全方法

本文转载自公众号:PaperWeekly。论文作者:蔡健宇,中国科学技术大学,研究方向:知识图谱近些年,知识图谱(Knowledge Graph)在自然语言处理、问答系统、推荐系统等诸多领域取得了广泛且…

美团背后的商业模式是什么?后疫情时代该走向何方?

文 | King James知乎本文已获作者授权,禁止二次转载2020年的疫情,让10年前的一部剧再次进入人们的视线中,那就是《我的团长我的团》传统社区团购和各大互联网巨头都广发英雄帖招聘社区团购的团长,感觉回到了10年前那场“百团大战”…

LeetCode 783. 二叉搜索树结点最小距离(中序遍历)

1. 题目 给定一个二叉搜索树的根结点 root, 返回树中任意两节点的差的最小值。 示例:输入: root [4,2,6,1,3,null,null] 输出: 1 解释: 注意,root是树结点对象(TreeNode object),而不是数组。给定的树 [4,2,6,1,3,null,null] 可表示为下图…

Kubernetes 1.20 版本开始将弃用 Docker,是时候拥抱 Containerd 和 Podman 了!

Kubelet 中对 Docker 支持被弃用,并将在以后的版本中删除。Kubelet 使用一个名为 dockershim 的模块,该模块实现了对Docker的 CRI 支持,在此PR后续版本将删除dockershim。 Kubectl 弃用 --delete-local-data 参数。 名词解释 上面中提到两个名…

开源开放 | OpenKG 更新发布新冠概念、防控和流行病等多个知识图谱

近日,OpenKG 继续更新发布多个新冠知识图谱,其中包括哈尔滨工业大学构建的新冠概念图谱,武汉科技大学与东南大学联合构建的新冠防控图谱。同时,更新了由 IBM 中国研究院构建的流行病学图谱 V1.1。OpenKG 发布的所有新冠知识图谱都…

客户端单周发版下的多分支自动化管理与实践

背景 目前,互联网产品呈现出高频优化迭代的趋势,需求方希望尽早地看到结果,并给予及时反馈,所以技术团队需要用“小步快跑”的姿势来做产品,尽早地交付新版本。基于以上背景,美团客户端研发平台适时地推行了…

无意中发现了一位清华大佬的代码模版

对于刷题相关的文章,在之前我也推荐过不少,今天在给大家推荐一份算法刷题笔记,这份笔记与以往的刷题有所区别,作者把 Leetcode 一千多道题都进行了系统的整理,并且对于每一道题的代码,都要求 beat 100%。作…