如何快速识别烂项目
source link: http://www.phodal.com/blog/how-to-quick-analysis-project-levels/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
软件开发是一个非常有意思的复制 + 粘贴活动。开发业务代码的时候,大部分人都不会不加思索地添加代码。毕竟,聪明的产品经理/项目经理们,天才式地想出了用代码行数的方式来计算 KPI,又或者是通过提交次数来进行考核 —— 虽然小步提交是个好东西,但是吧,大部分人不经过练习还是掌握不会的。
最近,我还我的朋友们说到,她们公司的打算强制一天只能提交一次代码。这绝对是代码行数计算 KPI 之后的,又一个伟大地创举式的地发明。如果我有直接颁发诺贝尔奖的权力,我一定给送给他一奖杯。
好了,回到正题。
自上而下的代码分析
最近,刚好因为项目的关系,需要分析某一系统的代码行数。通过一系列的复制 + 粘贴和 Excel 操作,我大致有了一套 DIY 的自动化分析方案:自上而下的代码分析。当然了,这肯定不是我先发明的,在某处一定有论文和代码、工具。只是我依据自己的想法和需求,完善了一下现有的方案。要知道,已经有大量地代码分析工具了。
其实总体的思路非常简单:项目行数 -> 包行数 -> 修改历史 -> 引用分析。
具体来说,就是:
- 通过代码行数(LOC)统计工具,统计总体的代码情况。
- 结合代码行数(LOC)统计工具,统计各个包的代码情况
- 获取 Git 提交历史,统计出经常修改的包或者是类。
- 构建语法树、制品(如 jar)分析,统计出引用次数最多的包。
唯一麻烦的地方就是做一些自动化。所以,这些功能就被我完善到 Coca 里了,笑~。
好了,让我们来看个示例。这里以开源项目 intelli-community (即 IDEA 的社区版)为例。
项目级代码行数
市面上已经有大量的行数统计工具,大家可以自行寻找。这里我用的是 Coca (GitHub:https://github.com/phodal/coca ),集成了三方用 Go 实现的 CLOC 统计功能。
首先呢,我们要实现的是分析整个项目的行数情况 coca cloc .
:
─────────────────────────────────────────────────────────────────────────────── Language Files Lines Blanks Comments Code Complexity ─────────────────────────────────────────────────────────────────────────────── Java 66554 5172301 688054 512630 3971617 603221 Python 10017 424614 31629 34876 358109 22329 Kotlin 6383 602814 89130 35660 478024 51292 Plain Text 4105 635689 5799 0 629890 0 Groovy 3397 154817 23296 12364 119157 4683 XML 2549 494074 10056 3008 481010 0 HTML 2329 63331 2988 3623 56720 0 SVG 2124 21078 23 87 20968 0 JSON 1155 346795 352 0 346443 0 Shell 535 8295 1138 734 6423 811 Markdown 425 9660 1434 0 8226 0 Properties File 384 42069 2545 1348 38176 0 YAML 384 3264 202 55 3007 0 XML Schema 345 196649 17963 0 178686 0 JavaScript 169 30569 1562 5151 23856 3895 ... ─────────────────────────────────────────────────────────────────────────────── Total 101908 8389984 898893 629497 6861594 703260 ─────────────────────────────────────────────────────────────────────────────── Estimated Cost to Develop $288,297,976 Estimated Schedule Effort 132.017220 months Estimated People Required 258.681675 ───────────────────────────────────────────────────────────────────────────────
嗯,从规模上来看,这真的是一个超级大的项目,接近 700 万行的规模。所以,我第一次看到的时候,也不知道从哪里下手,于是我便想着是不是从包(目录)结构能解决这个问题。
PS:Coca 当前只支持单体分析,考虑有多模块和微服务系统的存在,我会在未来必要的时候,添加对应的实现。
按目录分析
简单来说就是,我们可以按目录执行 cloc,然后汇总结构即可。
所以,进一步地我们就可以执行 coca cloc . --by-directory
,得到一个 CSV 数据,根据自己的需要进行编辑:
还可以绘制成图表。
除此,我还提供了一个 --top-file --top-size 10
的参数,以了解行数最多的几个文件。
| LENGTH | COMPLEXITY | LOCATION | |--------|------------|-----------------------------------| | 1642 | 236 | ConstraintLayoutHandler.java | | 1492 | 375 | ConstraintComponentUtilities.java | | 1189 | 166 | CommonActions.java | | 1184 | 325 | ConstraintWidget.java | | 1169 | 129 | SingleWidgetView.java | | 1115 | 213 | ScoutArrange.java | | 1097 | 281 | ScoutWidget.java | | 1081 | 224 | 3d/Rasterize.java | | 1016 | 159 | LayoutlibSceneManager.java | | 1014 | 220 | TimeLinePanel.java |
接着,只需要层层下推,我们就可以分析出哪个是系统最复杂的一部分。如下图中的复杂点,依次是:platforms、java、plugins、android。
变更频次
紧接着,我们就可以通过获取 Git 提交历史来知道,对应文件的修改变化。这里,我依旧使用的是 coca git -t
。它源自于对于 git log --all --date=short --pretty="format:[%h] %aN %ad %s" --numstat --reverse --summary
命令的分析结果,有兴趣的读者可以参考 Coca 的源码,自行编写不同版本地对应实现。
可怕的是,我在 intellij-community 执行了 coca git -t
之后,生成了一个 241M 的文件,回去 GitHub 看了一眼:累计 290,459 次提交。
在我第一次没意识到应该记录下 log 之后,我又重新执行了一遍。最终,拿到了结果:
| ENTITYNAME | REVSCOUNT | AUTHORCOUNT | |-------------------------------------------------------------------------------------------------------------|-----------|-------------| | platform/util/resources/misc/registry.properties | 2473 | 224 | | platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java | 1211 | 149 | | platform/platform-api/resources/messages/IdeBundle.properties | 1209 | 181 | | platform/platform-resources/src/META-INF/LangExtensions.xml | 1206 | 192 | | plugins/InspectionGadgets/InspectionGadgetsAnalysis/resources/messages/InspectionGadgetsBundle.properties | 1113 | 159 | | platform/platform-resources-en/src/messages/ActionsBundle.properties | 1004 | 161 | | platform/platform-resources/src/META-INF/PlatformExtensions.xml | 937 | 162 | | platform/util//src/com/intellij/util/ui/UIUtil.java | 779 | 120 | | platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java | 763 | 133 | | platform/platform-resources/src/META-INF/LangExtensionPoints.xml | 762 | 150 | | platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java | 684 | 126 | | java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java | 675 | 117 | | platform/platform-resources/src/idea/PlatformActions.xml | 671 | 139 |
然后,看一眼 registry.properties
是一个有 1800+ 行的配置文件,EditorImpl.java 是一个有 5000+ 行的 Java 代码,UIUtil.java 也有 3600+ 行……。嗯,效果是不是也相当理想,再看看 UIUtil.java 这一个名字,一看就非常适合重构。
高引用
最后,可能会进入慢的一步,分析代码,生成 AST。考虑到 IDEA Community 的这个代码量。我就不重复演示了,以 GitHub 的示例为例 coca count
:
+------------+--------------------------------------------------------------------------+ | REFS COUNT | METHOD | +------------+--------------------------------------------------------------------------+ | 2 | com.phodal.pholedge.book.BookRepository.byId | | 2 | com.phodal.pholedge.book.model.Book.toRepresentation | | 2 | com.phodal.pholedge.book.BookRepository.save | | 2 | com.phodal.coca.analysis.JavaCallApp.parse | | 2 | com.phodal.pholedge.book.BookRepository.save | | 2 | com.phodal.coca.analysis.JavaCallApp.parse | | 1 | com.phodal.pholedge.book.model.Book.save |
最后,我们又回到了这个模型上。
考虑到 AST 的慢的程度,我已经有一个更好的实现方式。
结论
分析代码是一件很有意思的事情。一番操作下来,能学习到非常有意思的东西。
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK