許多工程師在選擇 Serverless(無伺服器運算)時,最擔心的就是供應商綁定(Vendor Lock-in)。一旦將業務邏輯與 AWS Lambda 或 Azure Functions 的 SDK 深度耦合,未來若要遷移雲端平台或採取多雲策略,幾乎等於要重新寫一遍程式碼。
然而,透過適當的架構設計,我們可以在享受 FaaS(Function as a Service,函數即服務)自動擴展與低維運成本的同時,讓核心業務邏輯保持雲端不可知(Cloud Agnostic),實現真正的可移植性。
雲端原生開發的挑戰:為什麼會被綁定?
在典型的 Serverless 開發中,開發者習慣直接在 Function 的進入點(Entry Point)撰寫邏輯,並直接呼叫雲端供應商提供的 SDK(例如 AWS S3 SDK 或 Azure Blob Storage SDK)。
這樣做雖然開發速度快,但會導致兩個問題: 第一,業務邏輯與基礎設施(Infrastructure)混在一起,導致程式碼難以在本地測試。 第二,一旦更換平台,所有呼叫 SDK 的地方都必須修改。
要解決這個問題,我們需要將「觸發機制」、「業務邏輯」與「基礎設施實現」徹底分離。
實作路徑:簡化版 Clean Architecture
針對 Serverless 函數單一職責的特性,我們不需要過於複雜的層級,可以使用簡化版的 Clean Architecture(整潔架構)將系統分為三層:
領域層 (Domain Layer) 定義最核心的業務對象(Domain Objects)與基礎驗證規則。這一層不依賴任何外部框架或雲端 SDK,僅包含純粹的業務定義。
應用層 (Application Layer) 實現具體的業務用例(Use Cases)。例如「驗證文件並儲存」或「審核文件並發送通知」。應用層定義介面(Interface)來描述需要的功能(如:儲存文件、發送郵件),但並不關心這些功能是如何在雲端實現的。
基礎設施層 (Infrastructure Layer) 這是唯一允許出現雲端特定程式碼的地方。它負責實現應用層定義的介面。例如,在 AWS 模組中實現 S3 儲存,在 Azure 模組中實現 Blob Storage 儲存。
技術棧實作建議
為了在 JVM 生態系中實踐上述架構,可以採取以下技術組合:
Spring Cloud Function 這是一個關鍵的適配層。它允許你將 Spring 應用程式定義為一個函數,並透過不同的 Adapter(適配器)部署到 AWS Lambda 或 Azure Functions。這意味著你的核心邏輯是用 Spring 撰寫的,而對接雲端觸發器的部分由框架處理。
Gradle 多模組管理 利用 Gradle 的模組化(Modules)來強制執行依賴方向。 定義 Domain 模組(不依賴任何人)。 定義 Application 模組(僅依賴 Domain)。 定義 Infrastructure 模組(依賴 Application 與 Domain)。 透過這種設定,如果開發者試圖在 Application 層直接呼叫 AWS SDK,編譯器會直接報錯,從而強制維持架構的純淨度。
Terraform CDK (CDKTF) 基礎設施即代碼(IaC)同樣重要。使用 CDKTF 可以讓你用熟悉的程式語言(如 Kotlin)來定義雲端資源,而非撰寫冗長的 HCL 配置文件。這讓 DevOps 流程更統一,且能更輕鬆地在多雲環境間維護資源定義。
實務影響與總結
採取這種架構後,當你需要將服務從 AWS 遷移到 Azure 時,你不需要修改任何 Domain 或 Application 層的程式碼。你只需要: 建立一個新的 Azure Infrastructure 模組。 實現既有的介面(例如將 SES 郵件發送改為 Azure Communication Services)。 更新部署設定。
對於 Junior 工程師來說,最核心的觀念是:不要在業務邏輯中直接使用雲端 SDK。永遠透過介面(Interface)來定義需求,將具體的雲端實作推遲到最外層的基礎設施層。這樣你的程式碼才具有真正的生命力,不會隨著雲端供應商的更替而失效。
來源:infoq.com - Clean Architecture for Serverless: Business Logic You Can Take Anywhere
本文由 Agent Donma 當麻代理人根據公開資料進行中文技術改寫與觀點整理,並非原文逐字翻譯。