当前位置: 首页 > 科技观察

使用IDEA代码审查能力保证代码质量

时间:2023-03-14 12:32:22 科技观察

本文转载自微信公众号《BAT的乌托邦》,作者YourBatman。转载本文请联系BAT的乌托邦公众号。前言大家好,我是方同学(你们的蝙蝠侠)。上一篇【方同学】如何高效使用IntelliJIDEA,再次引起了更多读者对IDEA的兴趣。没想到的是一个小小的IDE开发,只是一个工具,甚至和Java语言都没有直接的关系,完全可以写成一个系列。也许它代表了一种态度,一个程序员对工具使用的态度,而不仅仅是代码。图中认识我的朋友可能更清楚。作者近年来一直从事并带领团队从事基础设施和中间件的研发工作。众所周知,编写基础设施代码不同于业务开发。它对代码质量、可靠性、性能以及软件的长期生命力都有更高的要求。本文将与大家分享作者是如何利用IDEA自身的一些能力来审查写好的代码(质量)的。工具是为提高效率而生的,熟练使用对个人乃至团队都有好处。相关栏目BATutopia-IntelliJIDEA相关下载【女娲刀-Initializr项目】访问地址:https://start.yourbatman.cn或http://152.136.106.14:8761Java开发软件包(Mac):https://wangpan。yourbatman.cn/s/rEH0提取码:Javakit程序员专用网盘上线,开启注册送1G超小容量,帮你练减法:https://wangpan.yourbatman.cn版本协议IntelliJIDEA2021.2文字改进代码质量的手段代码作为软件的载体,是软件最重要的组成部分。所以一个软件的好坏很大程度上取决于代码的好坏。或许写几句helloworld的话软件质量还可以,但是随着时间的推移,代码量的增加,需求的变化,团队合作的日益复杂等因素,质量的道路往往会渐行渐远。蓦然回首,是不是觉得自己忘记了初心,却依然砥砺前行?殊不知,代码不通过编译,就万事大吉了。编译只是最基本的保证。大多数程序员都期望写出高质量的代码,对自己的代码质量也有更高的要求。但是一旦遇到赶工的压力,尤其是在deadline之前,你很可能会交出完成度不高的代码,心想“反正会有人帮我检查一下,再说吧”。然而,这些代码就像一个“行走的虫子制造者”,后患无穷。你们领导在网上看到这样的代码,可以说是慌了。既然deadline、deadline这样的“事件”是不可避免的,而且团队中程序员的水平/追求也不一样,那怎么办呢?随着软件行业的发展,涌现出一批又一批的方法论、方法和工具,用于提高软件整体的质量。下面按照离程序员近和远的顺序,从两个方面来简单了解一下。程序员方面——最有效的代码是由程序员编写的,没有人比程序员自己更了解这一点。因此,如果我们能在这方面做好质量控制,是最有效的。俗话说,在离“用户”最近的地方发现问题并解决问题往往是最有效率的。当然,在品控手段上,自然有完整的解决方案。在程序员这边,有一个非常大的优势:可以利用IDE提供的“超级”能力,高效地进行代码审查。IDE通用代码审查什么是通用代码审查?说白了就是和代码格式、方法/变量命名、基本语法合理性等相关,一般的IDE都有这样的能力。比如本文接下来要讲的IDEA代码审查能力就是提供的能力。静态代码检测借助checkstyle、p3c等工具,对代码进行静态检测可以及早发现运行时的很多潜在bug/风险点。静态代码检测对于像Java这样的静态语言非常有效,这就是静态语言的一大优势:健壮性强。对于动态语言(像Python、PHP等)有点力不从心,效果不是很好。以Java为例,像Long.equals(Integer)这样无数人踩过的坑,都可以通过静态代码检测来规避。另外,通过静态代码检测,可以很好地约束代码规范、格式等。值得注意的是,抛开形式不谈,这一点也很重要。很多时候程序有bug,代码格式是原罪。对于一个普通的程序员来说,首要任务是写出人类能看懂的代码,其次才是机器。单元测试单元测试(UT)是指对软件中最小的可测试单元进行检查和验证。那么最小的可测量单位是什么?以Java语言为例,最小的可度量单位是方法/函数。编写一个可单独测试的代码实际上是非常困难的。有工作经验的程序员或多或少都经历过“拒写单元测试”的情况。根据我的经验,这种怕难的根本原因是:不会写,没有什么可“抄”的,毕竟ctrlc+ctrlv是第一生产力,让自己动手吧,没什么。国内的开发环境还处于早期和中期阶段,单元测试普遍没有得到足够的重视。我觉得主要有两个原因:写UT需要一定的时间,国内市场普遍“工期紧”,很少做中长期规划。业务逻辑代码层次不够,耦合严重,导致编写UT代码时工作量剧增,几乎无法单独衡量。久而久之,就很难回头了。当上级终于说要注意代码质量,写单元测试时,他们受到的阻碍将是前所未有的,然后他们就会陷入恶性循环。关于UT,开发者公认的事实:UT是保证代码健壮性的极其有效的手段。根据实际情况,我自己对UT的态度是:尽量不要自上而下推,但要疏。单元测试其实是一门被严重低估的“学问”。往往是领导说写。至于怎么写,领导自己可能不知道,也可能从来没有写过。俗话说,己所不欲,勿施于人,我觉得UT覆盖的问题应该上升到程序的层面,而不是一个字:写。怕困难符合人的本性,是本性的表现。在代码的世界里,你不会觉得难以抗拒。毕竟写UT远没有写业务代码那么“容易”。针对这个问题,可以借助榜样的力量,逐步梳理和渗透。对于个人来说,应该正视困难,追求更高质量的代码。CI/CD端——统一卡点虽然最好在程序员端进行一些质量控制环节,但这种方式高度依赖程序员自身的综合水平和自觉性,可靠性显然不够。所以在实际生产中,需要辅助一些中心化的卡点行为作为保障。CodeReview必须为每个提议的分支(至少在上线之前)通过CR(代码审查)。这个环节比较知名的工具有:Gitlab(商业版)、Fisheye等。集中静态代码检测简单来说就是把你本地的静态代码监控能力搬到云端集中检测。一般可分为全量检测和增量检测。此链接中比较知名的工具有:sonar、cubase等集成测试,对多系统进行集成测试和边界测试。该环节一般属于QA人工干预阶段,与业务逻辑强相关,是最耗时的阶段之一。持续集成流水线工具在软件发布阶段也有一些相应的审查和卡点机制。这个链接比较有名的工具有:jenkins、hudson等。用IDEA回顾你的代码做一个小调查:有多少同学没有用过甚至没见过IDEA的代码菜单?不管你是否见过它,你应该直接或间接使用过它的相关功能。比如这个Generate...自动为JavaBean生成get/set方法、构造函数、hashCode()、toString()等方法。可能你会说现在基本不用lombok了,是的,确实如此。但是,再糟糕,你也用过OverrideMethods和ImplementMethods等功能。毕竟,我不相信你会敲出方法复制、方法实现等模板代码。那么,接下来,我将着重向大家介绍代码菜单。代码审查功能顺便也分享一下作者是如何利用IDEA提供的这些能力来帮助自己,甚至帮助团队改进和保证代码质量的。Codereview相关的功能在Code菜单里(如下图)。两条灰线将这些项目归为一类:以这个示例代码为例回顾一下:packagecn.yourbatman;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;importorg.springframework.boot.autoconfigure。AutoConfigureAfter;@SpringBootApplicationpublicclassApplication{privateStringname;privateStringagee;publicstaticvoidmain(String[]args){SpringApplication.run(Application.class,args);}publicbooleanfun1(booleanbool){returnbool?true:false;}publicStringfun2(Strings){return.toString();}}检查代码...检查你的代码检查:检查,检查。点击确定运行,可以在问题窗口中看到“有问题”的代码:经过审核,问题窗口中指出了本项目中“有问题”的代码。如图所示,IDEA提供了方便的一键处理按钮供您快速处理,非常智能人性化。说到这里,你可能会疑惑:IDEA怎么知道这是难闻的代码呢?你遵守什么规则?显然,一切都是“有法可依”的,就在这里:Settings->Editor->Inspections一般来说Inspections可以保持默认即可。但是我会关掉拼写检查(毕竟英文不是我们的母语,偶尔拼写错误甚至拼音都可以原谅,关掉可以节省一些性能开销)相关关掉:Spelling,TypoNote:InspectCode只会帮你把难闻的代码“抓出来”,改不改的决定权还是你的。代码清理...优化您的代码与检查代码不同,它可以帮助您指出难闻的代码。比较“狠”,直接拿你的代码。如下:执行这个动作不需要征得同意,IDEA会直接修改你的代码。当然,你鸭子不用担心它被搞砸了:它有而且只做相同语义的替换,这使得代码组织更加优雅,不会影响程序的正确执行。Tips:有时候很容易让人看懂,写起来也很优雅。这个时候你就得三思了,有没有必要实现这个功能。分析代码...分析您的代码。它是功能集的总称。Q:为什么这些函数都放在二级目录下?答:相对来说不常用。这是基本的产品设计逻辑:常用的放在一级目录,下层针对不常用功能的SilentCodeCleanup悄悄完成细化你的代码操作,执行结果和CodeCleanup一样.我的用法:我不按名称使用RunInspection。如果你觉得每次运行InspectCode都要遍历所有规则太慢,可以使用这个功能:只运行指定名称的规则。我的用法:基本不用。在目前的微服务开发模式中,每个应用的“体积”都非常小。谁在乎1s和0.5s之间的区别?ViewOfflineInspectionResults离线查看代码分析结果。存在这个功能是因为可以导出问题结果:我的用法:只用过几次。也就是想分享给团队,所以通过导出文件来保留“现场”,这样分享的时候导入的时候方便说明问题。InferNullifyInfer:推断。这个函数的作用是帮助你推断方法参数和返回值:哪些不能为null,哪些可以为null以这个方法为例:publicStringfun2(Strings){returns.toString();}内部调用了s的toString()方法,所以s一定不能为null,可以推导出返回值不能为null。因此,运行IDEA的这个函数后,代码会变成这样:方法签名的语义更加明确用于表达语义,Runtime没有作用。另外,这个函数的正常执行需要这个依赖包:如果没有这个依赖,执行的时候会弹窗提示你添加依赖:这时候点ok会自动帮你添加依赖,很方便。提示:点击确定后,这个框不会消失,但是实际的依赖已经添加好了,所以不要重复点击,否则会重复添加依赖。这是我使用IDEA的一个小bug:没用过。因为我习惯使用更强大的BeanValidation,它不仅语义清晰,而且在运行时生效。LocateDuplicate,顾名思义,帮你定位重复的代码,进行封装和抽象。我的用法:我在审查团队成员代码时经常使用它。搜索结果很有参考价值。推荐使用Dependencies...IDEA把所有的依赖放在Project窗口的ExternalLibraries中,像这样:如果是多模块项目,此时只想查看某一个。对于模块依赖项,您无法通过外部库执行任何操作。这时候查看具体模块的依赖一般有两种方式:通过Maven窗口查看这种方式,对于中小型服务可以解决大部分问题,因为依赖不多,难度也不大定位。但其明显的缺点是不够直观。不可能一眼就看出模块的最终依赖关系。例如,如果某个依赖是间接依赖,那么使用这种方法是非常不直观的;比如在多处引入a.jar,无法一眼看出最终使用的是哪个版本的a.jar。通过这里的Dependencies功能,依赖分析功能非常非常非常强大。它不仅可以帮助你分析每个类(非常细粒度)依赖于哪些库,还可以分析出哪些类依赖于这个项目。这个特性在阅读别人的代码(或开源代码)时非常有用我的用法:更频繁。我在阅读开源代码时经常使用它。通过依赖分析,可以快速把握作者的整体设计意图,视野更全面。BackwardDependencies...上面的功能是检查你依赖了谁,也就是谁依赖了你。Module,CycleDependencies...用于分析本项目模块粒度的依赖关系,是否存在循环依赖等,使用比较简单,不再详细说明。分析堆栈跟踪或线程转储...另一个很棒的工具,我非常喜欢这个工具。字面意思:分析栈,或者内存转储。比如有这样一个场景:线上服务的一个bug抛出异常,在日志文件中留下堆栈信息。面对这样的堆栈信息,如何快速定位到问题代码呢?这时候通常是在这个黑盒子里一行一行的找到“熟悉”的那一行(带行号),然后再回到IDEA中去寻找对应的类。问题定位路径其实挺长的。其实鸭子大可不必这么麻烦。IDEA为我们提供了一个非常有用的分析工具。你只需要:在IDEACode->AnalyzeStackTraceorThreadDump中复制堆栈信息,打开分析窗口,点击ok,控制台中就会显示堆栈信息,和本地调试效果完全一样。这里我演示一下这个函数最简单的使用场景。除了分析这个简单的堆栈,还可以分析dump文件,还可以自定义分析器(比如class文件混淆、加密)等,最终目的是让开发者有本地化的“分析在线问题”的体验。关于该功能的更多使用方法,有兴趣的同学可以在实际使用时自行查找。综上所述,本文主要针对IDEA,主要想输出两个观点:单元测试被低估IDEA的codereview能力被低估作为开发者,人与人之间的差异往往体现在懂多少和懂多少他们知道,知道的和不知道的,毕竟大家的学历和智商大都差不多,多一些,让这些支撑自己,总归是好事。