你的代碼會說話嗎?(下)

篇首語

代碼不講真話的直接後果是所有人被誤導了,然後做了一件錯誤的事情,不自知地將錯就錯,讓錯誤越陷越深,最後浪費寶貴的時間。可不講真話,編寫代碼的人又不是故意的,也萬萬不可上綱上線,袁帥秉着內訓師作爲知識沉澱者和文化傳播者角色的原則,藉助教育代碼的機會組織了一次部門內部的閒聊會,並美其名曰:Clean Code交流會。本文分爲上下兩篇,此爲下篇,上篇內容請參見你的代碼會說話嗎?(上)

講真話了嗎?

週五,是一個心情放鬆的日子,距離年會過去也快整整一週了。袁帥也趁此機會召集了團隊的幾名開發在線學習系統的小夥伴來碼聊。看起來是一次不經意的安排,其實他早有準備。

僞修飾

會議室裏,袁帥開門見山:“最近跟一個北美 BP 在協商給他們大客戶團隊的骨幹成員強化敏捷工程實踐,現在很多部門內訓有一套敏捷工程實踐課程。但是很有意思的是,這個BP跟我線上會議溝通時,從來不一步到位,總會在微信上再跟我發文字再解釋一遍,也不知道是我看着傻,還是她認爲我癡呆。”

大家被袁帥這開場給逗樂了,拋給他好奇的目光。

“沒講清楚唄,再給你講一遍。”清揚一副若無其事的樣子。

“嗯,她擔怕開會沒講清楚,想再跟我解釋一遍,而且每次微信上的留言比她會議上講的要更明確更具體。所以,後來慢慢地我習慣在會議上忽視她提供的信息,直接看她的微信留言。”

“那你們還幹嘛開會呀,不是白費時間嗎!” 萬正義直率地補充道。“可是,有時候她在後續的會議上又把之前留言的內容給更新了卻忘了再給我留言。” 袁帥表現得無辜。

“所以,你仍然按照微信留言的信息,結果誤解了真實的意思!” 清揚有搶答道。

“嗐,你還別提,我最近都沒跟活人打交道,也總是遇到這種煩惱。” 劉歡歡一臉滿腹牢騷的表情。

“是嘛,說來聽聽?”袁帥故作驚訝般試探道。

註釋啊,最近看到一些代碼的註釋,本來不看註釋花點時間琢磨琢磨代碼,還能搞清楚代碼在做什麼,可是有時想走捷徑,瞅了眼註釋,發現註釋是錯的,騙的我團團轉,被謊言帶節奏真不爽!” 歡歡打趣地補充。

“對的,這就跟我提到的那個BP類似,總習慣加一些修飾,本來初心是好的,是想解釋得更清楚,可是修飾只是一種補充信息,有時候原始信息變更了,修飾卻沒有跟着更新,不但沒有起到修飾作用,反而會誤導別人,很耽誤事兒!” 袁帥同情地回覆了正義。

說白了,還是沒有想清楚,代碼要做什麼事情,然後覺得需要通過註釋去解釋一下,後面代碼改了,大概率是不會修改註釋的。” 正義總是話裏充滿着正義。

“可能是使用中文註釋讀起來更順暢吧,因爲代碼不太好用中文命名”。程曉娜以理解的口吻弱弱地補充了一句。

袁帥突然陷入了沉思,腦海裏浮現出兩個畫面:

  1. 他曾經輔導過的某些程序員,因爲英語功底不好,很難將中文翻譯成恰當的英文,這在一定程度限制了他們,即便有翻譯工具的輔助。
  2. 有一次爲了給一個方法起名字,他跟三個10多年的工作經驗的技術Leader一起討論了10來分鐘,最後才搞定,但大家很開心。

爲什麼要寫註釋啊?代碼自解釋不香嗎?只有代碼沒法自解釋的時候才用一下注釋還能接受!” 正義越發正義起來。

“可有時方法太長了,做的事情比較多,每一段相關的代碼用註釋說明一下在做什麼也不是不可取的吧?”清揚見縫插針地拋了個問題。

“Talk is cheap,show me the code!”袁帥展示了準備好的代碼:

“2分鐘時間,大家先仔細閱讀這幾段段代碼,把你看到的問題和建議改進措施發到咱們的討論羣裏哈。”

5分鐘後,袁帥把所有人的答案彙總起來:

  • 示例1:類上的註釋完全沒必要,因爲VCS工具能夠很好地做記錄。
  • 示例1:構造方法方法上的註釋是冗餘的,構造器本身就能表達構造對象,參數也能表達傳入的東西。
  • 示例2:方法的註釋的確起到了解釋作用,但是讓方法自解釋更香:更名爲listByStatus後幹掉註釋。

緊接着,袁帥再拋出一個複雜的示例:

大家花了3分鐘找出問題:

  • 示例3:方法太長,中間分段註釋解釋做什麼的可以抽取方法,然後將註釋轉換成方法名來表達意圖。
  • 示例3:printReceipt方法內打印日期和客戶忠誠度註釋過期了,實際上代碼被註釋掉了。
  • 示例3:printReceipt方法內那個稅率寫的是15%,而實際用的10%,誤導讀者。

“註釋並不是一無是處,畢竟那誰講過 -- 「存在即合理」。註釋存在這麼多年,而且很多地方咱們也看到過。” 袁帥又恢復了主持人的狀態。

“有啊,「開放API文檔」到處都是API註釋,而且還要寫好看了。”

“最近有幾段代碼實在有些實現的難言之隱,我必須通過註釋來解釋一下。”

“嗯,我剛碰到過「法律版本信息」的一些註釋,白紙黑字的註釋聲明不能少。”

“魔術代碼可以註釋一下啊,比如複雜的郵件正則表達式:

/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;

袁帥對最後這一個補充有點感興趣,趁機提了個問題:“魔術代碼除了註釋,還有更好的方式嗎?”

引入「解釋性變量」啊,比如:emailMatcher。”清揚這次臨場發揮反應很快。

“大家怎麼看待「TODO | FIXME」這種註釋呢?”清揚緊接着有拋了個問題。

“不提倡,雖然它能幫助我們在本地記錄一些代辦列表,但儘可能及時處理完這些任務,將註釋清理掉,別提交到生產上。”正義的聲音覆蓋了全場。

袁帥朝清揚和正義點了個大拇指贊,簡單做了個總結:“有一些場景需要註釋的,當我們想要添加註釋的時候,我們首先應該想想代碼能否做到自解釋?

在收拾電腦之際,他腦海裏浮現出Uncle Bob關於註釋的一句話:

“註釋不同於《辛德勒的名單》。它們不是‘純善的’。事實上,註釋充其量是一種必要的惡。”

-- Robert C.Martin

行外話

老馬(Martin Fowler)的博客上有一句話:“There are only two hard things in Computer Science: cache invalidation and naming things.”。這句話不是老馬本人講的,老馬錶示很認同,袁帥也很認同,而且越來越信。

距離上一次的 Clean Code 交流會過去剛好一週,今天天氣格外晴朗,清揚饒有興致喊上袁帥去樓底下新開的小餐館炒倆菜。

兩人來到餐廳剛坐定,袁帥手機微信語音響起來,是隔壁團隊的 TL 石彪,想約他聊聊上次TDD工作坊後大家的落地情況和疑惑。

清揚伸手遞過菜單示意袁帥點個菜,他只說了個“青菜”繼續跟石彪聊了起來。清揚找了好一會也沒找到“青菜”,見袁帥聊得投入,就幫他點了個綠色的白灼生菜,還點了只清蒸桂花魚,外加兩份單人份的土雞湯和米飯。

10分鐘後,“青菜” 上來了,袁帥吃了兩口覺着不對勁:“咦,我點的是青菜啊,怎麼上了個生菜呢?”

“大哥,我盡力了,菜單沒有找到“青菜”,就點了個這咯。” 清揚一臉無辜。

“哦,我們那有一種叫“上海青”的蔬菜,平時我們都叫青菜。” 袁帥說完立即意識到自己現在身在北方,這邊的叫法跟老家可能不一樣。

“哈哈,我們西安把青菜理解成綠色的蔬菜~” 清揚說着就遞過來菜單。

看到 “清炒油菜”,袁帥心裏開始琢磨着:“不同地區(上下文),對同一個東西的叫法是可能不一樣的,如果切換了地區,自己還沿用原來地區的叫法,很可能造成困惑和誤解。

不同行業,不同領域,不同上下文,同物可不同名。你常常給我講寫代碼的時候要特別注意這一點,開發哪個行業的系統,就應該使用該行業的業務語言,有利於統一語言,交流起來效率會高很多,而且代碼跟業務相匹配,更容易理解。” 清揚猜到了袁帥在琢磨什麼,替他做了一個總結。

“你們的清蒸桂花魚,請慢用!” 服務員把香氣四溢的魚端到桌上,這是袁帥小時候特別喜歡的一道菜,他開心地拿起筷子正要去夾魚尾:“咦,剛纔服務員叫它清蒸桂花魚?” “對啊,桂花魚,清蒸的,營養健康,色香味俱全。”清揚麻利地迴應着。

袁帥拿起菜單看了一眼,嘴裏邊嘟囔邊若有所悟地點頭着:“在我老家這個菜叫「清蒸鱖魚」。”

清揚瞥了他一眼,作搖頭嘆息狀伸手去夾魚,開心地吃了起來。“小鬼厲害啊,竟然點了我最喜歡的魚,這頓飯我請了哈~” 袁帥這次快速從他的菜品命名的思緒中跳脫出來。

喫完飯回來,袁帥喊上清揚去看看隔壁石彪的團隊在做的Code Review,見到大屏幕上的代碼:

“小豹,這個FlyLine是指飛行路線嗎?” 石彪小心翼翼地問。

“嗯,是這個意思!”

“你在IDE搜一下【Route】” 只見小豹比較嫺熟地用快捷鍵定位到一個Route類:

看到這個類,小豹快速在正開着的Google翻譯框裏查到【Route:航線】。

“你打開Trello卡上的【航空術語】那張卡片上的有個航空術語鏈接。你打開頁面敲關鍵字【航線】進行搜索。”石彪見小豹下意識撓着頭不知所措,就進一步給了提示。

石彪10秒鐘的指尖操作後,大屏幕上將頁面展示出來:

“小豹剛來,對這些航空行業術語不熟悉可以理解,我提前給大家分享一條我的經驗:入行說行話,既然咱們在開發航空系統,我們就要講航空行話。” 石彪刻意掃視了所有在場的小夥伴,繼續說道:“那怎麼學會這些行話呢,翻譯工具是一個好助手,但有時它也會不靈,咱們團隊一直有在維護了一套專門的術語,上週我剛把它開發成Web版部署在內網服務器上了,咱們隨時可以在上面檢索術語哈。

石彪說完,小豹立刻示意結對的小夥伴在卡片上記下了一個Action:[ 更換Flight類中引用Flyline --> Route ]。

小結

如果說「域冗餘」、「碼尾禪」、「層錯綜」這些是代碼在溝通表達時的 偏形,那「僞修飾」、「行外話」這些就屬 **走神 **了,而這些貌合神離的假話更容易蠱惑人心。

寫代碼本沒什麼大事,努力打磨這五點,時刻審視代碼,時刻自省,軟件的可理解性可提升至少90%,沒錯就是很高。


文/Thoughtworks 袁慎建
原文鏈接:https://insights.thoughtworks.cn/how-to-write-clean-code-2/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章