Python 项目可以有多大
总是看到有人说,动态一时爽,重构火葬场。然而这世界上有的是著名的开源项目, 也有像 Github、Instagram 这样流量巨大的知名网站是基于动态语言开发的,经过了这么多年重构,也未听说哪个作者进了火葬场的,不明白这些人是真的不知道还是装作看不见呢?不过他们说动态语言大到一定程度就无法维护,虽然这话也同样不值一驳,不过也提醒了我,我也很好奇用动态语言开发的项目规模能大到什么程度。
从我知道的信息看,用动态语言开发的最大规模的项目可能要算是 OpenStack,据说代码总量已经达到数百万行,并且还在持续增加中。这当然是一个说明动态语言能力的好例子。不过像这样巨大的项目,要分析起来也并不容易(好吧,真正的原因是我懒得下载那么庞大的代码库)。我选择了 Python 社区中比较知名的一些项目来分析,主要是来自 Github ,也有个别来自其他仓库。这个选择可能包含了一定的主观因素在内,不过我相信大多数项目还是非常有代表性的。
计算代码数量的工具是 cloc。所有项目均选择截止到 2018 年 1 月 3 日的主干代码,统计中仅包含 Python 文件,排除了其他文件类型。值得说明的一点是, 通过 Ubuntu APT 默认安装的 cloc 版本 1.60 在统计部分项目的时候存在问题,该问题在最新的版本中已经得到解决,因此本文中所有统计均使用从官网下载的 cloc v1.72。
项目 | 文件 | 空白行 | 注释行 | 代码行 | 代码行/文件 | 注释/代码 | 类型 |
---|---|---|---|---|---|---|---|
Sentry | 1,828 | 32,745 | 16,593 | 698,733 | 409.23 | 2.22% | py,po |
CPython | 1,775 | 106,670 | 132,042 | 496,500 | 414.20 | 17.96% | py,c |
Salt | 2,432 | 158,906 | 248,391 | 486,106 | 367.35 | 27.80% | py,js |
Ansible | 2,641 | 109,406 | 254,073 | 383,396 | 282.80 | 13.41% | py,yaml |
wxPython | 1,611 | 95,293 | 94,784 | 220,420 | 254.81 | 23.09% | py,c |
Django | 1,906 | 50,634 | 48,494 | 219,999 | 167.43 | 15.20% | py,po |
Pandas | 561 | 64,291 | 57,207 | 213,402 | 596.97 | 17.08% | py,html |
Odoo | 2,010 | 31,394 | 37,042 | 158,106 | 112.71 | 16.35% | po,js |
youtube-dl | 830 | 15,343 | 6,666 | 108,276 | 156.97 | 5.12% | py,markdown |
NumPy | 380 | 33,578 | 68,711 | 102,490 | 538.89 | 33.55% | c,py |
PyTorch | 381 | 14,014 | 15,435 | 46,895 | 200.38 | 20.22% | py,cuda |
Django-CMS | 302 | 9,459 | 8,089 | 41,492 | 195.50 | 13.70% | po,py |
Keras | 158 | 9,707 | 13,972 | 37,484 | 387.11 | 22.84% | py,markdown |
Pillow | 267 | 9,064 | 8,733 | 26,348 | 165.34 | 19.78% | py,c |
Scrapy | 340 | 6,800 | 4,106 | 24,874 | 105.24 | 11.48% | py,xml |
Flask | 71 | 3,448 | 3,524 | 8,768 | 221.68 | 22.39% | py,html |
Fabric | 78 | 2,341 | 4,333 | 7,314 | 179.33 | 30.98% | py,yaml |
上表已经按代码行数排了序。有意思的一点是, 代码规模最大的前4名中除了 CPython 之外其他三个全部是运维性质的项目,本来我猜测代码应该比较多的项目比如 Odoo 排名反而很靠后。我对运维项目了解有限,不太清楚为什么这些项目的代码规模会名列前茅,或许是因为要支持的内容比较多而杂?
本次统计中纯 Python 代码量最大的 Sentry 几乎达到了 70W 行,这是相当有规模的项目了。30W~50W 行代码的项目有三个,包括基础项目 CPython 在内。20W 和 10W 行代码规模的分别有三个,剩下 7 个则在 10W 行以内。看过这个列表你应当相信,动态语言至少在几十W行代码的项目上是完全没有问题的。这也是绝大多数普通应用的上限了,如果代码真的达到数百万行规模的话,那么无论用什么语言,都势必面临着拆分项目的问题。
上表将代码量指标按照代码/空白/注释进行了分类,也在一定程度上反应了项目的代码风格。Sentry 是本次统计中代码量最多的项目,然而从表中可以看到,项目中的注释和其他项目相比,少得有点不成比例,说明 Sentry 的作者非常不注重注释。
同学们一定发现了,我在列表中除了代码行相关的指标之外还增加了几个其他内容,这也是我个人比较感兴趣的方面。
第一个指标是每个文件的平均代码行数。按照模块化的观点,单个文件中堆砌太多内容显然是不合理的,这通常意味着耦合太多、难于理解和修改。然而到底多少算是合适,并没有一个明确的标准。我希望通过这些项目的分析,了解一下开源作者们在实践中做出的选择。
统计的结果分布比较平均,从 100~600行/文件的都存在,并不存在明显的集中点。有趣的是,头两名(Pandas, NumPy)有着紧密的联系,都是和数学统计相关的。这可能是因为数学库的特点比较纯粹而单一,不像其他类库那样容易划分。末尾的项目(Pillow, youtube-dl, Odoo, Scrapy)可以从侧面印证这种猜想:它们都是面向特定领域的,所以更加容易模块化。
第二个指标是注释和代码的比例,这个问题也有着类似的情况。注释并非越详尽越好,但总是需要一定量的注释来解释 Why 的问题。注释太少,说明项目的作者没有给后来的维护人员留下足够的线索,可能会造成维护上的问题。另一方面,我们考察的全部是开源项目,没有公司考核或者 KPI 的约束,所以我们可以放心的相信不会存在作者故意多写注释的问题。前面提到的 Sentry 毫无争议的因为注释太少排到了最后,这未必说明这个项目很差,但至少是一个信号,说明该项目在维护方面可能是存在问题的。而对于那些作者愿意投入精力来写注释的项目(Ansible, NumPy, Fabric, Salt 等),足以反映作者在项目上投入了相当大的心力,这是一个好的信号,说明这些项目是值得信赖的。
有一点是出乎我意料的,那就是作为所有项目之母的 CPython 排名比较靠后,按照道理这个基础项目应该有更多的注释才对。不过再想一想又觉得可以理解,因为 CPython 有单独发布的、非常详尽的文档,这是其他大多数项目都没有的,那么代码中的注释少一些也是情有可原的。
最后一项统计是关于文件类型的。Python 项目中绝大多数应该是 Python 代码,这点没有什么疑问,但同时我也想看看除了 Python 代码之外,一个项目还包括哪些主要文件。C/HTML/Javascipt 的上榜是毫不意外的,但有一种文件我事先没有想到,那就是 .PO(开源项目常用的语言资源文件)。对于 Django 和 Django-CMS 这两个项目, PO 代码数量甚至比 Python 代码还要多。大概看了一下,Django 支持 90 种以上的语言,这也无怪乎语言文件的数量如此之多了。这个结果也可以提醒我们,有些同学——不仅是程序员,也包括大多数经验不足的老板、客户、产品经理等——会下意识的认为程序开发无非是写代码,对于代码之外的其他工作,在估算的时候往往只拍脑袋式的定下一个极短的时间。但对于实际的项目来说,代码仅仅是其中的一部分,“其他工作”有时候——应该说是经常——会占用你大部分的的时间和精力。这些工作往往并不有趣,但对于项目来说又是必不可少的组成部分,希望同学们予以足够的重视。