<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>

          那些消失的代碼注釋

          共 5389字,需瀏覽 11分鐘

           ·

          2021-11-23 15:32

          今天和大家聊聊代碼注釋:

          • 為什么很多人不喜歡寫注釋?
          • 要不要寫注釋?
          • 該怎么寫注釋?

          現(xiàn)在的項(xiàng)目開發(fā)里,代碼注釋就像程序員的頭發(fā),越來越少。

          尤其是國內(nèi),這種現(xiàn)象不僅是在小公司小團(tuán)隊(duì)中司空見慣,就算在大公司,以及大團(tuán)隊(duì)中的開源項(xiàng)目里,也是屢見不鮮。

          上圖是我在阿里的 Druid 項(xiàng)目源碼里截的。DruidDataSource 是 Druid 重度使用的核心類,非常關(guān)鍵,可是哪怕這種關(guān)鍵的核心類,也見不到什么注釋。

          這張圖則來自阿里的另一個(gè)著名開源項(xiàng)目Dubbo。DubboProtocol 是 dubbo 協(xié)議的實(shí)現(xiàn)類,而 dubbo 協(xié)議是 Dubbo 項(xiàng)目中最常見,使用最頻繁的默認(rèn)協(xié)議,一樣沒什么注釋。

          沒有注釋對我們讀代碼帶來了很多的不便之處。就像扔給你一個(gè)數(shù)碼產(chǎn)品,上面堆疊著密密麻麻的功能按鍵,但是卻沒有給你說明書。

          那為什么代碼注釋消失了呢?

          我嘗試總結(jié)一下原因:

          1. 國內(nèi)程序員的職業(yè)環(huán)境對加注釋不友好

          在國內(nèi)這種環(huán)境里,程序員們每天在苦悶的 996 中掙扎,各種大活小活不斷地做著,正常寫代碼都忙得不可開交,加注釋更是進(jìn)一步提升了工作量,沒人喜歡自己給自己加工作量的。

          咱們想想,在費(fèi)勁巴拉地寫完一大堆代碼之后,經(jīng)過反復(fù)自測修改之后,好不容易調(diào)通了,腦子已經(jīng)暈乎乎的了,你此時(shí)會(huì)有多大心思去寫這段注釋呢?

          又再想想,你可能想著要給代碼加注釋呢,突然這邊產(chǎn)品拉你開會(huì),又或者那邊運(yùn)營告訴你,需求變了,剛寫好的代碼還得再改改……此時(shí),你還有給代碼加注釋的念頭嗎?

          另外,注釋這事兒,寫好了是很費(fèi)精力的。一般來說,一段好的注釋,要能在有限的行數(shù)之內(nèi)說明出:被它注釋的代碼到底做了什么,是個(gè)怎樣的概念以及為什么會(huì)寫這段代碼

          寫注釋麻煩不說,關(guān)鍵是注釋還不算咱們程序員的工作量。

          程序員的工作是把業(yè)務(wù)用程序?qū)崿F(xiàn),工作結(jié)果里不看你注釋了多少代碼,也不看你注釋寫的好還是壞,只看你的程序是不是寫完了,滿足了需求沒有,會(huì)不會(huì)上線出什么問題。

          至于注釋,它滾出了程序員兄弟們的 KPI。有多少公司能像 Google 那樣去 Review 代碼的?BAT 有一個(gè)算一個(gè),都差點(diǎn)意思。

          所以,國內(nèi)程序員們糟糕的環(huán)境,是代碼注釋少的首要原因。

          2. 看待注釋的方式出現(xiàn)了變化

          Java 是一門面向?qū)ο蟮恼Z言,從它出世以來,業(yè)界就不斷地為 Java 制定了數(shù)不清的規(guī)范。

          在 2008 年,集這些規(guī)范于大成的《Clean Code》—— 中文名叫《代碼整潔之道》這本書出現(xiàn)了。

          在《代碼整潔之道》中有個(gè)理念就是,注釋是為了彌補(bǔ)代碼表達(dá)能力不足的一種不得已的做法。如果代碼能表達(dá)清楚,那就沒必要寫注釋。

          甚至,這本書的作者認(rèn)為寫注釋都需要用 failure 這個(gè)詞來形容,也就是說,如果你寫了注釋,那就說明你的代碼不夠好,你寫好代碼的努力失敗了。

          這個(gè)理念在業(yè)界也被不少大牛們認(rèn)可了。所以,后面就有越來越多的人認(rèn)為:代碼寫的夠好,就不用寫注釋了。

          如果大家有空,可以去看看《代碼整潔之道》的第四章,里面詳細(xì)說明了這種如今被業(yè)界不少人接受的關(guān)于注釋的理念。

          所以,“好代碼不需要注釋”這種觀點(diǎn)也是造成注釋少的一個(gè)原因。

          3. 注釋沒有規(guī)范,導(dǎo)致質(zhì)量參差不齊

          很多團(tuán)隊(duì)里,是沒有注釋規(guī)范的。對怎么注釋,在哪里注釋沒有任何規(guī)定,隨意程序員們自由發(fā)揮。

          這就麻煩了,注釋一旦寫了,它就很關(guān)鍵了。因?yàn)?/p>

          錯(cuò)誤的注釋,比沒寫注釋還禍害人

          注釋寫的很差,那不僅沒起到注釋本應(yīng)該起到幫助讀代碼的作用,反而還可能影響讀代碼,甚至還能把人帶坑里。

          如果沒有注釋規(guī)范,往往經(jīng)常就會(huì)出現(xiàn)有人做的好有人做的差的情況。

          比如,有人到處加注釋,i = i + 1; //把i加1連這種簡單代碼都恨不得加注釋,這就有點(diǎn)脫褲子放屁了。

          還有的人寫注釋了,但是需求變了,代碼改了之后,注釋懶得改了。又或者是改代碼的人不是原作者,新人改完之后壓根就沒意識(shí)到要改注釋。

          所以,如果沒有規(guī)范,很多程序員對注釋沒有什么正確的概念,沒寫好注釋由此還引來了埋怨……久而久之,就沒人愛干加注釋這件事了。

          到底應(yīng)該怎么寫注釋呢?

          談了那么多不寫注釋的原因,這里也想說明一下我對注釋的觀點(diǎn)。

          我個(gè)人并不怎么贊同《代碼整潔之道》對注釋的觀點(diǎn),我自己讀有好注釋的代碼,直接就省了五成以上的力氣。有好注釋的代碼讀起來,就像常年腦血栓,一朝被皮搋子打通了一樣,那叫一個(gè)順暢。

          比如,看看 Netty 的注釋:

          /**
          ?*?A?nexus?to?a?network?socket?or?a?component?which?is?capable?of?I/O
          ?*?operations?such?as?read,?write,?connect,?and?bind.
          ?*?


          ?*?A?channel?provides?a?user:
          ?*?


            ?*?
          • the?current?state?of?the?channel?(e.g.?is?it?open??is?it?connected?),

          • ?*?
          • the?{@linkplain?ChannelConfig?configuration?parameters}?of?the?channel?(e.g.?receive?buffer?size),

          • ?*?
          • the?I/O?operations?that?the?channel?supports?(e.g.?read,?write,?connect,?and?bind),?and

          • ?*?
          • the?{@link?ChannelPipeline}?which?handles?all?I/O?events?and?requests
            ?*?????associated?with?the?channel.

          • ?*?

          ?*
          ?*?

          All?I/O?operations?are?asynchronous.


          ?*?


          ?*?All?I/O?operations?in?Netty?are?asynchronous.??It?means?any?I/O?calls?will
          ?*?return?immediately?with?no?guarantee?that?the?requested?I/O?operation?has
          ?*?been?completed?at?the?end?of?the?call.??Instead,?you?will?be?returned?with
          ?*?a?{@link?ChannelFuture}?instance?which?will?notify?you?when?the?requested?I/O
          ?*?operation?has?succeeded,?failed,?or?canceled.
          ?*
          ?*?

          Channels?are?hierarchical


          ?*?


          ?*?A?{@link?Channel}?can?have?a?{@linkplain?#parent()?parent}?depending?on
          ?*?how?it?was?created.??For?instance,?a?{@link?SocketChannel},?that?was?accepted
          ?*?by?{@link?ServerSocketChannel},?will?return?the?{@link?ServerSocketChannel}
          ?*?as?its?parent?on?{@link?#parent()}.
          ?*?


          ?*?The?semantics?of?the?hierarchical?structure?depends?on?the?transport
          ?*?implementation?where?the?{@link?Channel}?belongs?to.??For?example,?you?could
          ?*?write?a?new?{@link?Channel}?implementation?that?creates?the?sub-channels?that
          ?*?share?one?socket?connection,?as?BEEP?and
          ?*?SSH?do.
          ?*
          ?*?

          Downcast?to?access?transport-specific?operations


          ?*?


          ?*?Some?transports?exposes?additional?operations?that?is?specific?to?the
          ?*?transport.??Down-cast?the?{@link?Channel}?to?sub-type?to?invoke?such
          ?*?operations.??For?example,?with?the?old?I/O?datagram?transport,?multicast
          ?*?join?/?leave?operations?are?provided?by?{@link?DatagramChannel}.
          ?*
          ?*?

          Release?resources


          ?*?


          ?*?It?is?important?to?call?{@link?#close()}?or?{@link?#close(ChannelPromise)}?to?release?all
          ?*?resources?once?you?are?done?with?the?{@link?Channel}.?This?ensures?all?resources?are
          ?*?released?in?a?proper?way,?i.e.?filehandles.
          ?*/
          public?interface?Channel?extends?AttributeMap,?Comparable<Channel>?{

          Channel 是 Netty 里非常核心的一個(gè)接口,你直接看注釋,一下子就能理解了 Netty 為啥搞出個(gè) Channel 類來,Channel 類你可以怎么玩兒,這些 Netty 在注釋給你說得清清楚楚、明明白白。

          所以,我覺得注釋一定是要的,只是需要有個(gè)標(biāo)準(zhǔn),也要有個(gè)度。

          從實(shí)踐上看,我們團(tuán)隊(duì)有這么幾個(gè)必須加注釋的標(biāo)準(zhǔn):

          1. 復(fù)雜的業(yè)務(wù)邏輯

          業(yè)務(wù)邏輯關(guān)聯(lián)太多的東西又或者步驟非常多,更或者兩者兼有,那么就很少有人會(huì)去耐心仔細(xì)的去一行一行的把整個(gè)代碼全部讀通理順。

          這時(shí)候,必須在業(yè)務(wù)邏輯實(shí)現(xiàn)的相關(guān)類中,把類在業(yè)務(wù)邏輯實(shí)現(xiàn)中是個(gè)什么成分,為什么這么設(shè)計(jì)類,以及對應(yīng)的業(yè)務(wù)邏輯都要講清楚。并且重構(gòu)代碼后,注釋也必須跟著重構(gòu)。

          2. 晦澀的算法

          算法也要加上注釋的,尤其那些深?yuàn)W的算法。大家不可能都是算法專家,能一下子就通過代碼理解到算法實(shí)現(xiàn)的真諦。所以,這里也要加上注釋,一般是說明這是用了個(gè)什么算法,這套算法的出處或者附上相關(guān)文章的引用地址。

          3. 非常規(guī)的寫法

          非常規(guī)的寫法往往是有特殊情況,不得已為之的。比如,為了得到更好的性能;又比如,為了修復(fù)一個(gè) bug,卻不想對代碼進(jìn)行大改動(dòng)。

          總之,非常規(guī)的寫法就是反模式、反套路的,有時(shí)候甚至?xí)`反程序員的直覺。像這些做法,必須在注釋中寫明這樣實(shí)現(xiàn)的原因。

          4. 可能有坑卻暫時(shí)沒太好解決辦法

          有些時(shí)候,需求出的夠難夠復(fù)雜,時(shí)間上催的又很急,你根本沒辦法馬上想到特別好的辦法去實(shí)現(xiàn)。只能臨時(shí)想個(gè)簡單粗暴的方案,先湊活著。甚至還會(huì)在某些地方,把一些變量的值寫死先去把本期的需求實(shí)現(xiàn)了。

          像這種就很可能就會(huì)給后面挖坑了。這時(shí)候,注釋必須加上為什么要這么解決的原因,還必須加上 //TODO 這類的,表示后面需要進(jìn)行進(jìn)一步的修改。

          5. 關(guān)于項(xiàng)目核心的接口、類和字段

          做項(xiàng)目的時(shí)候,需求中的很多核心概念很可能會(huì)被映射到對應(yīng)的接口或者實(shí)體類上,如果在這些核心接口和實(shí)體類加上清楚的注釋,寫明對應(yīng)的業(yè)務(wù)概念,那么,后面再維護(hù)項(xiàng)目的時(shí)候,真的是事半功倍。

          比如,我們在一套批量調(diào)度系統(tǒng)里,可能有多種任務(wù)的概念,有需要限定執(zhí)行時(shí)間的任務(wù),也有不需要限定執(zhí)行時(shí)間的任務(wù),那么實(shí)現(xiàn)上,就可能有個(gè) LimitedTimeTask 類對應(yīng)限定時(shí)間的任務(wù),還有個(gè) UnLimitedTimeTask 類去對應(yīng)不需要限定執(zhí)行時(shí)間的任務(wù)。那這兩個(gè)類就必須加上注解,寫清楚對應(yīng)的業(yè)務(wù)概念。

          如果特定概念是復(fù)合的,是由多個(gè)小概念構(gòu)成,卻必須用一個(gè)接口或者一個(gè)類來表示,那很可能實(shí)現(xiàn)上,就還得用字段去映射這些小概念,那么這些字段也得加上注釋說明起對應(yīng)的概念。

          總之,注釋我個(gè)人理解必須要有,但是不可能太泛濫,必須有節(jié)制、有規(guī)范的加。

          最后,咱們說白了,我對注釋的態(tài)度就是,和寫代碼一樣,要有規(guī)范。

          在這里和管理者說一句,如果你希望大家寫好注釋,不能就靠一句“必須寫注釋”這么高高在上的話去要求大家。沒有規(guī)范,你就不能完全怪程序員不加注釋了。

          最最后,大劉提醒我“四哥,注釋規(guī)范里還要再加一條”

          對項(xiàng)目、領(lǐng)導(dǎo)的吐槽,可以寫到注釋里!

          以上就是這篇文章的全部內(nèi)容,如果覺得寫的還行,可以給我點(diǎn)贊、點(diǎn)在看、轉(zhuǎn)發(fā),你們的支持是我寫文章最大的動(dòng)力。

          瀏覽 76
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

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

          手機(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>
                  日韩精品在线电影 | 一级片在线观看视频 | 91九色TS另类国产人妖 | 久操视频在线观看 | 国产一级黄片 |