← 所有文章

工程 · 2026.10.03 · 3 min · 更新於 2026.10.26

抓 Rust 與 TypeScript 的循環依賴:自己寫模組依賴掃描器,分層規則放進 CI

後端 18 個 package 之間有好幾組循環依賴,只靠人記。我寫了一支不用編譯的掃描器,產出能點進程式碼的架構圖、把分層規則放進 CI,同一天清掉 23 條既有違規,只有 2 條需要注入。

閱讀設定
主題
字級
寬度

Rust 後端 18 個 package 之間有好幾組循環依賴,例如 lending 和 subscription 互相引用,repo 裡卻沒有任何依賴規則,全靠人記。

最後的做法是自己寫一支不編譯、直接讀原始碼的掃描器,Rust 後端和 TypeScript 前端共用,規則放進 CI。

分層照現況排之後,只有 23 條違規,同一天全部清掉。真的需要注入的只有 2 條。

起點是我想要一張架構圖:從分層總覽一路點進子模組、再點進程式碼,而且清楚定義哪些模組可以互相依賴。

現成工具接不起來

cargo-modules、dependency-cruiser、ESLint 的 boundaries 規則都看過。

它們各管一邊,規則格式跟圖接不起來,後端的工具還要先編譯。

所以我寫了一支只用 Node 內建模組的工具。Rust 認 crate::、super:: 這類路徑和透過 State 的存取,TypeScript 認 import、export … from 和 import()。

整個檢查約半秒。

圖是單一 HTML,內嵌原始碼約 9 MB,不進版控。它是原始碼的衍生物,commit 進去的話,每個 PR 都會多一份 9 MB 的 diff。

規則:只能往下依賴

單位由上到下排成幾列,只能依賴排在自己下面那些列的單位。同一列互不依賴,往上也不行。

同一個 package 裡另外規定 controller → service → repository → entity,只能往後依賴。

例外分成兩份清單:allow 放設計上就要有的例外,debt 放現有的違規。

兩份清單只要有條目對不到實際的依賴,檢查就失敗。依賴已經拿掉、清單沒跟著刪,CI 會提醒,清單不會留著過期的東西。

後端 CI 多一個檢查步驟,前端掛在 npm run lint 裡,新的反向依賴在 PR 就擋下來。

示意圖:單位由上到下排成幾列,只能依賴下面列的單位,同一列互相依賴或往上依賴都不行;同一個 package 裡 controller、service、repository、entity 只能往後依賴。例外分成 allow 和 debt 兩份清單,條目對不到實際依賴時檢查失敗。

分層照現況排

照理想的分層排,會一次多出上百條待清,清單長到沒人看。

所以分層照現況排,挑違規最少的順序,先擋住新的違規,再慢慢清。

例如 subscription 排在 lending 下面,因為放貸引擎讀方案上限和訂閱狀態有 10 處,反方向只有績效費的計算在讀放貸資料。

照這個順序,後端 700 個檔、4,744 處引用裡只有 22 條違規,前端 1 條。分層跟現有程式大致吻合,循環集中在少數幾個檔。

圖解:lending 讀方案上限和訂閱狀態有 10 處,反方向只有績效費的計算,所以 subscription 排在 lending 下面。照理想分層會有上百條違規,照現況排只有 23 條:後端 700 個檔、4,744 處引用裡 22 條,前端 1 條。

分層順序是 agent 照違規數排的,我沒有逐條看過。之後有意見,改規則檔就好。

23 條違規,大多靠搬檔

清法照這個順序試:先搬檔,不行再改分層,最後才注入。

大多數是檔案放錯層,搬過去就好,例如 2FA step-up 驗證搬到 auth、Telegram 綁定端點搬到 notification。

有兩組是分層畫得太粗。績效費和 apikey 的 service、controller 本來就要讀寫放貸的資料,所以排到 lending 上面,entity 和 repository 留在下面。

真的需要注入的只有 2 處:放貸觸發績效費結算、通知中心讀有效公告,兩邊真的互相需要。

做法是依賴注入:下層定義 trait(Rust 的介面),實作寫在上層,啟動時再傳進去。

注入放在最後,是因為注入之後,從下層的程式看不到實際呼叫了誰,讀程式的人要多跳一層。

清完之後 debt 是空的,行為和 API 網址都沒變,2,793 個測試全過,後端同一天部署到 PROD。

流程圖:23 條違規照順序清。大多數靠搬檔解決,例如 2FA step-up 驗證搬到 auth、Telegram 綁定端點搬到 notification;2 組改分層,績效費和 apikey 的 service、controller 排到 lending 上面;只有 2 處注入,放貸觸發績效費結算和通知中心讀有效公告。清完 debt 清空、2,793 個測試全過,同一天上 PROD。

盲點:pub use 與巨集

掃描器不懂語意。

透過 pub use 轉出(re-export,把別處的項目從自己這裡公開)的項目,只算到轉出的那個檔。巨集展開後才出現的路徑,也認不到。

這是不編譯換來的代價,看規則和圖的時候要記得這兩個盲點。

#Rust#軟體架構#模組依賴#TypeScript

留言

載入留言中…

下一篇

工具

Claude Code mods 實作:翻一個月 session log 做出五個 mod

讓 Claude 讀過一個月的 session log,找出自己一再重複的需求,做成 prompt 上方的 band、status line 和指令,其中最有用的是追蹤 Claude 留下哪些東西的 leftovers。