總是看到有人說,動態一時爽,重構火葬場。然而這世界上有的是著名的開源專案, 也有像 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 種以上的語言,這也無怪乎語言檔案的數量如此之多了。這個結果也可以提醒我們,有些同學——不僅是程式設計師,也包括大多數經驗不足的老闆、客戶、產品經理等——會下意識的認為程式開發無非是寫程式碼,對於程式碼之外的其他工作,在估算的時候往往只拍腦袋式的定下一個極短的時間。但對於實際的專案來說,程式碼僅僅是其中的一部分,“其他工作”有時候——應該說是經常——會佔用你大部分的的時間和精力。這些工作往往並不有趣,但對於專案來說又是必不可少的組成部分,希望同學們予以足夠的重視。