譯者 | 劉汪洋
審校 | 重樓?
在審查某個軟件解決方案時,你是否感到其復雜性超出了實際需求?在對該架構或方法進行批評之前,請仔細考慮其可能的深遠影響。

“過度架構”常常被用來形容某些軟件解決方案的設計、抽象、實現或部署存在不必要的復雜性。這種批評通常暗示著這些方面難以理解、不易維護,甚至可能是錯誤的。然而,這類指責往往缺乏上下文或具體的支持性論述,但卻容易被人們輕信和接受。
那么,為一個解決方案貼上“過度架構”的標簽究竟意味著什么?
通常情況下,這種標簽被視為軟件工程師規避責任的一種“萬能借口”,用來解釋因工作量超出預期或項目時間線延誤而產生的問題。更令人遺憾的是,管理層往往會毫不懷疑地接受這一解釋,特別是在做出相關決策的工程師缺席時,這種解釋更容易顯得有說服力。
確實,最初實施的架構可能與當前的技術棧、業務假設或抽象存在分歧,但你是否有足夠的依據來明確判斷它是“過度架構”?公司自實施以來是否經歷了業務目標或技術方向的變化?當初在設計時是否考慮了某些非功能性需求?是否有任何提交信息能夠提供進一步的背景支持?
最關鍵的問題是,你的擔憂真的能準確定義“過度架構”,還是其實并沒有那么嚴重?或許我們都不能輕易下結論。
軟件工程師負責開發軟件
借用哈姆雷特的經典獨白:
維護,還是不維護,這是個問題:是心甘情愿地忍受荒唐實現帶來的打擊, 還是拿起武器對抗無盡的麻煩并從頭開始,用一張白紙重新設計。
雖然哈姆雷特的獨白原意在探討生死問題,這一段改編則成為了對軟件開發過程的隱喻。軟件工程師往往更傾向于編寫新代碼,而不愿意長期維護他人編寫的代碼。
當工程師被分配到維護任務時,無論是何種形式,他們通常會尋找各種方式來重新設計、重構甚至重寫代碼,以使工作更加有趣。如果代碼的變更頻率過高、圈復雜度過大,或者代碼已經難以維護,那么這種決策無疑是有其合理性的。盡管這可能會令產品負責人和Scrum Master感到不快,但有時,歷史遺留問題已無法忽視。
然而,公開稱現有代碼為“過度架構”可能為你贏得重新設計的機會,但也可能引發更深入的質疑,尤其是在以下幾種情況下:
- 工程師不愿深入理解當前的實現
- 工程師不充分了解業務需求或技術需求
- 工程師對現有的設計模式或代碼結構持不同意見
- 工程師不喜歡現有代碼的風格、格式,甚至編程語言?
諷刺的是,重寫項目的規模往往會超出預期,因為工程師最終不得不理解現有的解決方案才能重新實現它。盡管聲稱自己不是在“重復造輪子”,但在沒有全面理解的情況下,工程師往往還是得走這條路。你的組織是否真的準備好迎接API優先、微服務、NoSQL等新技術的挑戰?
隨著時間線的延長,領導層的挫敗感增加,其他重要工作被推遲或擱置,而這一切的起因往往是工程師堅稱這些改變是必要的。這樣的情景屢見不鮮,許多人甚至曾是始作俑者,但通常這些故事的結局并不理想。
最終的問題仍然存在:它真的過度架構了嗎?
問題架構
在軟件工程領域,架構類型繁多,如企業架構、系統架構、應用架構、軟件架構、云架構和集成架構等。更為復雜的是,不同的組織根據其內部需求對這些架構學科進行了獨特的定義,使得明確劃分每種架構的職責和界限變得困難。由于不同的軟件架構在不同的組織和上下文中可能有不同的定義和職責。因此,直接將它們進行比較是不合理的,因為它們之間的差異太大,就像不能簡單地將它們進行直接比較。
盡管如此,我們依然可以嘗試定義“問題”架構。我認為有三種基本類型的架構可能會存在問題。
1. 不同架構
“不同架構”指的是在解決方案中對于如何處理非功能性需求存在分歧的情況。比如,針對一個面向云的解決方案,究竟應該采用云原生還是云無關的架構?穩定性和可靠性是否比吞吐量和性能更重要?資源選擇的標準是成本、能力,還是兩者兼顧?對于基礎架構的任何擔憂或抱怨,都必須與成功解決方案所需的重要非功能性需求相平衡。你可能不同意這些需求的優先級,但只要這些需求得到了滿足,解決方案便是有效的,無論個人的偏好如何。 即使你認同非功能性需求,不同的工程師也可能會提出不同的解決方案:同步與異步、面向對象的繼承與組合、功能或 CRUD 的 API 端點、SQL 與 NoSQL、API 優先與 MVC。
這些選擇本質上都是主觀的,解決方案并無絕對的對錯,關鍵在于滿足需求。 “Hello, World”程序可以通過成千上萬種方式實現,每種方式都有其合理性。因此,不同的工程師會以不同的方式解決同一個問題。這種差異并非錯誤,更不一定是“過度架構”。如果非功能性需求明確并且得到了實現,即使你不同意某些設計和實現,這仍可能是一個成功的架構。
2. 錯誤架構
識別“錯誤架構”通常需要深入分析從概念到部署的整個過程,以找出其中的缺陷。這類架構常表現為需求定義不清、代碼質量差、項目執行不力、時間表不現實,以及架構不合理。這些問題往往相互交織,難以單獨解決。具體而言,錯誤架構的特點通常包括:
- 未能滿足非功能性需求,甚至根本沒有明確需求。
- 實現所需的技術技能和背景在組織內部不存在。
- 架構需要構建組織核心能力之外的組件,特別是當已有組件能夠滿足需求時。
- 部署的解決方案不穩定,需要定期維護以避免中斷。
- 維護和擴展嚴重依賴于某些不可替代的個人。?
如果你曾參與過失敗的項目,可能會對這些特征感同身受。有時,你可能會發現,所謂的“錯誤架構”實際上根本沒有經過嚴謹的架構設計。更重要的是,這類項目及其最終解決方案通常難以挽救,與其相關的一切努力往往都是時間的浪費。
3. 過度架構
是否存在真正的“過度架構”情況?答案是肯定的。某些設計方案可能過于復雜,超出了實際需求。例如,一個開關的設計可能顯得過于繁瑣,大多數人會認為這是不必要的復雜化,但魯布·戈德伯格和創客們可能持有不同的看法。以下經歷可能是“過度架構”的典型案例;當然,也可能是錯誤架構,或者只是一種完全不同的架構。
問題陳述
在我擔任獨立軟件顧問期間,曾被聘請為一位剛離職員工的替補。這位前員工設計并(大部分)實現了一個自定義框架,用以支持公司第一個真正的Web應用程序。然而,留給團隊的只有少量示例實現和幾乎沒有文檔(設計文檔、使用說明等),剩下的工程師們只能試圖拼湊這些碎片。為了更好地理解那段時期的背景,早期的Web開發沒有真正的標準或最佳實踐,開源軟件還處于萌芽階段。用戶電腦的性能非常有限,難以運行復雜的瀏覽器端腳本。瀏覽器供應商對HTML標準的解釋也各不相同,這是Internet Explorer主導市場的時期,與現在大不相同。我的任務是掌握這個框架,理解其內部運作,并為后續的應用程序開發制定路線圖。
理解與內化
從宏觀層面看,這一任務似乎相對簡單:通過Java Servlet應用程序(框架)生成HTML,處理請求、響應和導航。然而,隨著深入了解,問題逐漸浮現。頁面之間緊密耦合,任何微小的改動都會影響到相鄰頁面。頁面直接生成HTML,這使得在整個應用程序中保持一致性極為困難。要改變框架的默認行為,需要找到對應的鉤子,而這些鉤子往往數量眾多且混亂不堪。盡管最初的Servlet引擎工作正常,但一旦考慮更換(如使用Tomcat以提高性能),問題就會接踵而至。這些復雜問題使得項目面臨巨大挑戰,成功的希望渺茫,因此必須做出艱難的決定。
決策時刻
我的結論是:現有框架勉強能夠滿足當前需求,但不適合未來開發。繼續使用這個框架將使剩余的工程師不堪重負,項目可能永遠無法完成。經理展現出深刻的洞察力,同意及時止損。最終,我們設計了一個更簡單、更聚焦的框架,三周內工程師們就能夠在工作模型上開始應用開發,并在兩個月后成功演示了成果。最終,該框架非常成功,被用于多個應用程序,直到退役。
最終結論
將原始框架視為“過度架構”的原因包括:
- 非功能性需求的缺失:缺乏對設計和實現的必要約束。
- 自負驅動的設計:為了展示個人才華,過度追求復雜性。
- 過于復雜:難以實施、維護和支持。
- 無競爭優勢:架構的復雜性并未帶來競爭優勢,反而大大延長了項目的上市時間。?
雖然這種情況也可以被稱為錯誤架構或不同的架構,但這只是語義上的差別。無論如何,我們在改變方向前進行了充分的盡職調查,通過客觀的分析,而非簡單地將其貼上“過度架構”的標簽,最終做出了正確的決策。
最后的思考
軟件解決方案的架構形式多種多樣,受到諸多外部因素的影響,如業務需求、開發需求、技術團隊的經驗與技能、可用技術以及組織的成熟度等。這種多樣性是正常且必要的。然而,許多時候,一個架構方案會在缺乏對其背景和動機的深入理解的情況下被輕易否定。盡管在某些情況下,重新實現部分或全部解決方案確實有其正當理由,但有時這種動機可能源于工程師的個人偏好或私心。
作為負責任的軟件工程師,我們應該為那些對組織最有利的方案進行辯護,而不僅僅是為技術或個人興趣服務。這并不是說技術需求不重要,而是我們應該能夠為所提出的技術方案提供充分的理由和論據。 這一過程要求我們進行深入的調查,詳細記錄,清晰敘述,并合理辯護。簡單地將某個方案貼上“過度架構”的標簽遠遠不夠。我們必須超越簡單的批評,提出經過深思熟慮和充分驗證的判斷,確保每個決定都是在組織的整體利益下做出的。
譯者介紹
劉汪洋,51CTO社區編輯,昵稱:明明如月,一個擁有 5 年開發經驗的某大廠高級 Java 工程師,擁有多個主流技術博客平臺博客專家稱號,博客閱讀量 400W+,粉絲 3W+。2022 年騰訊云優秀創作者,2022 年阿里云技術社區最受歡迎技術電子書 TOP 10 《性能優化方法論》作者,慕課網:剖析《阿里巴巴 Java 開發手冊》、深度解讀《Effective Java》 技術專欄作者。
原文標題:Over-Architected? Maybe, Maybe Not,作者:Scott Sosna























