原始碼的壽命

oschina發表於2016-03-04

看看你現在日常工作中的程式碼。已經執行了多久了?程式碼有多老了?有六個月?一年?可能都有五年這麼久了吧?十年?二十年呢?!這樣的程式碼有多老了?不到10%?還是一半?亦或者已經有90%了?為了瞭解這些問題的答案,我對程式碼的存活時間做了一些調查。

軟體考古

在已經存在很多年並且已經有自己的一系列原始碼運作的公司裡,編寫軟體就像是類似軟體學考古的一種磨練,深入研究應用就像在挖掘一個古老的城市,逐層的揭開過去種種的面紗。

一旦你開始鑽研一些封裝好的微型服務,就算是已經開始研究過去:也許殘留著有對公司面向服務體系架構的第一個嘗試;現在就是對伴隨著複雜業務邏輯的整體服務並且捆綁了Spring的總結。深入挖掘後我們回到了EJB的時代;由於開發者已經喪失了對它們理解的慾望,一些已經被遺忘好久的beans仍然依附於生活。再往下就是整體系統骨架的地方了。

如果沒有被打破,就不要去修理它

如此糟糕的程式碼是什麼?不用懷疑它帶有如此強烈的目的性。至少有一些是這樣的。

如果你檢視你一年期所寫的程式碼並且發現沒有什麼可以改變的,你這一年算是沒有成長。

我們一直在學習:更好的理解領域,更好的理解領域解決方案,新的架構方式,新的工具,新的方法,新的標準以及新的思路。你一年前的寫程式碼在某些地方可以進行改進這是很正常的,但是,有多少程式碼你回過頭去進行改進了呢?

舊程式碼是會變得越來越難修改的。如果一個業務需求的變更讓你必須回頭修改最原始的EJB,你會怎麼辦?你會去修改你十多年前寫的程式碼嗎?或者花時間去分析其中需要修改的部分?或者乾脆每次都新建一個新的小模組來解決?這些修改的代價是很昂貴的。

而現在的問題是:償還這種“技術債”是正確的事,但是修改以前的程式碼一般都會比你上週寫的或者上個月寫的東西慢。如果以前程式碼應該修改的地方你沒有及時去修改,這將影響你開發新的功能。最糟糕的是我們有時會明明知道有些地方我們做錯了,但是還是保持他長期執行。這些方法在當時我們認為是對的,只是現在看起來是錯了。

我們程式碼的壽命?

我對大量原始碼做過調查,其中包括商業以及開源的,設計各種語言(Java,C#,Ruby)。總體上,這些程式碼都遵循一個相似的規則:

大約70%的程式碼,在你寫後的12個月內一直在使用,沒有發生修改。

也許並不奇怪,程式碼完成之後的頭幾個月改動是最頻繁的。再往後似乎就進入了一種維護模式,改動量變得相對較少。

原始碼的壽命

我發現這玩意兒實在太有趣了:大約75%的程式碼在我完成一年後仍然是原來的樣子。你可以設想一下我現在對於這個問題理解了多少,想像一下那些早就忘掉的設計思想,改變了的架構願景,新的工具和仍能重構使用的庫。想像一下當年寫下的那一行行程式碼在今天又能有多大的改進餘地。而且,在那些仍然遺留著類似技術債的程式碼庫裡,就算我們一直在孜孜不倦地償還,也沒見到老的程式碼新了多少。

我是怎麼做的這項分析?這要歸功於Git的魔力,它使這項分析變得很簡單。只要對整個倉庫做一次git blame的遞迴,就能夠列出針對分支中的每一行程式碼的commit號、提交人、提交時間。配合上一些shell指令碼技巧就能得出每月或每天的統計數字:

git ls-tree -r -rz --name-only HEAD -- | xargs -0 -n1 git blame -f HEAD | sed -e 's/^.* /([0-9]/{4/}-[0-9]/{2/}/)-[0-9]/{2/} .*$//1/g' | sort | uniq -c

按月份統計,截止到今天,以上輸出的這個表格是關於每一行程式碼最近被改動過的時間。不過,我也可以很容易地把時間往前推,比如把時間推到2015年的開始:

git checkout `git rev-list -n 1 --before="2015-01-01 00:00:00" master`

把時間往前推之後,重新遞迴執行一次git blame,通過比較每個月得出的結果,我就能知道有多少程式碼是在2015年之前寫的。經過更加詳細的分析,我也能得出某個月中最新修改的程式碼行數量怎樣隨著時間變化而變化,進而知曉程式碼衰退得有多快(多慢)。

結論

程式碼寫出來無非是為了實現某個意圖,遞送一些商業資料,但很快這就變成一種負債了。年代愈發久遠,原來的程式碼就越腐朽而越難以修改,根據上面的分析,你很容易明白為什麼一個程式碼倉庫能夠存在將近十年之久,裡面的程式碼為什麼都是些老古董:每年的改動量少之又少,它們就是躺在那兒沒人管,自始至終我們就只是在不斷地往裡面新增新的遺產——它們中的大多數即使到了下一個年頭你仍然還是可以找到的。

對於這種情況,我們可以做些什麼?過時的程式碼只會不斷堆積,這似乎就是軟體的自然法則,依我個人經驗來看,即使大家齊心協力對這些程式碼進行重構,似乎也收效甚微。我們還能做些別的麼?或者我們乾脆坦然接受越是年代久遠的程式碼就越難修改的這一事實?還是我們需要找到一個辦法,鼓勵軟體有一個更短的半衰期,以更快地得到重寫。

相關文章