如何科学评估代码复杂度?

原视频地址:Anthony Shaw - Wily Python: Writing simpler and more maintainable Python - PyCon 2019

要想写出更简单易懂、可维护的代码,我们首先当然得知道如何评估代码的复杂度。通过代码行数吗,肯定是不能的,比如下面两断代码,并不能说第二段比第一段更简单、更高级,因为第一段代码的可读性更强,我们一眼就能知道它在干什么。

下面介绍一下更加科学的评估方法。另外你没必要知道具体怎么计算,只要知道大概的意思就行。

评估代码复杂度的科学方案

Cyclomatic complexity(循環複雜度)

维基百科页面:en.wikipedia.org/wiki/Cyclom…

简单来说,Cyclomatic complexity就是一段代码独立路径可能性的总数目。如果没有 if语句、for 循环这些 controll flow 语句,代码就只有一条路径,那么复杂度就是1。如果有一条单条件if语句,复杂度就是2。两条嵌套的 if 语句,复杂度就是3。

维基中还给出了严格的数学定义,把一段代码的控制流程看作是一个图,这里不细讲了。

下面这段代码来自于 Python standard library,有很多个 if 判断,Cyclomatic complexity比较高。

更加形象点,假如我们把代码用一张纸打印出来,然后沿着缩进画一条曲线,如果这条曲线是一条蜿蜒曲折陡峭的山坡的话,那这段代码的Cyclomatic complexity就相对较高。

为什么我们的代码会有这么多 if?

git 可以通过git blame(好形象的指令)查看某段特定的代码究竟是谁写的。很多时候遇到了 bug,修复者为了不 break 之前的代码,往往会加一个 if 条件判断,于是大家你加一个 if,我加一个 if,代码的复杂度就这么提高了。

代码的复杂度就是这么一点一点积累起来的。

就像上面这张图一样。

Halstead Matrix

维基百科页面:en.wikipedia.org/wiki/Halste…

计算公式如下:

比如下面这段 c 代码:

Maintainability 指数

把前面提到的这些组合起来,得到了最终的指数,从0-100分,分为4个等级。

现成的计算工具

randon

github 地址:github.com/rubik/radon

通过pip install radon即可安装。

简单指令:

radon mi path -s
复制代码

这就可以查看此目录下所有 py 文件的Maintainability 指数得分。 我对我的一个项目跑了一下,结果如下:

看起来代码复杂度还很不错嘛。

然后用Cyclomatic complexity指标跑一下:

randon cc path -s
复制代码

这个还会给出具体 block 的得分,我在我电脑上跑了一下,还是找出了一些复杂度较高的代码块。

图中前面的 F 表示的 function 的意思,后面的字母和数字是得分,越高表示复杂度越低。

更多信息看官方文档。

wily

github 地址:github.com/tonybaloney…

注:wily 要求你要分析的代码库是一个 git repository,因为他会分析你的 git 历史代码。

直接通过pip install wily安装。

wily -help

第一步:在代码仓库运行wily build .

耐心等待 wily 分析完成,这会把数据写入到~/.wily/目录。

wily report

wili diff filename

wily graph

wily index

wily pre-commit hooks

pre-commit 如何使用请参考上篇文章:用 pre-commit hook 解决 Python 项目编码规范。

第一次可能会比较慢。

repos:
-   repo: local
    hooks:
    -   id: wily
        name: wily
        entry: wily diff
        verbose: true
        language: python
        additional_dependencies: [wily]
复制代码

总结一下

如果你有一个函数,最开始的时候很简单,随着项目进展,越来越多 edge case 被发现,最后你的函数就会 成为catch所有可能性的 "god class"。上文提到的工具后可以帮助你发现复杂度高的代码块。

如果你像我一样真正热爱计算机科学,喜欢研究底层逻辑,欢迎关注我的微信公众号:

你可能感兴趣的:(如何科学评估代码复杂度?)