【譯】注釋的藝術

原文地址:css-tricks.com/the-art- 譯者 Github:@elevenbeans 更多內容請見譯者 Blog:github.com/elevenbeans/

我認為注釋代碼十分重要。最主要的是,我認為注釋往往是被誤解的。我之前某天在 Twitter 上說過:「對於是否應該寫注釋,我聽到的意見不一致,但我因為寫這些,從初級開發者那裡得到感謝,所以我會繼續寫下去」。我收到的反饋是多種多樣的,但我看到的是:每個人都同意,寫注釋是必要的,他們都有不同的原因。

注釋是一個比我們所賦予它的功勞更具意義的事情。注釋沒有術語 (也不應該有),但把所有的注釋集中在一起是過於簡單化了。在這個漫畫中回應的例子是真實的:

這就是我認為許多注釋的錯誤觀念之所在。《Clean Code》這本書中,羅伯特 c. 馬丁談到這:注釋不必要,因為代碼應該是自說明的。如果你覺得一個注釋是必要的,你應該重寫你的代碼直至她自說明得更清晰。我既同意,也不同意。在寫注釋的過程中,你的確經常可以找到一些可以寫的更好的地方,但是並不是一個二選一的問題。我可能仍然重寫代碼以自說明得更清楚,同時也可以編寫注釋,原因如下:

代碼可以描述 how,但它不能解釋 why。

這不是一個新的概念,它是一個共同的主題,我已經遇到有用的注釋,她有傳達代碼不能或不能簡潔傳達的東西的能力。

所有這些都在講,沒有一個正確的方法或一個理由來寫注釋。為了更好地學習,讓我們深入研究一些有益的注釋,這些注釋可能都有不同的用途和目的,遵循著一些我們可能想要避免的模式。

好的注釋

  • 為什麼?

許多好的注釋的例子可以放在這個類別下。代碼解釋了您希望計算機採取的操作。您會聽到人們討論聲明性代碼,因為它精確地描述了邏輯,但沒有描述所有步驟,就像一個食譜。它讓計算機去完成重活。我們也可以將我們的注釋寫成一個補充聲明:

/*

We had to write this function because the browser

interprets that everything is a box

*/

這個注釋並沒有描述下面的代碼會做什麼。她沒有描述代碼接下來要執行的動作。但是,如果您找到了重寫此函數的更優雅的方法,您可能會感到有信心這樣做,因為您的代碼可能以不同的方式解決同一問題。

因此,維護成本變得更少了(我們將進一步深入了解這一點)。如果你找到了一個更好的方法來寫這個函數,你可能不需要重寫注釋。您還可以快速了解是否可以重寫另一段代碼,使此函數不再必要,而無需花費很長時間來分析所有步驟弄清楚整個邏輯(即:為什麼存在這個函數)。

  • 澄清一些普通人類無法辨認的東西

當你看一長行的 regex,你能立即理解是怎麼回事?如果你可以,你是少數。即使你可以在這一刻可以理解,但你可能無法在明年這個時候也立即理解。

瀏覽器的 hack 呢?你在你的代碼中見過這個嗎?

.selector { [;property: value;]; }

還有這個呢?

var isFF = /a/[-1]==a;

第一個 CSS hack 的目標是 Chrome ≤ 28,Safari ≤ 7,Opera ≥ 14,第二個是火狐版本 2-3。我寫的代碼需要這樣的東西。為了避免另一個維護者或未來假設我在去上班那天吃了一些葯(頭暈)的時候描述清楚這寫 hack 是為了什麼,這真是極好的。特別是我們可以為:不再需要支持該瀏覽器,或瀏覽器的 bug 修復了做好準備,時刻刪除它。

  • 對你來說清晰易懂的東西不一定對別人清楚

誰聰明?我們!誰寫的代碼乾淨清爽?我們!我們不必注釋, 看它有多清晰!

這種思維方式的問題是:我們所有人都是在各自不同的領域裡有較深的知識。在小團隊中,人們的技能和專業更加接近,由此組成的團隊能力圖要比維恩圖更加圓潤,這比那些經常變動的團隊或者經常納入初級開發者或實習生的大團體的問題少。但我可能還是會為那些新人或未來的你騰出空間。在更大的團隊中,有初級工程師,甚至是來自所有類型背景的工程師,人們可能不會決絕告訴你他們需要你寫注釋,但是當你這樣做的時候,很多人也會表達感謝。

  • 像書的章節一樣注釋

如果這篇文章被寫成一大塊,而不是分成一些空白和較小的標題,它會難以被人瀏覽完。也許不是我說的所有都適用於你。注釋部分或片斷可以允許人們跳到與他們最相關的部分。但你又說,我們現在為此準備了函數式的編程、import 和模塊化(囧)。

是真的!我們把事情分解成更小的部分,這樣它們就更容易管理了,謝天謝地。不過,即使是在較小的代碼段中,您也一定會遇到一個需要長一點的片斷。能夠快速掌握什麼是相關的、找出一個部分的標籤,一點小不同可以加快生產率。

  • 編寫代碼時保持邏輯順暢的指南

這是一個有趣的點!這些不是您保留的注釋,因此也可以在 「壞模式」 部分找到。很多時候,當我在一個更大的項目,有很多動態的部分打破了我下一步行動的時候是非常有益的。這看起來像

// get the request from the server and give an error if it failed

// do x thing with that request

// format the data like so

如此,我可以很容易地在同一時間專註於一件事。但是,當您的代碼中保留時,這些注釋可能會被曲解為需要以後閱讀。它們在你寫的時候很有用,但是一旦你完成了,就只能變成代碼的重複,強迫讀者用兩種不同的方式讀同樣的東西。但這並不會使他們的寫作更有價值。

我的完美建議是在寫作時使用這些注釋,其後再重新審視它們。當您刪除它們時,您可以問 "這裡的代碼是否以最優雅和可讀的方式做到了這一點?」 「是否有其他注釋,我可能會取代這個注釋,並且能解釋其必要性?」 「我認為什麼是對未來的我(或者從另一個母親那裡來的我)所能表達的最有用的東西?」

  • 這可以重構

你是否有過一個非常急迫的產品 Deadline?也許你實現了一個你自己不滿意的功能,或者他們告訴你這是 "暫時的","只是一個 AB 測試,所以不要緊"。*恐怖音樂 *

因為它可能很尷尬, 如注釋像:

// this isnt my best work, we had to get it in by the deadline

是相當有用的。作為一個維護者,當我在這樣的注釋中工作時,我會節省大量試圖找出這個人到底出了什麼毛病以及設想我怎麼破壞他早上上班的方式的時間。我將立即停止嘗試找出該代碼中的哪些部分應保留,轉而側重於可以重構的內容。我將給出的唯一警告是:不要讓這種類型的編碼成為你的降級方案 (我們將詳細討論這一點)。

  • 注釋作為教學的工具

請問,你們是一家為客戶全提供 Ruby 的 PHP 商店嗎?也許你們提供的 Ruby 完全標準,但你的團隊似乎自己都有些搞不懂(故弄玄虛?) (英語能力有限,其實沒完全懂作者意圖。。囧。。大概就是說語言教學應該專業且專註,少跨語言來教人坑人。但是,跟後面邏輯有點對不上啊!!!)。你在為某人寫教程嗎?這些都是有限的例子,寫出了如何可以對人有幫助。這個人確實在學習,但可能無法理解自己到底在幹什麼,因為他們從來沒有在他們的生活中看到過這些(學習的內容)。請注釋一下那個東西(飆髒的部分就。。。)!沒有注釋的學習已經足夠的謙卑了,畢竟他們並沒有大聲問你如何可以更容易地自學。

  • I StackOverflowd the bejeezus outta this (給你們個眼神自己體會 =,=)

您是否只是從 StackOverflow 複製粘貼一整塊代碼和修改它以滿足您的需要?這不是一個偉大的實踐,但我們都這麼做。過去我做過的事就是把我找到的那篇文章鏈接放上。但!你可能會說,那我們就不會得到那個代碼的功勞了!你在為錯誤的事情做優化,這個是我的答案。

不可避免的,人們有不同的編碼風格,解決方案的作者以不同的方式解決問題,如果你對這個領域理解更深。這有什麼關係?因為以後你會更聰明,你可能會在這一領域的水平更高,然後你會花更少的時間思索為什麼你這樣寫它,或從其他人的方法學習。另外,你也可以回顧一下這篇文章,看看在這個問題上是否有任何新的回復或更多的解釋。可能還會有另一個更好的答案。

不良注釋

寫注釋有時會有不好的總結,這是因為壞的注釋確實存在。讓我們來談談一些在寫的時候要避免的事情。

他們只是說它已經在做什麼。

約翰爸爸做了一個準確的笑話,這:

// if foo equals bar ...

If (foo === bar) {

} // end if

是很大的痛苦。為什麼?因為你實際上是以兩種不同的方式讀兩遍。它沒有提供更多的信息,事實上,它使你不得不用兩種不同的格式處理事情,這是精神上的開銷而不是幫助。我們都寫過這樣的注釋。也許是因為我們自己不太了解它,或者我們太擔心以後再讀。不管是什麼原因,如果可以的話,退後一步,試著從別人的角度看代碼和注釋,而不是作為作者,這總是好的。

  • 沒持續維護的注釋

錯誤的文檔可能比沒有文檔更糟糕。沒有什麼是比看到一段注釋說的與下面代碼表達的完全不同更令人沮喪的了。比浪費時間更糟糕的是誤導。

一個解決方案是確保無論您正在更新的代碼是什麼,您同時都繼續維護相關的注釋。當然,以後只會有越來越少但卻更有意義的注釋,從而讓維護更省力。但注釋和維護注釋都是工程師工作的一部分。注釋是在您的代碼中的,您的工作就是處理它,即使處理意味著刪除。

如果你的注釋是良好的質量開始,並表達了 why,而不是 how,你可能會發現這個問題就自己解決了。例如,如果我寫

// we need to FLIP this animation to be more performant in every browser

並在以後重構此代碼以從使用 getBoundingClientRect() 變成使用 getBBox(),注釋仍然適用。該函數的存在是出於相同的原因,但 how 的細節則是代碼被改變的那部分內容。

  • 你可以用一個更好的命名

我肯定見過人們寫代碼 (或自己做這件事),其中變數或函數的名稱是一個字母,然後再注釋一下這是什麼東西。這是浪費,我們都討厭打字,但是如果您有用重複使用變數或函數名,我可不想掃描整個文檔找您解釋了名稱本身可以做什麼的地方。我理解,命名是很難的。但是一些注釋取代了一些可以更精確地寫出的東西。

  • 注釋是一個不好好開始寫代碼的借口

這對很多人來說是問題的癥結所在。如果你寫的代碼是雜亂的,你扔在注釋在旁邊用以說明。這意味著注釋反而阻礙了你的編程。這是一種本末倒置的情景。不幸的是,即使是本文的作者我,也不是那麼容易確定哪個是本哪個是末。

我們以無數的方式欺騙自己。我們可能會花時間寫一段注釋,讓代碼更清楚。我們也可以告訴自己,我們不需要注釋我們的代碼,因為我們的代碼寫得足夠好,即使其他人可能不同意。

兩個方向都有懶惰的嫌疑。儘力而為吧,不要只依賴一種正確的方法,應該編寫代碼,然後閱讀它。試著想像你既是作者又是維護者,或者說對於一個更年輕的你來說,這段代碼看起來如何。你需要什麼樣的信息才能儘可能的高效?

最近,人們傾向於支持 "你是否應該寫注釋" 或反之,力挺另一邊。但我認為:這種談話是不夠好的。我希望能讓大家更深入地討論如何寫有意義的注釋,從而彌合差異。

即便如此,這個話題還是有很多需要解析的地方。哈哈, 明白了嗎?無論如何,我會留給你一些 (更好) 的趣聞。一段時間前,Stack Overflow 上有一個關於人們寫過或看到的最好的注釋的帖子。你絕對可以在這裡花更多時間。一個好玩的事情


推薦閱讀:

CFD網格中的幾何操作(程序中的幾何操作):
誰能用軟體跑一下6+大牌德州的牌型概率不?
男友他媽的媽見到女友他媽的爸叫什麼?
演算法相關學習資料整理
零基礎學開發經驗分享

TAG:代码注释 | 程序 |