0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

函數(shù)的設(shè)計(jì)功能是什么

馬哥Linux運(yùn)維 ? 來源:馬哥Linux運(yùn)維 ? 作者:馬哥Linux運(yùn)維 ? 2022-11-01 10:19 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

每隔一段時(shí)間,網(wǎng)上總會突然出現(xiàn)一些令人討厭的帖子,其觀點(diǎn)是:不應(yīng)該為代碼寫注釋,它存在的唯一原因是因?yàn)榇a本身不足夠好。對于這些論點(diǎn),我完全不能茍同。

爛代碼

他們的觀點(diǎn)也不完全是錯(cuò)誤的。沒有人能說自己的代碼足夠好。代碼本身也會慢慢變壞。你知道什么時(shí)候代碼腐爛得最厲害嗎?當(dāng)你六個(gè)月沒有碰這些代碼的時(shí)候!

當(dāng)回過頭再讀的時(shí)候,你會非常好奇:“這個(gè)作者到底是怎么想的?”(于是,使用 Git blame 來查看歷史記錄,沒想到代碼竟然是自己寫的,因?yàn)檫@是你的代碼。)

反對注釋者的論點(diǎn)是:需要注釋的唯一原因是你的代碼不夠“清晰”。如果代碼重構(gòu)、命名和組織地更好,那就不需要這些注釋了。

今天,當(dāng)整個(gè)項(xiàng)目和問題空間都裝在你的腦袋里的時(shí)候,你自然會覺得代碼是干凈、清晰和優(yōu)雅的。但是,當(dāng)六個(gè)月后,又或是 CTO 剛好在生產(chǎn)系統(tǒng)上突然發(fā)現(xiàn)一個(gè)非常嚴(yán)重的 bug,在主管緊盯的情況下,某個(gè)可憐的家伙不得不去調(diào)試你的代碼的時(shí)候,這些代碼可能對你已經(jīng)有些模糊了。

你無比熟悉的一段代碼,嘗試去理解其他人在什么場景下不能理解,這是一種非常難以掌握的技能。不過,它具有無可估量的價(jià)值,幾乎和一次就能把代碼寫到位的能力一樣重要。在工業(yè)界中,基本上沒有人是獨(dú)行俠。即使真地在獨(dú)自寫代碼,你也會遺忘代碼這么寫的緣由或者昨天深夜“工程代碼”核心部分的確切目的。未來一旦你離職,接替你的人不得不去理解每一個(gè)僅藏在你的腦袋里的小偏好和習(xí)慣。

所以,寫上一個(gè)即使在現(xiàn)在看來過于淺顯的注釋也不是一個(gè)壞事情。有時(shí)候,它甚至?xí)砭薮蟮膸椭?/p>

無注釋經(jīng)常導(dǎo)致代碼更難以理解

某些人聲稱:移除注釋將會使代碼變得更好,因?yàn)檫@迫使你編寫更清晰的代碼。我對此亦不以為然,因?yàn)槲也徽J(rèn)為有人會實(shí)際寫上一些次佳的代碼,并且寫上一些注釋來解釋這種行為(除了// TODO: 這是一個(gè)臨時(shí)的解決方法,我會稍后修正之外)。我們都會寫出在各種外部條件(通常是時(shí)間)下自認(rèn)為最好的代碼。

為去除注釋而重構(gòu)代碼的問題在于,這種努力往往事與愿違,會產(chǎn)出更壞的代碼。典型例子是重構(gòu)一行復(fù)雜的代碼,將之提取到一個(gè)獨(dú)立的函數(shù)中,并取一個(gè)望文生義的名字。這個(gè)行為看上去很棒,但是,現(xiàn)在你為閱讀代碼的人帶來了一個(gè)上下文切換點(diǎn)。替代真實(shí)代碼的是一個(gè)函數(shù)調(diào)用,于是,他們不得不滾動到函數(shù)定義的地方,記住和對照函數(shù)聲明和調(diào)用的參數(shù),并且將函數(shù)返回值代入到調(diào)用的地方。

另外,清晰的函數(shù)名僅僅能夠提供非常短小的注釋。任何需要多余一小段短語的注釋無法(或者不應(yīng)該)概括到一個(gè)函數(shù)名中。因此,你最終會得到一個(gè)其上有注釋的函數(shù)。

的確,一個(gè)非常短小的函數(shù)都可能導(dǎo)致困惑和更復(fù)雜的代碼。如果看到這樣的函數(shù),我會去搜索這個(gè)函數(shù)在哪些地方被調(diào)用。如果只有一個(gè)地方,我就會去思考,這是一個(gè)確實(shí)封裝了全局邏輯的通用代碼塊呢(譬如 NameToUserID),還是,這個(gè)函數(shù)嚴(yán)重依賴調(diào)用端的特定狀態(tài)和實(shí)現(xiàn),并且不能在其他地方正確工作。隨著把這些代碼提取一個(gè)函數(shù)里面,你本質(zhì)上在其余的代碼庫中暴露了這些實(shí)現(xiàn)細(xì)節(jié),這么草率的做決定是不合適的。即使你知道這個(gè)函數(shù)其他人不應(yīng)該調(diào)用,其他人還會在某些地方調(diào)用它,即便這些地方不合適這么做。

小函數(shù)的相關(guān)問題在 Cindy Sridharan 在 medium 網(wǎng)站上的帖子[1]中有更加詳細(xì)的闡述。

我們甚至可以深入討論長短變量名的比較和權(quán)衡,但是就此打住吧,一般你不可能接受更長的變量名了。除非你的變量名就是你想寫的完整的注釋,否則你還是會丟失信息而不得不添加到注釋中。我認(rèn)為我們可以達(dá)成一致:usernameStrippedOfSpacesWithDotCSVExtension 是一個(gè)可怕的變量名稱。

我不是說我們不應(yīng)該提煉代碼,讓它們更加清晰和優(yōu)雅。絕對要這么做!這是一個(gè)杰出開發(fā)人員的特征。但是,代碼清晰性和有注釋是正交的,撰寫良好的注釋也是杰出開發(fā)人員的特征。

沒有壞注釋

在這些討論中給出的壞注釋的例子都是些小錯(cuò)誤,除了那些啟蒙編程課程外,在實(shí)際工作中幾乎不會碰到。

// 實(shí)例化一個(gè)錯(cuò)誤對象
var err error

不錯(cuò),這個(gè)注釋很清楚,但不是非常有用。不過同時(shí),它實(shí)際上也沒有什么壞處。

在瀏覽代碼時(shí),雖然有些不待見,但也很容易被忽略。如果開發(fā)者能夠在其中包含一個(gè)有用的注釋,能夠節(jié)省我數(shù)小時(shí)鍵盤工作時(shí)間的話,我寧愿看成百這樣的簡單注釋,而不是沒注釋。

我非常確信,不會有任何代碼會說“伙計(jì),這段代碼非常容易理解,所以不需要提供任何注釋?!?實(shí)際情況恰恰完全相反。

實(shí)際上,我找到了一些嚴(yán)重缺失注釋的代碼 - Go 標(biāo)準(zhǔn)庫。它的代碼非常精良,但在很多情況下,如果在讀取代碼前對其功能沒有深刻理解,那么理解他們?yōu)槭裁催@么設(shè)計(jì)將是個(gè)挑戰(zhàn)。如果能加一些注釋,用于解釋代碼的邏輯和設(shè)計(jì)意圖,將使 Go 標(biāo)準(zhǔn)庫更加容易閱讀。在這篇文章中,我主要討論實(shí)現(xiàn)代碼里的注釋,而不是通常的公開函數(shù)的文檔注釋(通常情況下,它們也是非常棒的)。

任何注釋勝過無注釋

另外一個(gè)反注釋者喜歡拿出來的例子,可以用下面的簡潔有力的圖片來展示(證明其論點(diǎn)):

哈,極好笑的,有人更換了瓶子里面的東西但是沒有更新外面的標(biāo)簽。

但是,這是 20 年前的問題了,當(dāng)時(shí)通常不進(jìn)行代碼審查。不過,現(xiàn)在代碼審查已經(jīng)非常普遍了。如果檢查注釋和實(shí)現(xiàn)是否匹配不是你們代碼審核流程的一部分,那么最好檢查一下你們的代碼審核流程。

這不是說不會犯錯(cuò)誤,實(shí)際上我昨天剛提交了一個(gè)“注釋和實(shí)現(xiàn)不一致”的 bug。類似“無注釋比錯(cuò)誤注釋好”的言論初聽起來是正確的,然而,當(dāng)你認(rèn)識到如果沒有注釋,開發(fā)人員猜錯(cuò)代碼的功能比錯(cuò)誤注釋的出現(xiàn)的概率高的多的時(shí)候,你會改變你的看法。

即使這種情況真的發(fā)生,代碼被修改了,你依然可以獲取有價(jià)值的信息:代碼以前的用途。修改僅僅和原先有些許不同罷了,它依舊完成基本相同的功能。為了版本控制和向后兼容,同一個(gè)函數(shù)在不改變名稱和簽名的情況下,在功能上發(fā)生劇烈變化的頻率有多少?基本上非常少。

就拿我昨天發(fā)現(xiàn)的 bug 來說,我們調(diào)用 client.SetKeepAlive(60)。而 SetKeepAlive 函數(shù)的注釋是 “SetKeepAlive 在發(fā)送 PING 請求之前,客戶端需要等待指定數(shù)量的時(shí)間(以秒為單位)”??瓷先ズ馨簦皇菃??知道我注意到 SetKeepAlive 的參數(shù)是 time.Duration。

如果沒有其他指定的單位,60 這個(gè)整數(shù)將使用 Go 的 duration 的缺省單位納秒。哎,某人更新了該函數(shù),使用 Duration 類型來替換 Int。有趣的是,它仍然向下取整到了最接近的秒數(shù),所以注釋不是不正確,只是有些誤導(dǎo)罷了。

為什么?

最重要的注釋是為什么要注釋。為什么代碼是按照設(shè)計(jì)來執(zhí)行的?為什么這個(gè) ID 需要小于 24 個(gè)字符?為什么要在 Linux 下面隱藏這個(gè)選項(xiàng)?諸如此類。這些問題為什么重要的原因是你無法從代碼中提煉出來。這些注釋總結(jié)了開發(fā)者獲得的經(jīng)驗(yàn)教訓(xùn),商業(yè)或系統(tǒng)層面的限制條件等,它們是價(jià)值無量的,并且?guī)缀鯚o法從其他途徑獲得(例如,函數(shù)取名應(yīng)該反映函數(shù)做什么而不是為什么)。

那些用于說明代碼功能的注釋往往不是特別有用的,因?yàn)槿绻麚碛凶銐虻臅r(shí)間和努力,你總能夠理解代碼的功能。本質(zhì)上,通過函數(shù)定義,代碼往往會告訴你它的具體功能,但這不意味著你不應(yīng)該寫任何注釋。確實(shí)應(yīng)該力爭寫出最清晰簡潔的代碼,但是注釋不需要任何額外的運(yùn)行時(shí)開銷,如果你覺得有人會錯(cuò)誤理解一些代碼或者理解上有困難,應(yīng)該寫上一些注釋。至少,這個(gè)會節(jié)省他們半個(gè)小時(shí)來理解你的代碼,這些注釋也會在很大程度上幫助他們避免錯(cuò)誤地修改或使用你的代碼,從而導(dǎo)致 bug 的產(chǎn)生。

測試

一些人認(rèn)為函數(shù)的功能測試案例就相當(dāng)于文檔。某種程度上說,確實(shí)是這樣的。但是,在我的效率文檔表中,它的優(yōu)先級非常低。為什么呢?因?yàn)樗鼈儤O其精確而且瑣碎,僅僅覆蓋了功能的很少一部分。每一個(gè)測試僅確切地測試一個(gè)特定的輸入和與之相配的輸出。任何超過一個(gè)簡單函數(shù)的情況,你很可能需要一大串代碼來構(gòu)建輸入和輸出。

對于大多數(shù)編碼而言,描述一個(gè)函數(shù)的主要功能比寫代碼去完整測試要容易的多。

很多時(shí)候我的測試代碼行數(shù)倍于函數(shù)實(shí)現(xiàn)本身,然而文檔注釋僅僅需要寥寥幾行而已。

此外,測試僅僅解釋了函數(shù)的功能。函數(shù)的設(shè)計(jì)功能是什么?它們不能解釋為什么,但是就像前面提到的,設(shè)計(jì)目的和意圖總是更重要的。

你確實(shí)應(yīng)當(dāng)測試你的代碼,通過一些邊界測試案例,測試對于判定代碼在邊界條件下是否能夠正常工作非常有用。但是一般而言,如果到了必須通過閱讀測試案例來理解代碼的地步的話,那么已經(jīng)是一個(gè)危險(xiǎn)信號,告訴我們需要去編寫更多更好的注釋了。

結(jié)論

除了一些非常簡單的例子以外, 有用注釋和無用注釋的邊界是非常難于去發(fā)現(xiàn)的。

所以,我寧愿人們站在多寫注釋的一方。你無法知道下一個(gè)可能閱讀你代碼的人是誰,所以能幫助他們的是盡你所能寫上一大堆的注釋。盡量寫到你認(rèn)為太多了,然后再多寫一些,這個(gè)數(shù)量估計(jì)就正好了。

審核編輯:彭靜
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4375

    瀏覽量

    64470
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4891

    瀏覽量

    70402
  • BUG
    BUG
    +關(guān)注

    關(guān)注

    0

    文章

    156

    瀏覽量

    15979

原文標(biāo)題:淺談 Go 語言代碼注釋問題

文章出處:【微信號:magedu-Linux,微信公眾號:馬哥Linux運(yùn)維】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點(diǎn)推薦

    itop-3568開發(fā)板機(jī)器視覺opencv開發(fā)手冊-圖像繪制-畫線

    函數(shù)功能: 繪制一條直線。 函數(shù)原型: cv2.line(img,pt1,pt2,color,thickness=None,lineType=None,shift=None) 參數(shù)定義: img
    發(fā)表于 06-04 10:38

    詳解RTOS中的Hook函數(shù)

    Hook函數(shù)是RTOS中的一個(gè)關(guān)鍵特性,通過該函數(shù),用戶可以增強(qiáng)對任務(wù)管理的控制,定義系統(tǒng)行為。
    的頭像 發(fā)表于 03-24 16:14 ?323次閱讀

    基于瑞薩RA0E1開發(fā)板的ThreadX實(shí)時(shí)操作系統(tǒng)串口回顯測試

    感謝立創(chuàng)提供測試機(jī)會,學(xué)到RA0及瑞薩MCU的相關(guān)使用。使用瑞薩FSP庫和配置工具大大簡化了開發(fā)過程。掌握相關(guān)函數(shù)功能,如打開串口、設(shè)置串口參數(shù)、讀取和寫入串口數(shù)據(jù)等。
    的頭像 發(fā)表于 02-25 09:27 ?450次閱讀
    基于瑞薩RA0E1開發(fā)板的ThreadX實(shí)時(shí)操作系統(tǒng)串口回顯測試

    迅為RK3568開發(fā)板篇Openharmony配置HDF控制UART-UART 接口運(yùn)作機(jī)制

    UART 設(shè)備傳輸模式,關(guān)閉 UART 設(shè)備的接口。 ? 核心層主要提供 UART 控制器的創(chuàng)建,移除以及管理的能力,通過鉤子函數(shù)與適配層交互。 ? 適配層主要是將鉤子函數(shù)功能實(shí)例化,實(shí)現(xiàn)具體的
    發(fā)表于 02-19 10:41

    用51單片機(jī)控制TLV5618進(jìn)行數(shù)模轉(zhuǎn)換,想利用+1.024內(nèi)部參考電壓,芯片REF引腳要怎么接,是懸空還是接地?

    (uint Dignum) // 函數(shù)功能 :進(jìn)行DA轉(zhuǎn)換 // 入口參數(shù) :Dignum:根據(jù)說明設(shè)置轉(zhuǎn)化數(shù)據(jù).頭四位為特殊位用于選擇轉(zhuǎn)化方式, // 以及用于通道選擇.請自行設(shè)置.后12位為需要轉(zhuǎn)換的值
    發(fā)表于 01-08 07:56

    各類Modbus功能接口函數(shù)詳解

    函數(shù)對應(yīng)于功能碼01(0x01)讀取線圈/離散量輸出狀態(tài)(Read CoilStatus/DOs),其中,所讀取的值存放于參數(shù)uint8_t * dest指向的數(shù)組空間因此dest指向的空間必須足夠大,其大小至少為nb * sizeof(uint8_t)個(gè)字節(jié)。
    的頭像 發(fā)表于 12-11 17:12 ?2455次閱讀
    各類Modbus<b class='flag-5'>功能</b>接口<b class='flag-5'>函數(shù)</b>詳解

    SUMIF函數(shù)對比VLOOKUP的優(yōu)勢

    功能和使用場景上有所不同。 SUMIF函數(shù)簡介 SUMIF函數(shù)是Excel中用于條件求和的函數(shù)。它的基本語法是: SUMIF (range, criteria, [sum_range]
    的頭像 發(fā)表于 11-11 09:16 ?1138次閱讀

    SUMIF函數(shù)與SUMIFS函數(shù)的區(qū)別

    SUMIF函數(shù)和SUMIFS函數(shù)都是Excel中用于條件求和的函數(shù),它們可以幫助用戶根據(jù)特定的條件對數(shù)據(jù)進(jìn)行求和。盡管它們的基本功能相似,但在使用場景和
    的頭像 發(fā)表于 10-30 09:51 ?7187次閱讀

    SUMIF函數(shù)使用教程

    SUMIF函數(shù)是Excel中非常實(shí)用的函數(shù)之一,能夠根據(jù)指定條件對數(shù)據(jù)進(jìn)行篩選和求和操作。以下是對SUMIF函數(shù)使用方法的詳細(xì)教程: 一、基本語法 SUMIF函數(shù)的基本語法為: =SU
    的頭像 發(fā)表于 10-30 09:50 ?2014次閱讀

    如何由系統(tǒng)函數(shù)求頻率響應(yīng)

    頻率響應(yīng)函數(shù)表征了測試系統(tǒng)對給定頻率下的穩(wěn)態(tài)輸出與輸入的關(guān)系,可以通過系統(tǒng)函數(shù)(或稱為傳遞函數(shù))來求解。以下是由系統(tǒng)函數(shù)求頻率響應(yīng)的步驟: 一、理解系統(tǒng)
    的頭像 發(fā)表于 10-18 09:32 ?3369次閱讀

    什么叫系統(tǒng)的頻率響應(yīng)函數(shù)?它和傳遞函數(shù)有何關(guān)系

    系統(tǒng)的頻率響應(yīng)函數(shù)(Frequency Response Function, FRF)是描述線性時(shí)不變(Linear Time-Invariant, LTI)系統(tǒng)在不同頻率下輸入和輸出之間關(guān)系的數(shù)學(xué)
    的頭像 發(fā)表于 10-18 09:29 ?4533次閱讀

    為什么按鍵后串口收到很多組相同的數(shù)據(jù)?

    名 : uart_init 函數(shù)功能 : 串口通信中斷配置函數(shù),通過設(shè)置TH和TL即可確定定時(shí)時(shí)間 輸 入 : baud:波特率對應(yīng)的TH、TL裝載值 輸 出: 無
    發(fā)表于 09-28 21:19

    面試???1:函數(shù)指針與指針函數(shù)、數(shù)組指針與指針數(shù)組

    在嵌入式開發(fā)領(lǐng)域,函數(shù)指針、指針函數(shù)、數(shù)組指針和指針數(shù)組是一些非常重要但又容易混淆的概念。理解它們的特性和應(yīng)用場景,對于提升嵌入式程序的效率和質(zhì)量至關(guān)重要。一、指針函數(shù)函數(shù)指針指針
    的頭像 發(fā)表于 08-10 08:11 ?1407次閱讀
    面試???1:<b class='flag-5'>函數(shù)</b>指針與指針<b class='flag-5'>函數(shù)</b>、數(shù)組指針與指針數(shù)組

    【CH32V208】2、體驗(yàn)systick

    ); } 此函數(shù)功能為輸出一個(gè)計(jì)算值,并在串口中輸出,以便觀察 5、主程序中,我們傳一個(gè)配置溢出值為系統(tǒng)時(shí)鐘-1即1秒種進(jìn)入一次中斷。 【實(shí)驗(yàn)現(xiàn)象】 下載到開發(fā)板后,打開串口終端,可以成功實(shí)現(xiàn)即定功能
    發(fā)表于 07-31 09:37

    tcpip_adapter_start_api 函數(shù)功能是什么?

    , msg->mac, msg->ip_info); } 請問 1. tcpip_adapter_start_api函數(shù)功能是什么??或者說tcpip_adapter_start中調(diào)用
    發(fā)表于 06-26 07:08

    電子發(fā)燒友

    中國電子工程師最喜歡的網(wǎng)站

    • 2931785位工程師會員交流學(xué)習(xí)
    • 獲取您個(gè)性化的科技前沿技術(shù)信息
    • 參加活動獲取豐厚的禮品