你代碼的異味是故意的還是不小心?是故意的!
原創-
2023-02-28 17:32:52
-
2784
本篇目錄
一、代碼竟會有“氣味”
食物在腐烂之际,会散发出异味,提醒人食物已经坏掉了,需要处理。同样,如果代码中某处出现了问题,也会有一些症状。这些症状,被称之为“代碼異味”(Code smell,也译作“代码味道”)。与食物腐败发出的味道不同的是,代碼異味并非真正的气味,而是一种“暗示”,暗示我们代码可能有问题,提示程序员需要对项目设计进行更进一步的查看。

代碼異味的产生原因跟厨师的“清洗过程中故意保留”不一样,它更多地并非刻意为之,创造者也未必“品尝”过自己所写的代码,它更多地是由于设计缺陷或不良编码习惯而导致的不良代码症状。
這種異味也並非來自一種有據可查的標准,更多的是來自程序員的直覺。尤其是經驗豐富和知識淵博的程序員,他們無需思考,只要通過查看代碼或一段設計就可以立馬對這個代碼質量産生這種“感覺”,能對代碼設計的優劣有一個大致的判斷。這有點類似我們英語學到一定程度後,即便不能完全看懂文章,但憑借語感也能選出正確答案。
二、 代碼異味的影响
一般情況下,有“異味”的代碼也依舊能運行得很好。只是倘若重視不夠,沒有適當地維護或改進代碼,代碼質量就會下降,系統也會開始變得難以維護和擴展,同時也會增加技術債務。這就像做出有異味的九轉大腸的的小胖廚師,在前期准備中對評委的建議置若罔聞,一意孤行,做出來的菜連自己都難以下咽。
所以團隊應盡可能地做有質量的代碼,減少甚至避免這些問題,産生高效益的成果。
三、 如何辨别代碼異味
代码是否存在代碼異味,通常是靠程序员的主观判断,但由于语言、开发者、开发理论的不同,对代碼異味的判断也会存在差异。
所以要想更精准地识别代碼異味,获得更高的代码质量,程序员需要大量的实践和经验。不过,前辈们总结的经验也可以让我们少走一些弯路。Martin Fowler在《重构:改善既有代码的设计》一书中,列举了最常见的24种代碼異味,可以幫助我们轻松识别,便于处理和改善它们:

1) 过大的类(Large Class)
一個類包含許多字段、方法或者代碼行,並逐漸變得臃腫。2) 数据泥团(Data Clumps)
代碼的不同部分包含了相同的變量組,且這些數據總是綁在一起出現。3) 过长参数列表(Long Parameter List)
指一個方法的參數超過了三個或四個。出現這種情況一般是將幾種類型的算法合並到一個方法之後。4) 基本类型偏执(Primitive Obsession)
創建一個原始字段比創建一個全新的類要容易得多,所以對于具有意義的業務概念如錢、坐標、範圍等,很多程序員不願意進行建模,而是使用基本數據類型進行表示,進而導致代碼內聚性差、可讀性差。
5) 神秘命名(Mysterious Name)
在編程中,命名是一件非常惱人的事情。一些可能只有自己看懂的命名,無疑加大了代碼可讀性的難度,有時甚至自己也會忘記這些命名的含義。
6) 重复代码(Duplicated Code)
這幾乎是最常見的異味。當多個程序員同時處理同一程序的不同部分時,通常會發生這種情況。
7) 过长的函数(Long Function)
根据Martin Fowler的经验,通常活得最长、最好的程序,其中的函数都比较短。函数越长,就越难理解。
8) 全局数据(Global Data)
這是一個非常可怕且刺鼻的異味代碼。因爲從代碼庫的任何一個角落都可以修改它,而且沒有任何機制可以探測出到底是哪段代碼做出了修改。全局數據造成一次又一次的詭異Bug,讓我們很難找出出錯的代碼。
9) 可变数据(Mutable Data)
如果可变数据的变量的作用域越大, 越容易出现问题。变量是可以更改的,但我们可能不知道是哪里改变了它。
10) 发散式变化(Divergent Change)
是指一個類受到多種變化的影響。
11) 霰弹式修改(Shotgun Surgery)
是指一種變化引發多個類相應修改。
12) 依恋情结(Feature Envy)
一個類使用另一個類的內部字段和方法的數據多于它自己的數據。

在不同的地方反複使用switch邏輯。這帶來的問題就是當我們想要增加一個選擇分支時,就必須找到所有的switch,並逐一更新。
14) 循环语句(Loops)
在编程语言中,循环一直是程序设计的核心要素。在《重构》中,Martin Fowler认为它是一种代碼異味,因为他们觉得如今的循环已经有点过时了。他们提出“以管道取代循环”,这样可以幫助我们更快看清被处理的元素以及处理它们的动作。
15) 冗赘的元素(Lazy Element)
這是幾乎無用的組件。我們在設計代碼時有時爲了未來的功能設計出“預備”代碼,但實際上從未實現;又或者這個類本來有用但隨著重構,越來越小,最後只剩下一個函數。無論哪種,它們都是冗贅無用的。
16) 推测的通用性(Speculative Generality)
是指爲了“以防萬一”,支持預期的未來功能,但這些功能並未被實現,這些類、方法、字段或參數也從未被使用,結果導致代碼變得難以理解和支持。
17) 临时字段(Temporary Field)
創建臨時字段以用于需要大量輸入的算法。但這些字段僅在算法中使用,其余時間不使用。
18) 过长的消息链(Message Chains)
當客戶端請求另一個對象,該對象又請求另一個對象,依此類推時,就會出現過長的消息鏈。這些鏈意味著客戶端依賴于類結構的導航。一旦發生更改,客戶端也要跟著修改。
19) 中间人(Middle Man)
指一個類只執行一個動作,但將工作委托給另一個類,這種委托屬于過度委托。該類也可能只是一個空殼,只負責委托且只有一件事。
20) 内幕交易(Insider Trading)
指模塊之間大量地交換數據,增加模塊之間的耦合。
21) 异曲同工的类(Alternative Classes with Different Interface)
是指兩個類執行了相同的功能但具有不同的方法名稱。
22) 纯数据类(Data Class)
指包含字段和访问它们的粗略方法(getter 和 setter)的类。这些只是其他类使用的数据容器。这些类不包含任何附加功能,并且不能独立操作它们拥有的数据。
23) 被拒绝的遗赠(Refused Bequest)
指如果子類複用了超類的行爲,但又不願意支持超類的接口的情況。
24) 注释(Comments)
程序員將其作爲一種“除臭劑”使用情況下的行爲。比如:一段代碼有著長長的注釋,但這段長注釋的存在是因爲代碼很糟糕。
四、 如何对代码“除臭”

1)重構
上述代碼異味没有优先级一说,所以对于程序员而言,只能依靠直觉和经验去决定是否需要重构。
重構,一言以蔽之,就是在不改變外部行爲的前提下,有條不紊地改善代碼。是實現敏捷性的最重要的技術因素之一。是程序員根據已識別出的氣味然後將代碼分成更小的部分的過程,再決定要麽刪除它們,要麽用更好的代碼替換它們,如此循環重複這個過程,直到異味消失,這樣可能會提高代碼質量並讓代碼變得更具簡單性、靈活性和可理解性。
2)使用代碼檢測工具
识别和消除代碼異味是一个令人厌烦且不确定的过程,而且也不可能手动查找到和删除掉所有异味,尤其是面对一个有着上千行异味的代码的时候。所以使用一些代码检测工具可以辅助我们进行快速大量地审查,幫助我们节约时间来做更为重要的工作,比如能专注于代码高层面的设计原则问题。
好了,关于代碼異味的知识,算是讲了个清楚,那么让我们相约下一次代码评审吧!
-
禅道産品
禅道開源版 禅道企業版 禅道旗艦版 禅道IPD版 -
核心功能
産品管理 項目管理 質量管理 效能管理 -
使用文檔
基本版手冊 企業版手冊 旗艦版手冊 IPD版手冊 開發中心手冊 -
幫助中心
积分問答 常見問題 論壇交流 使用視頻 Gitee GitHub -
關于我們
關于我們 禅道軟件 最新動態 禅道活動 -
禅道社區
禅道博客 積分排行 積分商城 禅道書院 -
聯系方式
聯系人:金娟 電話:18562856230 微信:18562856230 Q Q:1826606239北京、上海、深圳分部