每一行程式碼都有記錄

敏敏發表於2014-02-16

每一行程式碼都有一塊被隱藏了的文件資訊。

下面的程式碼片段不管是誰寫的,其第4行因為某些原因要訪問一個DOM結點的clientLeft屬性,但卻對結果不作任何處理。這十分的莫名其妙,你能告訴我他們為什麼要這樣做嗎?以後改變或移除這個呼叫安全嗎?

即使曾有人像我一樣給你貼過該段程式碼,你可能還是不知道誰寫的這行程式碼,他們的用意是什麼,有必要繼續保留這行嗎?無論如何,大部分在你致力於一個專案時,你一般會通過版本控制系統訪問它的歷史。

專案的歷史是其最有價值的記錄

當我們觀察下面這行命令輸出的提交資訊時,一切謎底都揭開了:

Fix animate() for elements just added to DOM

Activating CSS transitions for an element just added to the DOM won’t work in either Webkit or Mozilla. To work around this, we used to defer setting CSS properties with setTimeout (see 272513b).

This solved the problem for Webkit, but not for latest versions of Firefox. Mozilla seems to need at least 15ms timeout, and even this value varies.

A better solution for both engines is to trigger “layout”. This is done here by reading clientLeft from an element. There are other properties and methods that trigger layout; see gent.ilcore.com/2011/03/how-not-to-trigger-layout-in-webkit

正如結果所示,這一行—更確切地說,是引進這一行所做的改動—大量記載了有關於為什麼它是必要的,為什麼先前的方法(指的是通過提交SHA)不奏效,哪些瀏覽器受到影響以及進一步閱讀的連結這些資訊。

上面的結果也顯示,這行莫名其妙的程式碼的作者就是我,實際上我有方法將這行程式碼本身寫的更好:通過在函式中用意圖明顯的名字如triggerLayout()封裝magic屬性的訪問,或者至少通過新增觸發動畫這樣一個簡短的解釋作為程式碼註釋。不管什麼原因,我那天就是沒能讓這段特殊的程式碼賦有表達力。這樣的程式碼發生了,就不總是完美的。

即使這段程式碼更具表達力,或者它已經包含了數行程式碼註釋,專案的歷史都能提供更加豐富的資訊:
1. 誰新增的這行程式碼;
2. 他們什麼時候新增的這行程式碼;
3. 哪部分是accompanying test(如果有的話);
4. 完整的提交資訊可以是整部小說(但其中的程式碼註釋應該保持簡潔)。

程式碼質量仍然十分重要。但是在琢磨如何進一步提高你的編碼水平時,你應該考慮完成更好的提交資訊。你不僅僅應該請求你自己,還應該請求整個團隊甚至所有的貢獻者做到這一點。一個軟體的故事與其最新的檢出一樣重要

對專案歷史有效的深層次探索

git blame

我已經在上面的命令中證明了如何使用git blame。當你不能夠訪問本地git庫時,你也可以開啟GitHub上任何檔案的“Blame”檢視。

一個非常有效的探索檔案歷史的方法是使用Vim和Fugitive:
1. 在緩衝區裡使用:Gblame開啟blame檢視;
2. 如果你需要進一步探索,在blame皮膚那行按下Shift-P在那次提交的parent上重新blame;
3. 按下o開啟一個拆分皮膚顯示出blame皮膚當前選中的提交資訊。
4. 在提交分割槽使用:Gbrowse開啟GitHub web介面的commit;
5. 按下gq關閉blame皮膚返回到主緩衝區。

git blame view in vim Fugitive
:help Gblame瞭解更多資訊。

找到一次commit起源的pull request

用git blame你可以獲得每次改動後提交的SHA值,但是提交資訊並不總是攜帶足夠的資訊或上下文來解釋此次改動背後的原因和依據。無論如何,如果專案背後的團隊練習過GitHub Flow,那麼上下文就可能在pull request討論裡找到:

這裡,單次提交的SHA值就足以發現它起源於pull request #42。

git的pickaxe選項-S

有時你會試圖找出已丟失的東西:例如,一個函式過去的某一次呼叫,該函式如今不再被任何地方呼叫。找出是哪次提交引進或刪除某個關鍵字的最好方法就是使用git log的“pickaxe”引數:

利用該方法你可以探索出一些提交資訊,例如刪除了對某個函式的呼叫或新增了某個CSS類名。

git churn

從一個專案的歷史不僅要觀察個人提交資訊,通過整體分析改動集也有可能獲得寶貴的見解。例如,用來包裝git log的git-churn是一個簡單的卻有價值的指令碼,可以彙編統計出哪些檔案改動最多。例如為了看一個app開發中哪個地方在過去的6個月裡受到重點關注:

順便說一下,這樣的分析也強調了在一個專案中因技術債可能出現的潛在問題。經常改動的某個檔案通常標註一個紅旗,因為這可能意味著那個檔案裡的程式碼要麼需要頻繁的修復bug,要麼那個檔案通常承載了太多的任務,應該被分割為更小的單元。

相似的歷史分析方法可以被用於觀察誰近來負責程式碼庫某個部分的開發。例如,為了看誰對一個應用的API部分貢獻的最頻繁:

成為歷史的正面資訊

記住你今天所做的每件事情都會進入專案的歷史並永久儲存在那兒。為了更加善待與你一起工作的其他人(即使它是一個單獨的專案,3個月期限,包括自己在內),在做提交時請遵循下面這些基本規則:

  • 總是編寫提交資訊,好像你在向正坐在你旁邊且完全不知道整個事情緣由的同事解釋此次改動。每個Thoughtbot給出的提示都是為了更好的提交資訊:
    回答下面的問題:
    • 為什麼此次改動是必需的?
    • 它是如何解決問題的?
    • 這次改動有什麼副作用?
    • 考慮包含一個[to the discussion.] 的連結。
  • 避免在一次提交中有不相關的改動。你可能在一個已經做了其它改動的同一個檔案裡發現了一個錯字或做了微小的程式碼重構,但是一定要抵制誘惑與主要的改動一起記錄,除非它們是直接相關的。
  • 在push之前總是清除你的歷史。如果提交還沒有被共享,那麼重新修訂它們中不好的部分是安全的。下面的可能是Faraday專案的永久歷史,但是我最終把它壓縮為僅2次提交,並編輯它們的資訊以隱藏我首次設定指令碼遇到了麻煩這樣一個事實。
    messy git history before rebase
  • 避免不相關改動間的推導:堅持基於行的編碼風格,允許你新增,編輯或刪除列表中的值而不用改動相鄰行。一些例子:

    你為什麼要使用這樣的編碼風格?好吧,總得想想將要git blame這個的人們。在JavaScript的例子裡,如果你要新增一個值“baz”然後提交,當有人blame新增“bar”的行時你不想你的名字呈現把,因為這兩個變數可能不相關。

獎勵指令碼

既然你已經讀到這裡,我將獎勵你一個額外的指令碼。我稱之為git-overwritten,它能夠顯示出指定分支處所改動或刪除的行其原始作者的blame資訊:

當開啟每個GitHub Flow的pull requests時,這是非常有用的;你要是想要你的pull request被同伴審查,但是你可能不太確定該ping誰,使用git-overwritten你可以獲得你剛剛改動程式碼行的原始作者名字,所以你就會知道當開啟一個pull request時@-mention誰了。

相關文章