在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

函數的設計功能是什么

馬哥Linux運維 ? 來源:馬哥Linux運維 ? 作者:馬哥Linux運維 ? 2022-11-01 10:19 ? 次閱讀

每隔一段時間,網上總會突然出現一些令人討厭的帖子,其觀點是:不應該為代碼寫注釋,它存在的唯一原因是因為代碼本身不足夠好。對于這些論點,我完全不能茍同。

爛代碼

他們的觀點也不完全是錯誤的。沒有人能說自己的代碼足夠好。代碼本身也會慢慢變壞。你知道什么時候代碼腐爛得最厲害嗎?當你六個月沒有碰這些代碼的時候!

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

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

今天,當整個項目和問題空間都裝在你的腦袋里的時候,你自然會覺得代碼是干凈、清晰和優雅的。但是,當六個月后,又或是 CTO 剛好在生產系統上突然發現一個非常嚴重的 bug,在主管緊盯的情況下,某個可憐的家伙不得不去調試你的代碼的時候,這些代碼可能對你已經有些模糊了。

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

所以,寫上一個即使在現在看來過于淺顯的注釋也不是一個壞事情。有時候,它甚至會帶來巨大的幫助。

無注釋經常導致代碼更難以理解

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

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

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

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

小函數的相關問題在 Cindy Sridharan 在 medium 網站上的帖子[1]中有更加詳細的闡述。

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

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

沒有壞注釋

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

// 實例化一個錯誤對象
var err error

不錯,這個注釋很清楚,但不是非常有用。不過同時,它實際上也沒有什么壞處。

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

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

實際上,我找到了一些嚴重缺失注釋的代碼 - Go 標準庫。它的代碼非常精良,但在很多情況下,如果在讀取代碼前對其功能沒有深刻理解,那么理解他們為什么這么設計將是個挑戰。如果能加一些注釋,用于解釋代碼的邏輯和設計意圖,將使 Go 標準庫更加容易閱讀。在這篇文章中,我主要討論實現代碼里的注釋,而不是通常的公開函數的文檔注釋(通常情況下,它們也是非常棒的)。

任何注釋勝過無注釋

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

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

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

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

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

就拿我昨天發現的 bug 來說,我們調用 client.SetKeepAlive(60)。而 SetKeepAlive 函數的注釋是 “SetKeepAlive 在發送 PING 請求之前,客戶端需要等待指定數量的時間(以秒為單位)”。看上去很棒,不是嗎?知道我注意到 SetKeepAlive 的參數是 time.Duration。

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

為什么?

最重要的注釋是為什么要注釋。為什么代碼是按照設計來執行的?為什么這個 ID 需要小于 24 個字符?為什么要在 Linux 下面隱藏這個選項?諸如此類。這些問題為什么重要的原因是你無法從代碼中提煉出來。這些注釋總結了開發者獲得的經驗教訓,商業或系統層面的限制條件等,它們是價值無量的,并且幾乎無法從其他途徑獲得(例如,函數取名應該反映函數做什么而不是為什么)。

那些用于說明代碼功能的注釋往往不是特別有用的,因為如果擁有足夠的時間和努力,你總能夠理解代碼的功能。本質上,通過函數定義,代碼往往會告訴你它的具體功能,但這不意味著你不應該寫任何注釋。確實應該力爭寫出最清晰簡潔的代碼,但是注釋不需要任何額外的運行時開銷,如果你覺得有人會錯誤理解一些代碼或者理解上有困難,應該寫上一些注釋。至少,這個會節省他們半個小時來理解你的代碼,這些注釋也會在很大程度上幫助他們避免錯誤地修改或使用你的代碼,從而導致 bug 的產生。

測試

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

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

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

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

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

結論

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

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

審核編輯:彭靜
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 函數
    +關注

    關注

    3

    文章

    4331

    瀏覽量

    62618
  • 代碼
    +關注

    關注

    30

    文章

    4788

    瀏覽量

    68612
  • BUG
    BUG
    +關注

    關注

    0

    文章

    155

    瀏覽量

    15669

原文標題:淺談 Go 語言代碼注釋問題

文章出處:【微信號:magedu-Linux,微信公眾號:馬哥Linux運維】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    各類Modbus功能接口函數詳解

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

    SUMIF函數與SUMIFS函數的區別

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

    為什么按鍵后串口收到很多組相同的數據?

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

    【CH32V208】2、體驗systick

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

    tcpip_adapter_start_api 函數功能是什么?

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

    接口測試的工具有哪些種類

    單元測試框架 單元測試框架主要用于測試單個模塊或函數功能。雖然它們主要用于開發階段,但也可以用于接口測試。 1.1 JUnit (Java) JUnit 是 Java 語言的單元測試框架,支持自動化測試,可以測試 Java 編寫的接口。 1.2 NUnit (C#)
    的頭像 發表于 05-30 15:07 ?715次閱讀

    求助,關于在STM8S用FOR遇到的疑問求解

    我用了一塊STM8F103F3P,TSSOP20封裝的最小系統板,直接連接WS2811的燈條,用數組來存貯要發送的數據,發送是這樣寫的: /*********************** 函數功能
    發表于 05-16 07:30

    函數信號發生器的定義、功能及應用

    隨著現代電子技術的飛速發展,電子測試設備在科研、生產、教育等領域的應用越來越廣泛。其中,函數信號發生器作為一種重要的電子測試設備,在電子工程、通信、科研等領域發揮著至關重要的作用。本文將詳細介紹函數信號發生器的定義、分類、功能
    的頭像 發表于 05-15 14:42 ?1757次閱讀

    STM32F3執行函數的時候進入HardFault_Handler死循環,怎么處理?

    + (uint32_t)(dataRx1 << 16)); return *Result; } 執行這個函數的時候進入HardFault_Handler死循環,求助怎么處理?函數功能是從某個芯片中讀取兩個字,網上
    發表于 05-13 07:35

    STM32片上flash能否讀取正在運行的代碼段內容?

    如題 小弟想請教下大家 STM32片上flash的讀取問題。舉個例子: 函數功能是 讀取片上flash 0x0800_1000~0x0800_2000的存儲內容 函數存儲在flash的 0x0800_1000~0x0800_2
    發表于 04-16 07:22

    求助,關于STM32F3系列啟動時SWD的配置問題求解

    求助:小弟現在使用STM32F373RCT6這款芯片,原來使用F103的,由于IO資源使用比較緊湊,基本沒什么剩余IO,所以在system_stm32f1xx.c中增加了一個函數
    發表于 04-09 06:12

    現場可編程門陣列的基本結構和優缺點

    主要由查找表(LUT)和D觸發器(DFF)等邏輯電路構成。查找表用于實現邏輯函數功能,而D觸發器則用于存儲邏輯狀態。嵌入式塊RAM提供了額外的存儲空間,布線資源則負責各個邏輯單元之間的連接。
    的頭像 發表于 03-27 14:49 ?609次閱讀

    使用CubeMX配置STM32010C6T6的LPUART1外設,調用串口發送和接收函數均不能收發數據怎么解決?

    串口初始化文件中將RX引腳模式更改為輸入類型同樣不能接收到數據 在CubeMX中更換MCU型號為F103系列并配置串口,則RX引腳默認為輸入模式,并且生成的工程調用串口收發函數功能正常 這種現象是不是CubeMX軟件導致的問題呢,應該如何解決(生成的工程默認沒有使能串口,
    發表于 03-19 07:48

    【RISC-V開放架構設計之道|閱讀體驗】匯編語言和擴展指令集

    函數可訪問的位置; 2)跳轉到函數入口(使用RV32I的jal指令); 3)獲取函數所需的局部存儲資源,按需保存寄存器; 4)執行函數功能
    發表于 02-03 13:29

    ADT7310讀取數據波動較大是什么原因導致的?

    PORTB= ~BIT(CS) //片選關 /* 函數功能: SPI初始化 */ void Spi_Init(void) { //使能SPI,先發送MSB //主機模式,SPI工作在模式0
    發表于 01-02 07:37
    主站蜘蛛池模板: 欧美三四级片| 一卡二卡卡四卡无人区中文| 天天cao在线| 久久深夜福利| 男人日女人免费视频| 5g成人影院| 成 人 在 线 免费 8888 www| 亚洲v在线| 欧美成人午夜视频| 操狠狠| 日韩爱爱| 黄色片xxx| 在线三级网| 日本免费精品视频| 国产精品九九久久一区hh| 天天干天天草天天| 欧美高清xx| 又色又爽又黄视频| 黄色一级片视频| 色综合成人| 皇帝受h啪肉np文| 欧美一级黄色录相| 1000部啪啪未满十八勿入中国| 久热国产精品| 亚洲人成电影在线| 开心综合网| 天天操天天插天天干| 久久精品国产精品亚洲人人| 日本三级免费| 日日插天天操| 一级毛片免费网站| 精品国模| 亚洲国产日韩欧美在线as乱码| 在线视频观看你懂的| 国产caob| 国产破苞合集 magnet| 综合色爱| 九九色网站| 尻逼久久| 色婷婷精品| 亚洲精品视频在线|