iT邦幫忙

2025 iThome 鐵人賽

DAY 23
0
Software Development

Go Clean Architecture API 開發全攻略系列 第 23

[Day 23] 為何 `internal` 目錄對你的 Go 專案至關重要

  • 分享至 

  • xImage
  •  

在我們整個專案的目錄結構中,internal 目錄佔據了核心地位,我們幾乎所有的業務程式碼都存放在其中。你可能會想,這僅僅是一個命名約定嗎?我能把它命名為 privatecore 嗎?

答案是:不行。internal 在 Go 語言中是一個具有特殊意義的「魔術」目錄,它的行為是由 Go 編譯器直接強制執行的。這不僅僅是團隊內部的共識或慣例,而是 Go 官方語言規範的一部分。只要你的程式碼被放在 internal 目錄下,Go 工具鏈就會自動限制其可見性,這種強制性的封裝機制遠比單純的命名規範來得可靠。

internal 目錄的唯一規則

internal 目錄的規則非常簡單,但卻異常強大:

一個位於 internal 目錄下的套件,只能被其直屬父目錄及其後代目錄中的程式碼所匯入(import)。

這條規則的強大之處在於,它直接由編譯器層面保護你的專案架構,防止外部專案或模組誤用、濫用你的內部實作。這種保護是自動且無法被繞過的,讓你可以放心地在 internal 目錄下實作所有敏感、關鍵的業務邏輯,而不必擔心被外部依賴。

讓我們以我們的專案為例來解釋:

  • 我們的專案模組路徑是 go-clean-project
  • 我們的 internal 目錄位於專案的根目錄下。

這意味著,只有在 go-clean-project 這個模組內部,才能匯入像 go-clean-project/internal/domaingo-clean-project/internal/usecase/api/user 這樣的套件。這種設計讓我們能夠明確劃分哪些程式碼是「內部」的,哪些是「外部」可見的,從而大幅降低了專案被誤用或產生不必要耦合的風險。

如果另一個完全無關的專案 my-other-app 試圖在他的程式碼中寫下 import "go-clean-project/internal/domain",Go 編譯器會立刻報錯,並拒絕編譯,錯誤訊息通常是:use of internal package ... not allowed

這不是一個建議,而是一條由 Go 工具鏈強制執行的硬性規定。這種強制性保護讓你的專案架構更加健壯,減少了因為外部依賴導致的維護困難與技術債。

internal vs. pkg:一個清晰的選擇題

Go 開發者常常對何時該用 internal、何時該用 pkg 感到困惑。internal 的特殊規則為我們提供了一個清晰的判斷標準:

  • internal:用於存放僅供本應用程式內部使用的程式碼。這是我們應用程式的主體,包含了所有不希望被外部專案依賴的業務邏輯、控制器、資料庫實作等。在我們的專案中,幾乎 99% 的程式碼都理應放在這裡。這樣做的好處是,當你需要重構、調整內部邏輯時,不必擔心會影響到外部使用者,讓你可以更靈活地演進專案架構。

  • pkg:用於存放那些可以被外部專案安全地匯入和使用的公共程式碼包。如果我們開發了一個通用的、與具體業務無關的函式庫(例如,一個處理貨幣計算的 money 套件,或一個處理 UUID 的 uuid 套件),並且我們希望其他專案也能使用它,那麼就應該將其放在 pkg 目錄下。這些套件的 API 設計必須更加謹慎,因為一旦被外部依賴,未來的修改就會受到更多限制。

經驗法則:當你不確定時,永遠優先選擇 internal。只有當你明確地需要將某個套件作為一個獨立的函式庫供其他專案使用時,才考慮將其放入 pkg。這樣可以最大程度地保護你的專案不被外部依賴鎖死,也讓你的內部邏輯能夠自由演進。

internal 對我們架構的意義

現在回頭看我們的六角形架構,internal 目錄的重要性就顯而易見了。它正是我們用來強制執行架構邊界的完美工具。

因為我們所有的核心邏輯(domain, usecase, repository)都位於 internal 目錄下,所以我們可以從編譯器層面,保證外部世界絕對無法繞過我們的 API 層(controller),去直接依賴或呼叫我們的內部實作。這種結構讓我們能夠嚴格遵守「依賴倒置原則」,確保外部只透過明確定義的介面與我們的應用程式互動,從而維持架構的純粹性與可維護性。

internal 目錄像一位忠誠的守衛,保護著我們應用程式核心領域的純粹性和完整性,防止了意外的、混亂的依賴關係的產生。這種保護不僅提升了專案的安全性,也讓團隊成員在協作時有明確的邊界意識,減少了溝通成本與潛在的技術債。

總結

internal 目錄是 Go 語言設計哲學中「約定優於配置」思想的體現。它不是一個可有可無的檔案夾,而是 Go 語言提供給開發者的一個強大的封裝和架構保護工具。透過 internal,你可以用最簡單的方式,獲得最強大的架構邊界保護,這是許多其他語言需要額外工具或複雜設計才能達到的效果。

正確地理解和使用 internal 目錄,能幫助我們建立起更加健壯、可維護、邊界清晰的應用程式,是每一位專業 Go 開發者都應掌握的知識。

在下一篇文章中,我們將比較我們所採用的六角形架構與更廣為人知的 MVC 架構,來探討不同設計模式之間的權衡與思考。


上一篇
[Day 22] Go 單元測試:如何 Mock 資料庫與外部依賴
系列文
Go Clean Architecture API 開發全攻略23
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言