<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          編寫代碼注釋的最佳實(shí)踐

          共 6021字,需瀏覽 13分鐘

           ·

          2021-11-09 15:33

          關(guān)注、星標(biāo)公眾號(hào),直達(dá)精彩內(nèi)容

          來源:CSDN(ID:CSDNnews)

          作者:Ellen Spertus |?譯者:王雪迎? ?


          雖然有很多資源可以幫助程序員編寫更好的代碼,比如書籍或靜態(tài)分析器,但是很少有資源可被用于編寫更好的注釋。雖然度量一個(gè)程序中的注釋數(shù)量很容易,但衡量注釋的質(zhì)量卻很難,而且兩者并不一定相關(guān)。差的注釋比根本不寫注釋更糟糕。這里有一些規(guī)則可以幫助你實(shí)現(xiàn)一種折中的方法。

          麻省理工學(xué)院的著名教授Hal Abelson曾說過:“程序必須寫給人們閱讀,而只是附帶地讓機(jī)器執(zhí)行?!彪m然他可能故意低估了運(yùn)行代碼的重要性,但卻注意到了程序有兩種截然不同的受眾。編譯器和解釋器會(huì)忽略注釋,找出同等容易理解的所有語(yǔ)法正確的程序。而人類讀者則完全不同。我們發(fā)現(xiàn)有些程序比其它的更難理解,此時(shí)就會(huì)通過查看注釋來幫助我們理解這些程序。

          雖然有很多資源可以幫助程序員編寫更好的代碼,比如書籍或靜態(tài)分析器,但是很少有資源可被用于編寫更好的注釋。雖然度量一個(gè)程序中的注釋數(shù)量很容易,但衡量注釋的質(zhì)量卻很難,而且兩者并不一定相關(guān)。差的注釋比根本不寫注釋更糟糕。正如Peter Vogel所述:

          1. 編寫并維護(hù)注釋是一項(xiàng)開銷。

          2. 編譯器不會(huì)檢查注釋,因此無法確定注釋是否正確。

          3. 另一方面,你可以保證計(jì)算機(jī)完全按照你的代碼所示運(yùn)行。

          所有這些觀點(diǎn)都是正確的,但如果走到另一個(gè)極端,即從不寫注釋,那將是一個(gè)錯(cuò)誤。這里有一些規(guī)則可以幫助你實(shí)現(xiàn)一種折中的方法:

          • 規(guī)則1:注釋不應(yīng)與代碼重復(fù)。

          • 規(guī)則2:好的注釋不能成為代碼不清晰的借口。

          • 規(guī)則3:如果無法寫出一個(gè)清晰的注釋,代碼可能有問題。

          • 規(guī)則4:注釋應(yīng)該消除混亂,而不是引起混亂。

          • 規(guī)則5:在注釋中解釋不規(guī)范的代碼。

          • 規(guī)則6:提供復(fù)制代碼的原始出處鏈接。

          • 規(guī)則7:在可能提供幫助的地方引入指向外部參考的鏈接。

          • 規(guī)則8:在修復(fù)bug時(shí)添加注釋。

          • 規(guī)則9:使用注釋來標(biāo)記未完成的實(shí)現(xiàn)。

          本文其余部分將逐條解釋這些規(guī)則,提供示例并說明如何以及何時(shí)應(yīng)用它們。


          01

          規(guī)則1:注釋不應(yīng)與代碼重復(fù)


          許多初級(jí)程序員會(huì)寫太多注釋,因?yàn)樗麄兘邮芰巳腴T指導(dǎo)老師的培訓(xùn)。我曾見過計(jì)算機(jī)科學(xué)系的高年級(jí)學(xué)生為每對(duì)大括號(hào)加上一條注釋,以表示該塊結(jié)束:

          if (x > 3) {} // if

          我也聽說過老師要求學(xué)生對(duì)每一行代碼進(jìn)行注釋。雖然這對(duì)極為初級(jí)者來說可能是一個(gè)合理的策略,但這樣的注釋就像是訓(xùn)練輪,在大孩子騎車時(shí)應(yīng)該去掉。

          不添加任何信息的注釋具有負(fù)價(jià)值,因?yàn)樗鼈儯?/span>

          • 增加視覺混亂

          • 讀寫花時(shí)間

          • 可能會(huì)過時(shí)

          一個(gè)典型的壞示例為:

          i = i + 1;         // Add one to i

          它不添加任何信息,并切產(chǎn)生維護(hù)成本。

          每一行代碼都需要注釋的策略在Reddit上都受到了相當(dāng)?shù)某靶Γ?/span>

          // create a for loop // <-- commentfor // start for loop(   // round bracket    // newlineint // type for declarationi    // name for declaration=   // assignment operator for declaration0   // start value for i


          02

          規(guī)則2:好的注釋不能成為代碼不清晰的借口


          注釋的另一個(gè)誤用是提供本應(yīng)包含在代碼中的信息。一個(gè)簡(jiǎn)單的例子是,有人用一個(gè)字母命名一個(gè)變量,然后添加一個(gè)描述其用途的注釋:

          private static Node getBestChildNode(Node node) {    Node n; // best child node candidate    for (Node node: node.getChildren()) {        // update n if the current state is better        if (n == null || utility(node) > utility(n)) {            n = node;        }    }    return n;}

          通過更好的變量命名,可以不需要再做注釋:

          private static Node getBestChildNode(Node node) {    Node bestNode;    for (Node currentNode: node.getChildren()) {        if (bestNode == null || utility(currentNode) > utility(bestNode)) {            bestNode = currentNode;        }    }    return bestNode;}

          正如Kernighan和Plauger在編程風(fēng)格要素一書中所寫,“不要注釋糟糕的代碼 — 重寫它?!?/span>


          03

          規(guī)則3:如果無法寫出一個(gè)清晰的注釋,代碼可能有問題


          Unix源代碼中最臭名昭著的注釋是“你不希望理解它”,它出現(xiàn)在一些恐怖的上下文切換代碼之前。Dennis Ritchie后來解釋說這是故意為之:“本意是想表達(dá)‘這不會(huì)出現(xiàn)在考試中’,而不是作為一種厚顏無恥的挑戰(zhàn)?!辈恍业氖?,結(jié)果發(fā)現(xiàn)他與合作者Ken Thompson自己也理解不了,后來不得不重寫。

          這讓人想起了Kernighan定律:

          調(diào)試在一開始就比編寫程序困難一倍。因此,按照定義,如果你的代碼寫得非常巧妙,那么你就沒有足夠的能力來調(diào)試它。

          警告讀者遠(yuǎn)離你的代碼就像打開汽車的危險(xiǎn)警示燈:承認(rèn)你正在做知法犯法的事情。相反,把代碼重寫成你充分理解的東西,或者更進(jìn)一步,直截了當(dāng)?shù)剡M(jìn)行解釋。


          04

          規(guī)則4:注釋應(yīng)該消除混亂,而不是引起混亂


          如果沒有Steven Levy的 黑客:計(jì)算機(jī)革命的英雄 中的這個(gè)故事,任何關(guān)于負(fù)面注釋的討論都是不完整的:

          [Peter Samson]拒絕在源代碼中添加注釋來解釋他在特定時(shí)間所做的事情,使其特別晦澀難懂。在一個(gè)分發(fā)良好的程序中,Samson繼續(xù)編寫了數(shù)百條匯編語(yǔ)言指令,其中只有一條包含1750數(shù)字的指令帶有注釋。注釋是RIPJSB,人們絞盡腦汁研究它的含義,直到有人發(fā)現(xiàn)1750年是巴赫去世的那一年,而Samson寫的注釋是Rest In Peace Johann Sebastian Bach(安息吧,約翰·塞巴斯蒂安·巴赫)的縮寫。

          雖然我和別人一樣欣賞一個(gè)好的黑客,但這種注釋不可效仿。如果你的注釋引起混亂而不是消除混亂,刪除它。


          05

          規(guī)則5:在注釋中解釋不規(guī)范的代碼


          注釋掉其他人可能認(rèn)為不需要或冗余的代碼是個(gè)好主意,比如來自App Inventor的代碼(我所有的正面示例均源于此):

          final Object value = (new JSONTokener(jsonString)).nextValue();// Note that JSONTokener.nextValue() may return// a value equals() to null.if (value == null || value.equals(null)) {    return null;}

          如果沒有注釋,有人可能會(huì)“簡(jiǎn)化”代碼或?qū)⑵湟暈橐粋€(gè)神秘但必不可少的咒語(yǔ)。寫下為什么需要這些代碼,可以節(jié)省未來讀者的時(shí)間并解除他們的焦慮。

          需要對(duì)是否注釋代碼做出判斷。在學(xué)習(xí)Kotlin時(shí),我遇到了Android教程中的代碼:

          if (b == true)

          我立即想到是否可以用以下代碼取代:

          if (b)

          就像在Java中一樣。經(jīng)過一點(diǎn)研究,我了解到可以為null的布爾變量會(huì)顯式地與true進(jìn)行比較,以避免出現(xiàn)難看的null檢查:

          if (b != null && b)

          我建議不要為常見的語(yǔ)法添加注釋,除非專門為新手編寫教程。


          06

          規(guī)則6:提供復(fù)制代碼的原始出處鏈接


          如果你像大多數(shù)程序員一樣,有時(shí)會(huì)使用網(wǎng)上找到的代碼。包含對(duì)源代碼的引用,可使將來的讀者能夠獲得完整的上下文,例如:

          • 解決了什么問題

          • 誰提供了代碼

          • 為什么推薦此解決方案

          • 評(píng)論者怎么看

          • 是否仍然有效

          • 如何改進(jìn)

          例如,考慮此注釋:

          /** Converts a Drawable to Bitmap. via https://stackoverflow.com/a/46018816/2219998. */

          點(diǎn)開鏈接,給出了以下信息:

          • 代碼的作者是Tomá? Procházka,他在Stack Overflow上排名前3%。

          • 一個(gè)評(píng)論者提供了一個(gè)優(yōu)化,已經(jīng)納入repo資源庫(kù)。

          • 另一位評(píng)論者提出了一種避免邊緣情況的方法。

          將其與下面的注釋對(duì)比(稍作修改以防止侵權(quán)):

          // Magical formula taken from a stackoverflow post, reputedly related to// human vision perception.return (int) (0.3 * red + 0.59 * green + 0.11 * blue);

          任何想要理解這段代碼的人都必須搜索公式。粘貼到URL要比以后查找引用快得多。

          有些程序員可能不愿意表明他們自己并沒有編寫代碼,但是重用代碼是一個(gè)明智的舉動(dòng),它可以節(jié)省時(shí)間并讓你獲得更多關(guān)注。當(dāng)然,永遠(yuǎn)不要粘貼不懂的代碼。

          人們從Stack Overflow的問題和答案中復(fù)制大量代碼。這些代碼要求歸屬于知識(shí)共享許可下。引用注釋滿足該要求。

          同樣,你應(yīng)該引用一些有用的教程以便再次找到它們,并且感謝它們的作者:

          // Many thanks to Chris Veness at http://www.movable-type.co.uk/scripts/latlong.html// for a great reference and examples.


          07

          規(guī)則7:在可能提供幫助的地方引入指向外部參考的鏈接


          當(dāng)然,并非所有引用都指向Stack Overflow??紤]:

          // http://tools.ietf.org/html/rfc4180 suggests that CSV lines// should be terminated by CRLF, hence the \r\n.csvStringBuilder.append("\r\n");

          到標(biāo)準(zhǔn)或其它文檔的鏈接可以幫助讀者理解代碼正在解決的問題。雖然這些信息可能出現(xiàn)在設(shè)計(jì)文檔中的某個(gè)地方,但一個(gè)適當(dāng)位置的注釋會(huì)在最需要它的時(shí)間和地方為讀者提供標(biāo)識(shí)。本例中,點(diǎn)開鏈接可以看到RFC 4180已經(jīng)由RFC 7111更新了有用的信息。


          08

          規(guī)則8:在修復(fù)bug時(shí)添加注釋


          不僅應(yīng)該在最初編寫代碼時(shí)添加注釋,修改代碼時(shí),特別是修復(fù)bug時(shí),也應(yīng)該添加??聪旅孢@個(gè)注釋:

            // NOTE: At least in Firefox 2, if the user drags outside of the browser window,  // mouse-move (and even mouse-down) events will not be received until  // the user drags back inside the window. A workaround for this issue  // exists in the implementation for onMouseLeave().  @Override  public void onMouseMove(Widget sender, int x, int y) { .. }

          注釋不僅有助于讀者理解當(dāng)前方法和引用方法中的代碼,而且有助于確定是否仍然需要這些代碼以及如何測(cè)試它們。

          注釋還可以幫助參考問題跟蹤程序:

          // Use the name as the title if the properties did not include one (issue #1425)

          雖然 git blame 可以用來查找添加或修改行的提交,但提交消息往往很簡(jiǎn)短,最重要的更改(例如,修復(fù)問題#1425)可能不是最近提交(例如,將方法從一個(gè)文件移動(dòng)到另一個(gè)文件)的一部分。


          09

          規(guī)則9:使用注釋來標(biāo)記未完成的實(shí)現(xiàn)


          即使代碼中有已知的限制,有時(shí)還是有必要檢查它。雖然不分享代碼中已知的缺陷很有誘惑力,但最好將這些明確化,例如使用TODO注釋:

          // TODO(hal): We are making the decimal separator be a period,// regardless of the locale of the phone. We need to think about// how to allow comma as decimal separator, which will require// updating number parsing and other places that transform numbers// to strings, such as FormatAsDecimal

          對(duì)此類注釋使用標(biāo)準(zhǔn)格式有助于衡量和解決技術(shù)負(fù)債問題。更好的辦法是,在跟蹤系統(tǒng)中添加一個(gè)問題,并在注釋中引用該問題。


          10

          總結(jié)


          我希望上面的例子已經(jīng)表明,注釋不能成為差代碼的借口或修復(fù)差代碼;它們通過提供不同類型的信息來補(bǔ)充好的代碼。正如Stack Overflow聯(lián)合創(chuàng)始人Jeff Atwood所寫,“代碼告訴你怎么做,注釋告訴你為什么。”

          遵守這些規(guī)則可以節(jié)省你及其隊(duì)友的時(shí)間,減少挫折感。

          即便如此,我確信這些規(guī)則并不是詳盡無遺的,并期待著在評(píng)論中看到補(bǔ)充建議。

          參考資料:

          • https://www.reddit.com/r/ProgrammerHumor/comments/8w54mx/code_comments_be_like/

          • https://www.reddit.com/r/ProgrammerHumor/comments/bz35nh/whats_a_comment/

          • https://geekandpoke.typepad.com/geekandpoke/2011/06/code-commenting-made-easy.html

          • https://geekandpoke.typepad.com/geekandpoke/2008/07/good-comments.html

          • https://www.commitstrip.com/en/2016/09/01/keep-it-simple-stupid/?

          • https://www.commitstrip.com/en/2013/07/22/commentaire-de-commit/?

          • https://geekandpoke.typepad.com/geekandpoke/2009/07/

          • https://geekandpoke.typepad.com/geekandpoke/2010/11/architecture.html

          原文鏈接:https://stackoverflow.blog/2021/07/05/best-practices-for-writing-code-comments/

          聲明:本文由CSDN翻譯,轉(zhuǎn)載請(qǐng)注明來源。?

          ???????????????? ?END ?????????????????

          關(guān)注我的微信公眾號(hào),回復(fù)“加群”按規(guī)則加入技術(shù)交流群。

          歡迎關(guān)注我的視頻號(hào):

          點(diǎn)擊“閱讀原文”查看更多分享,歡迎點(diǎn)分享、收藏、點(diǎn)贊、在看。

          瀏覽 79
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  五月色综合网 | 奶妈做爱网站 | 色天天天天 | 国产三级片网站 | 99er国产精品 |