簡介
Andrew Koenig在1995年造了 anti-pattern這個詞,靈感來自於GoF的《設計模式》一書。而這本書則在軟體領域引入了“設計模式”(design pattern)的概念。三年後antipattern因《AntiPatterns》這本書而獲得普及,而它的使用也從軟體設計領域擴展到了日常的社會互動中。按《AntiPatterns》作者的說法,可以用至少兩個關鍵因素來把反面模式和不良習慣、錯誤的實踐或糟糕的想法區分開來:
•行動、過程和結構中的一些重複出現的乍一看是有益的,但最終得不償失的模式
•在實踐中證明且可重複的清晰記錄的重構方案
很多反面模式只相當於是錯誤、咆哮、不可解的問題、或是可能可以避免的糟糕的實踐,它們的名字通常都是一些用反話構成的詞語。有些時候陷阱(pitfalls)或黑色模式(dark patterns)這些不正式的說法會被用來指代各類反覆出現的糟糕的解決方法。因此,一些有爭議的候選的反面模式不會被正式承認。
這個概念很容易推廣到工程學以及工程以外需要人們付出努力去爭取的領域。儘管在工程學以外很少用到這個術語,但其概念是通用的。
舉例
社會和組織結構
組織結構
•從天而降的責任(Accidental Ownership):雇員們接手了一個與當前系統完全無關的系統,在沒有合適的訓練、學習或關心下就得維護它
•分析癱瘓(Analysis paralysis):花費太多精力在項目的分析階段
•搖錢樹(cash cow):盈利的老產品通常會導致對新產品的自負
•委員會設計(Design by committee):很多人同時進行設計,卻沒有統一的看法
•承諾升級(Escalation of commitment):明知錯了還不能收回之前的決定
•獨裁管理(Management by perkele):用完全聽不進異議的獨裁作風進行管理
•目標管理(Management by objectives):通過數字管理,過於關注非本質而或不易取得的數字指標
•道德風險(Moral hazard):不讓做決定的人知道他的決定會帶來什麼結果
•蘑菇管理(Mushroom management):不通知或是錯誤地通知雇員信息。雇員像蘑菇一樣在黑暗中吸取養分,自生自滅
•煙囪或者發射塔(Stovepipe or Silos):結構上支持數據主要在上下方面的流動,卻禁止跨部門的通信
•供應商套牢(Vendor lock-in):使一個系統過於依賴外部提供的部件
項目管理
•雪崩模型(Avalanche):不合理的混合瀑布模型和敏捷開發。
•死亡征途(Death march):除了CEO,每個人都知道這個項目會成為一場災難,但是真相卻被隱瞞下來,以免項目被立即取消。(儘管CEO通常知道並且仍然繼續試圖最大化利潤。)然而,真相被隱藏起來,直到大限來臨 ("Big Bang")。另一種定義:雇員由於不合理的deadline,被迫在深夜和周末加班。
•團隊思維(Groupthink):在團隊思維中,團隊成員避免提出在一致觀點之外的思維。
•過度設計(Overengineering):花費資源完成比實際需要的還要魯棒和複雜的工程
•障眼法(Smoke and mirrors):展示還沒實現的功能,就像它們已經實現了一樣
•軟體膨脹(Software bloat):允許系統的後續版本使用更多的資源
分析方式
•旁觀冷漠(Bystander apathy):一個需求或者設計是錯的,注意到這一點的人卻不指出,因為這影響的是其他人。
軟體工程
軟體設計
•抽象倒置(Abstraction inversion):不把用戶需要的功能直接提供出來,導致他們要用更上層的函式來重複實現
•用意不明(Ambiguous viewpoint):給出一個模型(通常是OOAD,面向對象分析與設計)卻沒有指出用意何在
•大泥球(Big ball of mud):沒有清晰結構的系統
•用資料庫進行進程間通信(Database-as-IPC):使用資料庫進行進程間通信,而不使用更輕量級的合適的機制。
•鍍金(Gold plating):在項目達到最高價值後還繼續工作。
•內部平台效應(Inner-platform effect):系統可自定義的太多,以至於成為一個軟體開發平台的蹩腳的複製品。
•輸入問題(Input kludge):無法確定和實現對異常輸入的處理
•接口膨脹(Interface bloat):把一個接口做得過於強大以至於極其難以實現
•魔力按鍵(Magic pushbutton):直接在接口的代碼里編寫實現,而不使用抽象
•競爭風險(Race hazard):輸出結果受到事件執行順序和時機的影響,在多執行緒環境和分散式系統中可能發生
•煙囪系統(Stovepipe system):過度聚集數據和功能,忽視了與其他系統和模組的共享
面向對象設計
•貧血的域模型(Anemic Domain Model):僅因為每個對象都要有屬性和方法,而在使用域模型的時候沒有加入非OOP的業務邏輯
•(BaseBean):繼承一個工具類的功能,而不是委託給它
•調用父類(Call super):需要子類調用父類被重定義的方法
•圓還是橢圓問題(Circle-ellipse problem):基於變數的子類化關係進行子類化
•循環依賴(Circular dependency):在對象或軟體模組中,直接或間接引入循環依賴。
•常量接口(Constant interface):使用接口定義常量
•上帝對象(God object):在設計的單一部分(某個類)集中了過多的功能
•對象糞池(Object cesspool):復用那些不滿足復用條件的對象。對象池是一種管理對象的方法,在重複使用對象前,需要針對對象進行初始化,以避免上次使用後的狀態等數據影響下次的使用
•不羈的對象(Object orgy):沒有成功封裝對象,外部可以不受限制地訪問它的內部
•幽靈(Poltergeists):指這樣一些對象,它們唯一的作用就是把信息傳給其它對象
•順序耦合(Sequential coupling):指這樣一些對象,它們的方法必須要按某種特定順序調用
•悠悠問題(Yo-yo problem):一個結構(例如繼承)因為過度碎片化而變得難於理解
編程
•偶然複雜度(Accidental complexity):向一個方案中引入不必要的複雜度
•遠隔作用(Action at distance):意料之外的在系統分離的部分之間互動
•盲目信任(Blind faith):缺乏對bugfix的校驗或對子函式返回值的正確性檢查
•船錨(Boat anchor):在系統中保留無用的部分
•忙等待(Busy waiting):在等待的時候不斷占用CPU,通常是因為採用了重複檢查而不是適當的訊息機制
•快取失敗(Caching failure):錯誤被修正後忘記把錯誤標誌復位
•拜物編程(Cargo cult programming):由於對模式的盲目崇拜,在不理解的情況下就使用模式和方法,企圖得到好的結果
•靠異常編程(Coding by exception):當有特例被發現時才添加新代碼去解決
•隱藏錯誤(Error hiding):在顯示給用戶之前捕捉到錯誤信息,要么什麼都不顯示,要么顯示無意義的信息
•硬編碼(Hard code):將對系統環境的假設寫入實現中
•熔岩流(Lava flow):保留不想要的(冗餘的或是低質量的)代碼,僅因為除去這些代碼的代價太高或是會帶來不可預期的結果
•循環-switch序列(Loop-switch sequence)在循環結構中使用switch語句來編寫連續步驟
•魔幻數字(Magic numbers):在算法里直接使用數字,而不解釋含義
•魔幻字元串(Magic strings):直接在代碼里使用常量字元串,例如用來比較,或是作為事件代碼
•自我複製(Repeating yourself): 通過不斷複製已有代碼的模式或代碼段進行編碼;而非採用once and only once(抽取原則)
•軟代碼(Soft code):在配置檔案里保存業務邏輯而不是在代碼中
•麵條代碼(Spaghetti code):指那些結構上完全不可理解的系統,尤其是因為誤用代碼結構
•霰彈槍手術(Shotgun surgery):開發人員一次性在一個多個實現的代碼基中增加功能
方法論
•拷貝貼上編程(Copy and paste programming):拷貝(然後修改)現有的代碼而不是構造通用的解決方案
•黃金大錘(Golden hammer):認為自己最喜歡的解決方案是到處通用的(見:銀彈)
•不可能因素(Improbability factor):認為已知的錯誤不可能發生
•不是這裡發明的(Not invented here):拒絕使用組織外的主意或方案
•這裡發明的(invented here):拒絕組織內部實現的創新或解決方案,通常因為對成員沒有信心
•不成熟的最佳化(Premature optimization):在編碼的早期追求代碼的效率,犧牲了好的設計、可維護性、有時甚至是現實世界的效率
•轉換編程法或巧合編程(Programming by permutation or programming by accident):試圖通過連續修改代碼再看是否工作的方式來解決問題
•重新發明方的輪子(Reinventing the square wheel):已經有一個很好的方案了,又再搞一個爛方案來替代它
•銀彈(Silver bullet):認為自己最喜歡的技術方案能解決一個更大的問題
•測試人員驅動開發(Tester driven development):需求來自bug報告的軟體工程
配置管理
•依賴地獄(Dependency hell):依賴的產品的版本導致的問題
•DLL地獄(DLL hell):不同版本帶來的問題,DLL可見性和多版本問題,在微軟的Windows上尤為突出
•擴展衝突(Extension conflict):蘋果系統在Mac OS X版本之前的不同擴展的問題
•JAR地獄(JAR hell):JAR檔案不同版本或路徑帶來的問題,通常是由於不懂類載入模型導致的