閒談軟體設計:Interface-based Typed Configuration

更新 發佈閱讀 10 分鐘
圖片來源:ChatGPT 生成

圖片來源:ChatGPT 生成

在決定使用 Javalin 取代 Spring framework 作為後端的框架後 [1],除了安全控管 [2][3]、日誌 [4] 和交易管理 [5],還有一個被忽略,但其實非常重要的基礎設施:配置 (Configuration)。今天就聊一下在新系統裡怎麼處理配置的問題。

對照組

在看新設計前,先看一下對照組。一般在使用 Spring framework 開發時,可以用 @Value 自動將配置檔的內容直接綁定到物件中。

事實上 @Value 只是 Spring Boot 眾多處理配置的其中一種方式,但這些方式原則上都有幾個特點:

  • 型別安全 — 會自動將字串轉成目標的型別
  • 來源優先序 — 讀取順序從配置檔 → 系統參數 → 環境變數 → 預設值
  • 使用 annotation 注入 — 使用上非常方便,但 framework 在啟動時需要透過 reflection與 metadata 處理 configuration binding

這些特點確實有幫助到開發者,但有個缺點,只能搭配 Spring framework 使用,而這個缺點正是選擇 Javalin 後最大的問題,但好在上述的問題並不是無法解決的。

設計目標

由於 Javalin 的核心思維是簡單與輕量,因此原生沒有提供任何配置的相關框架,此時,就只好先回顧一下 Java 原生常見的幾種處理方式:

  • 啟動參數 — 在啟動應用程式時,帶入參數,但需要寫參數的解析程式,這邊可以用 JCommander 幫忙處理,還算容易
  • 系統參數 — 也是在啟動應用程式時,透過 -Dsecret=value 的方式定義系統參數,然後在程式裡用 System.getProperty("secret") 取得參數
  • 環境變數 — 在程式中用 System.getenv("secret"),使用方式很像系統參數,差別是變數的來源不同
  • 配置檔 — 即便不使用 Spring framework 也是可以自己寫程式讀取配置檔

在雲原生的環境中,直接透過環境變數通常會比啟動參數或系統參數更直觀,剩下就是環境變數與配置檔,最後我選擇的是環境變數,不需要解析 JSON 或 YAML。

但如果單純使用環境變數,會遇到一個問題是 key 是四散在各個角落,難以管理,所以還是需要一個抽象層,而這個抽象層希望達成幾個目標:

  • 集中管理 — 這裡的集中管理是指 key、預設值與使用位置在同一個模組中定義,而不是散落在不同地方。
  • 型別安全
  • 慣例優先 — 如果沒有特殊需求,默認使用慣例,但如果有特殊需求,能夠隨時替換
  • 容易實作 — 雖然 annotation 使用上很方便,但背後的處理很麻煩,因此新的抽象層要在使用和實作上都要很方便
  • 隔離來源 — 雖然已經確定使用環境變數,但不希望使用端直接呼叫 System.getenv()

這裡,來源優先序不在這次的考量內,因為整個系統都會使用環境變數,不需要為不存在的需求讓設計變複雜,只有確保來源是可以被抽換的。

Interface-based Typed Configuration

首先,在這個設計中,configuration schema 直接以 Java interface 的形式表達。因此,設計中有一個非常重要的基礎,雖然只有一個檔案,卻提供了環境變數的讀取、型別轉換與預設值的處理:

接下來,每個需要配置的地方,定義自己的 Configuration,以用 SendGrid 發送郵件為例,可以定義一個介面 SendGridClientConfig 提供呼叫 API 時需要的 API Key:

這個檔案提供了三個功能:

  • 定義慣例 — 環境變數的 key 就是 SENDGRID_API_KEY,如果沒有其他需求,不需要再提供
  • 定義預設值 — 在這裡預設值是 null,因為這資訊是不能明文放在程式碼中的,但如果可以明文儲存,這裡可以放一些預設值,例如 Javalin 啟動時要使用哪個 port。
  • 提供 API Key — 由 getSendGridApiKey 用慣例的 key 呼叫 getConfig 來取得 API Key,如果沒有值則回傳預設值。

而這個檔案的位置和使用的檔案 SendGridClient 是放在一起的,這個類別提供兩個建構子:

  • 預設建構子 — 由於 SendGridClient 黏合 (SendGridClientConfig),在沒有提供 config 的情況下,能用自己作為 config。
  • 能指定 SendGridClientConfig 的建構子 — 有任何不符合慣例或額外設定的情況下,提供符合 SendGridClientConfig 介面的實作。

Java 沒有原生 mixin (黏合) 的語法,Java interface 的 default method 在某種程度上提供了類似 trait 的能力,因此可以被用來黏合。

如此一來,當初希望達成的四個目標都算是達到了:

  • 集中管理 — key 的定義、預設值與使用方都集中在同一個地方,要使用時很容易較能找到 key
  • 型別安全 — 定義 configuration 時,能直接提供正確型別的值
  • 慣例優先 — 如果沒有特殊需求,用預設建構子,然後把 API Key 用預設的 key 設為環境變數就可以使用
  • 容易實作 — 雖然不像 annotation 那樣簡單,但實際上也沒有寫多少程式碼,而且要抽換實作也非常容易
  • 隔離來源 — SendGridClient 不需要知道 API Key 的來源,只依賴 configuration interface

進階議題

雖然來源優先序不再這次的設計目標中,但如果未來要加入相關的支援,有幾種方式可以實現:

  • Template method — 若策略固定,可以在定義 configuration 的地方透過 template methods 決定讀取來源與讀取的順序
  • Responsibility chain —若想要動態來源,可以透過串接數個相同介面的實作,動態地調整讀取的順序
  • Builder — 想要彈性的組合側月,可以用 Builder 決定一個慣例的優先順序,在建立時可以替換掉順序中的某幾個步驟,例如忽略某個來源或是替換不同的實作

總而言之,目前的設計是非常輕量,易於使用,而且保留了未來的擴充性。

比較

最後簡單和對照組的 Spring framework 做一個比較。如圖所示,這個設計只依賴一個簡單的 Config 介面,如果需要在其他專案中使用,基本上只需要複製這個介面即可,不依賴任何特定框架。

雖然沒有方便的 annotation 注入,但也避免了使用 reflection 進 binding。所有 configuration 都是透過明確的方法呼叫取得,讓整個流程更直接,也減少了啟動時需要進行的額外處理。在雲環境中,應用程式通常會頻繁地啟動與部署,減少啟動時的負擔往往是有意義的。

在功能上,這個設計仍然保留了幾個重要特性,例如型別安全,以及未來擴充來源優先序的可能性。雖然不像 Spring framework 那樣完整,但在保持輕量的同時,也提供了一個簡單且實用的替代方案。

Spring framework Configuration vs Interface-based Typed Configuration

Spring framework Configuration vs Interface-based Typed Configuration

小結

當從 Spring framework 轉向 Javalin,原本依賴 annotation 注入配置的方式無法使用,因此需要一個和 Javalin 搭配的替代方案,透過 interface-based typed configuration,在保持輕量的前提下,達成了集中管理、型別安全、慣例優先、容易實作與隔離來源等目標,是一個務實且簡單的解決方案。

延伸主題

  1. 閒談軟體設計:Web 框架的選擇
  2. 閒談軟體設計:安全聲明
  3. 閒談軟體設計:身家調查
  4. 閒談軟體設計:日誌框架
  5. 閒談軟體設計:交易管理


留言
avatar-img
Spirit 異想世界
58會員
122內容數
這是從 Medium 開始的一個專題,主要是想用輕鬆閒談的方式,分享這幾年軟體開發的心得,原本比較侷限於軟體架構,但這幾年的文章不僅限於架構,也聊不少流程相關的心得,所以趁換平台,順勢換成閒談軟體設計。
Spirit 異想世界的其他內容
2026/03/08
開發系統過程中常遇到 race condition 問題,文章探討了樂觀鎖、Serializable Isolation Level 交易的限制,並提出 PostgreSQL Advisory Lock 作為一種方便且無需額外部署基礎設施的分散式鎖解決方案,以確保批次寫入與背景運算能按順序執行。
Thumbnail
2026/03/08
開發系統過程中常遇到 race condition 問題,文章探討了樂觀鎖、Serializable Isolation Level 交易的限制,並提出 PostgreSQL Advisory Lock 作為一種方便且無需額外部署基礎設施的分散式鎖解決方案,以確保批次寫入與背景運算能按順序執行。
Thumbnail
2026/03/01
本文探討在軟體開發過程中,將原本並非 Aggregate 的設計,逐步重構成具有 Aggregate 精神的實作。作者分享了一個實際案例,說明如何在一致性問題和更複雜的協同作業需求出現時,透過引入樂觀鎖,並逐步思考 Aggregate 的設計原則,最終找到一個在滿足系統需求下的特殊解決方案。
Thumbnail
2026/03/01
本文探討在軟體開發過程中,將原本並非 Aggregate 的設計,逐步重構成具有 Aggregate 精神的實作。作者分享了一個實際案例,說明如何在一致性問題和更複雜的協同作業需求出現時,透過引入樂觀鎖,並逐步思考 Aggregate 的設計原則,最終找到一個在滿足系統需求下的特殊解決方案。
Thumbnail
2026/02/21
作者分享了 B2B 產品在迭代開發過程中所遇到的挑戰,特別是在追求功能完整性的過程中,如何避免設計變得過於複雜,進而影響使用者體驗。文中探討了從使用者回饋、市場變化到團隊內部認知的變化,並提出了在產品開發中「踩煞車」的重要性,以確保產品能真正符合使用者需求,而非徒增複雜度。
Thumbnail
2026/02/21
作者分享了 B2B 產品在迭代開發過程中所遇到的挑戰,特別是在追求功能完整性的過程中,如何避免設計變得過於複雜,進而影響使用者體驗。文中探討了從使用者回饋、市場變化到團隊內部認知的變化,並提出了在產品開發中「踩煞車」的重要性,以確保產品能真正符合使用者需求,而非徒增複雜度。
Thumbnail
看更多
你可能也想看
Thumbnail
封裝、繼承、多型是物件導向的三大核心特徵,判斷一種程式語言是否為物件導向的程式語言,就看其是否支援這三大核心特徵。 軟體類別是對現實類別的模擬,但不是簡單的等同。除了實作現實類別相對應的功能,還會創造出許多現實中不存在的類別。 這個創造過程正是各種設計方法、設計模式、設計原則大顯身手的地方。
Thumbnail
封裝、繼承、多型是物件導向的三大核心特徵,判斷一種程式語言是否為物件導向的程式語言,就看其是否支援這三大核心特徵。 軟體類別是對現實類別的模擬,但不是簡單的等同。除了實作現實類別相對應的功能,還會創造出許多現實中不存在的類別。 這個創造過程正是各種設計方法、設計模式、設計原則大顯身手的地方。
Thumbnail
常見的 C 語言是屬於程序導向中結構化程式設計的概念,採取『自上而下、逐步細化、模組化』的方法,從而降低軟體發展的複雜度,因此 C 語言成為 20 世紀 70 年代軟體發展的潮流。因為結構化程式設計的方式無法滿足軟體『可擴充性』和『可維護性』的需求,因此物件導向的概念才開始普及。
Thumbnail
常見的 C 語言是屬於程序導向中結構化程式設計的概念,採取『自上而下、逐步細化、模組化』的方法,從而降低軟體發展的複雜度,因此 C 語言成為 20 世紀 70 年代軟體發展的潮流。因為結構化程式設計的方式無法滿足軟體『可擴充性』和『可維護性』的需求,因此物件導向的概念才開始普及。
Thumbnail
在實務上,為了求快,工程師們常知其然不知所以然,反正呼叫 API 能動或能給出想要的結果就好。但這樣的想法到底是讓軟體設計變的更輕鬆,還是入門容易熟練難呢? 當你邊上理論課程,然後自己又有能力設計出基於理論的實用軟體工具,並分享給其他人使用時,豈不是更滿足也更有成就感!
Thumbnail
在實務上,為了求快,工程師們常知其然不知所以然,反正呼叫 API 能動或能給出想要的結果就好。但這樣的想法到底是讓軟體設計變的更輕鬆,還是入門容易熟練難呢? 當你邊上理論課程,然後自己又有能力設計出基於理論的實用軟體工具,並分享給其他人使用時,豈不是更滿足也更有成就感!
Thumbnail
代理模式通過封裝原始對象來實現對該對象的控制和管理,同時不改變原始對象的行為或客戶端與該對象互動的方式,以此介入或增強對該對象的訪問和操作。
Thumbnail
代理模式通過封裝原始對象來實現對該對象的控制和管理,同時不改變原始對象的行為或客戶端與該對象互動的方式,以此介入或增強對該對象的訪問和操作。
Thumbnail
觀察者模式透過主題訂閱/訊息通知的機制,極度增強系統的可擴展性、靈活性以及降低組件間的耦合度。概念直觀簡單,是非常實用的設計模式。
Thumbnail
觀察者模式透過主題訂閱/訊息通知的機制,極度增強系統的可擴展性、靈活性以及降低組件間的耦合度。概念直觀簡單,是非常實用的設計模式。
Thumbnail
5 月將於臺北表演藝術中心映演的「2026 北藝嚴選」《海妲・蓋柏樂》,由臺灣劇團「晃晃跨幅町」製作,本文將以從舞台符號、聲音與表演調度切入,討論海妲・蓋柏樂在父權社會結構下的困境,並結合榮格心理學與馮.法蘭茲對「阿尼姆斯」與「永恆少年」原型的分析,理解女人何以走向精神性的操控、毀滅與死亡。
Thumbnail
5 月將於臺北表演藝術中心映演的「2026 北藝嚴選」《海妲・蓋柏樂》,由臺灣劇團「晃晃跨幅町」製作,本文將以從舞台符號、聲音與表演調度切入,討論海妲・蓋柏樂在父權社會結構下的困境,並結合榮格心理學與馮.法蘭茲對「阿尼姆斯」與「永恆少年」原型的分析,理解女人何以走向精神性的操控、毀滅與死亡。
Thumbnail
背景:從冷門配角到市場主線,算力與電力被重新定價   小P從2008進入股市,每一個時期的投資亮點都不同,記得2009蘋果手機剛上市,當時蘋果只要在媒體上提到哪一間供應鏈,隔天股價就有驚人的表現,當時光學鏡頭非常熱門,因為手機第一次搭上鏡頭可以拍照,也造就傳統相機廠的殞落,如今手機已經全面普及,題
Thumbnail
背景:從冷門配角到市場主線,算力與電力被重新定價   小P從2008進入股市,每一個時期的投資亮點都不同,記得2009蘋果手機剛上市,當時蘋果只要在媒體上提到哪一間供應鏈,隔天股價就有驚人的表現,當時光學鏡頭非常熱門,因為手機第一次搭上鏡頭可以拍照,也造就傳統相機廠的殞落,如今手機已經全面普及,題
Thumbnail
樣板模式的定義極為簡單,卻是大型系統程式、WEB/APP應用框架的設計核心,完美展現設計模式的價值: 簡單、高效、強大。
Thumbnail
樣板模式的定義極為簡單,卻是大型系統程式、WEB/APP應用框架的設計核心,完美展現設計模式的價值: 簡單、高效、強大。
Thumbnail
希望透過實戰系列來撰寫技術學習文章,然後一邊打造免費版的機器視覺軟體,再把這個過程記錄下來。開發軟體的人最希望的就是,自己創造的東西越多人用越好,因為那是最自由也最有成就感的時刻。 
Thumbnail
希望透過實戰系列來撰寫技術學習文章,然後一邊打造免費版的機器視覺軟體,再把這個過程記錄下來。開發軟體的人最希望的就是,自己創造的東西越多人用越好,因為那是最自由也最有成就感的時刻。 
Thumbnail
策略模式將多種演算法封裝於獨立的策略類別中,每個策略類別都實現了一個共同的介面。這種設計允許使用者在系統運行時動態選擇和切換演算法,以達成相同的目的。
Thumbnail
策略模式將多種演算法封裝於獨立的策略類別中,每個策略類別都實現了一個共同的介面。這種設計允許使用者在系統運行時動態選擇和切換演算法,以達成相同的目的。
Thumbnail
本文分析導演巴里・柯斯基(Barrie Kosky)如何運用極簡的舞臺配置,將布萊希特(Bertolt Brecht)的「疏離效果」轉化為視覺奇觀與黑色幽默,探討《三便士歌劇》在當代劇場中的新詮釋,並藉由舞臺、燈光、服裝、音樂等多方面,分析該作如何在保留批判核心的同時,觸及觀眾的觀看位置與人性幽微。
Thumbnail
本文分析導演巴里・柯斯基(Barrie Kosky)如何運用極簡的舞臺配置,將布萊希特(Bertolt Brecht)的「疏離效果」轉化為視覺奇觀與黑色幽默,探討《三便士歌劇》在當代劇場中的新詮釋,並藉由舞臺、燈光、服裝、音樂等多方面,分析該作如何在保留批判核心的同時,觸及觀眾的觀看位置與人性幽微。
Thumbnail
這是一場修復文化與重建精神的儀式,觀眾不需要完全看懂《遊林驚夢:巧遇Hagay》,但你能感受心與土地團聚的渴望,也不急著在此處釐清或定義什麼,但你的在場感受,就是一條線索,關於如何找著自己的路徑、自己的聲音。
Thumbnail
這是一場修復文化與重建精神的儀式,觀眾不需要完全看懂《遊林驚夢:巧遇Hagay》,但你能感受心與土地團聚的渴望,也不急著在此處釐清或定義什麼,但你的在場感受,就是一條線索,關於如何找著自己的路徑、自己的聲音。
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News