N’‘’# 文章分析:《IaC Module Anti-Patterns: Don’t Create Resource Wrapper Modules》
這篇文章的核心論點是,在基礎設施即程式碼 (IaC) 的實踐中,為單一資源建立「包裝模組 (wrapper modules)」通常是一種反模式 (anti-pattern),因為它在沒有提供實質價值的情況下,不必要地增加了程式碼的複雜性。
各段落重點與總結
段落一:前言
- 重點整理:作者在將一個 OpenAI 的 Azure Bicep 範例轉換為 Terraform 的過程中,發現了一個常見的 IaC 反模式:為單一資源建立包裝模組,而這些模組實際上並未抽象化或簡化任何事情。這個模式不必要地增加了程式碼的複雜性,讓理解部署變得更加困難,卻沒有帶來有意義的回報。這個問題在檢視 Azure OpenAI Demo 專案中的一個 Bicep 模組時尤其明顯。
- 段落總結:本段點出了一個核心問題,即為單一資源建立「包裝模組」是一種反模式。作者認為這種做法徒增複雜性,卻無實質效益,並以一個 Azure Bicep 範例作為切入點。
段落二:問題點:一個幾乎不增加價值的包裝模組
- 重點整理:在 OpenAI 的範例應用程式中,有一個定義在
core/security/role.bicep的 Bicep 模組,在整個程式碼庫中被實例化了 21 次。深入模組內部,會發現它只是定義了一個角色指派 (role assignment)。這個模組增加的功能如下:- 對
principalType參數進行驗證。 - 使用當前的 Azure 上下文為角色定義產生一個隨機名稱。
- 透過在
resourceId函數中硬式編碼前綴來建構roleDefinitionId。 作者認為,這些功能都是極低價值的程式碼,不足以支持將其封裝到一個獨立的模組中。
- 對
- 段落總結:本段透過一個具體的
role.bicep範例,展示了「包裝模組」的問題。該模組雖然被多次呼叫,但其內部邏輯價值極低,與直接在原地撰寫資源定義相比,並沒有顯著優勢。
段落三:錯誤的抽象及其隱藏成本
- 重點整理:建立模組的理由通常是為了簡化、抽象複雜性、減少重複或強制一致性。但在這個案例中,這些目標都沒有真正實現。相反地,這個包裝模組引入了不必要的間接性 (indirection),增加了開發者的認知負擔。作者認為,直接內聯的版本能完成與模組完全相同的事情,程式碼更加透明、易於閱讀。
- 段落總結:本段深入探討了錯誤抽象的代價。作者指出,這種包裝模組並未真正簡化或抽象,反而引入了「間接性」,增加了開發者的認知負擔。
段落四:Terraform vs. Bicep:上下文很重要
- 重點整理:有人可能會說,與 Terraform 相比,Bicep 缺乏內建的提供者級別 (provider-level) 的抽象,這鼓勵了這種模式的出現。即便如此,這也無法成為將瑣碎邏輯包裝在一個獨立模組中的理由。在 Bicep 中,你並沒有節省程式碼行數——只是把它們移到別處,增加了程式碼庫的表面積。
- 段落總結:本段從工具生態的角度分析了問題的成因。Bicep 因缺乏像 Terraform provider 那樣的內建抽象能力,使得開發者傾向於使用模組來避免重複。但作者強調,這種做法依然不可取。
段落五:何時使用模組是值得的?
- 重點整理:在以下情況下,模組才有意義:
- 將多個資源封裝成一個有內聚力的單元。
- 代表可重用的基礎設施模式。
- 接受靈活的參數並輸出複雜的值。
- 在不同的專案或環境中被引用。
作者認為,
role.bicep模組的例子不符合以上任何一項標準。
- 段落總結:本段明確定義了建立模組的合理時機。一個好的模組應該是多個資源的組合、代表可重用的模式、處理複雜的輸入輸出,或跨專案共享。
整篇文章重點結論
這篇文章的核心論點是,工程師應避免為單一資源建立「包裝模組」的 IaC 反模式。這種做法看似在進行抽象和封裝,但如果模組本身並不比直接呼叫資源的程式碼更簡單,或者沒有組合多個資源來形成一個有意義的單元,那麼它就只是一種增加了認知負擔和維護成本的「間接層」。
最終建議:保持你的 IaC 程式碼扁平、透明,並盡可能地簡單。一個好的經驗法則是:如果你需要進入模組才能理解它在做什麼,而它做的正是你所預期的那件事,那麼你一開始可能就不需要這個模組。 ‘’’