為什麼最後不用 Reusable Workflows: GitHub Actions 可讀性、維護性與操作面取捨

我原本以為把 shared logic 抽成 reusable workflows 會比較乾淨。

結果實際做完之後, 我最後把它們又收回到入口 workflows, 只保留 composite actions。不是因為 reusable workflows 不能用, 而是因為它在這個 case 裡, 沒有帶來我真正想要的「乾淨」。

這篇把我最後的取捨整理下來。

一開始為什麼會想用 reusable workflows

理由其實很合理。

如果 deploy-devdeploy-prod 都有這些步驟:

  • test
  • build
  • migrate
  • terraform deploy
  • health check

那直覺上就會想抽出兩條 reusable workflows:

1
2
service-build-test
service-deploy

然後入口 workflows 變成很薄的協調層。

這種設計看起來有幾個明顯優點:

  • less YAML duplication
  • one shared implementation path
  • easier to update one common pipeline

在紙面上很漂亮。

問題不是功能, 是操作者體驗

真正讓我改主意的不是功能失敗, 而是操作面和可讀性。

GitHub Actions UI 會把 reusable workflows 也顯示成獨立 runs。這件事帶來兩個實際問題:

  1. 操作者會看到太多 workflows
  2. 責任歸屬會變得沒那麼清楚

我真正想要的 UI 是:

1
2
3
4
CI
Deploy Dev
Deploy Prod
Infrastructure

但用了 reusable workflows 之後, Actions 頁面會多出內部 workflow 項目。技術上它們沒有壞, 但對平常操作的人來說會變得很雜亂。

可讀性不是只有 UI, 也包括原始碼

除了 UI, source code 的追蹤成本也變高。

當 deploy 出錯時, 你常常要來回跳:

  • 入口 workflow
  • reusable workflow
  • composite action
  • Terraform root

這條追查路徑不是不能走, 但會比直接在入口 workflow 讀完整 pipeline 還慢。

尤其當 workflow 又牽涉到:

  • branch guard
  • environment-scoped vars
  • job-level permissions
  • OIDC auth
  • concurrency

如果這些東西拆在不同 workflow file, review 的認知負擔會變高。

我後來怎麼分辨什麼該抽, 什麼不該抽

我最後用一個很簡單的判準。

適合保留成 composite action 的情況

如果它只是 step group, 適合抽成 composite action。

例如:

  • install uv and sync dependencies
  • install Cloud SQL Proxy

這種東西抽出來很合理, 因為:

  • no job graph
  • no permissions model
  • no environment decision
  • no workflow identity ambiguity

適合留在入口 workflow 的情況

如果它本身就是 deploy pipeline 的主體, 我現在更傾向留在 入口 workflow。

例如:

  • build and push image
  • run migration
  • terraform plan and apply
  • health checks

這些步驟跟 branch、environment、permissions、identity 都強相關。留在入口 workflow 比較容易審查和除錯。

這是一個 DRY vs clarity 的取捨

本質上這不是技術對錯, 是取捨。

Option Advantage Cost
Reusable workflows less duplication worse UI and more indirection
Flat 入口 workflows more explicit some duplication
Composite actions reuse step groups cleanly cannot model full workflow graphs

在我這次的 case 裡, 真正要優先的是:

  • readable
  • maintainable
  • 乾淨的操作者入口面

所以我最後選的是:

  • flat 入口 workflows
  • composite actions for setup steps
  • accept some duplication

什麼樣的 duplication 是可以接受的

不是所有重複都該消滅。

如果 deploy-devdeploy-prod 都各自有一份:

  • build step
  • migrate step
  • terraform apply step

這在某些 case 其實是可以接受的。

因為它換來的是:

  • 每條 workflow 都能自成一體
  • 每個環境路徑都很清楚
  • 權限審查比較直觀
  • 操作者不需要理解 workflow 的內部接線

對中小型 repo 來說, 這種重複常常比高度抽象更好維護。

什麼時候 reusable workflow 仍然值得用

我不會說 reusable workflow 不該用。

它在這些情況還是有價值:

  • many repositories share the same workflow
  • the workflow graph itself is the reusable asset
  • UI clutter is acceptable
  • 操作者根本不會直接碰 Actions 頁面

但如果你的要求是:

  • Actions page must stay clean
  • 面向操作者的 workflows 必須一眼看懂
  • permissions must be easy to audit

那 reusable workflow 就不一定是最好的共用方式。

我最後的 workflow shape

我最後比較滿意的是這樣:

1
2
3
4
5
6
7
8
9
.github/
  workflows/
    ci.yml
    deploy-dev.yml
    deploy-prod.yml
    infra.yml
  actions/
    setup-api-env/
    install-cloud-sql-proxy/

這個 shape 的好處是, 面向操作者的 workflows 很清楚, shared setup steps 也沒有變成大量 copy-paste。

結論

我這次最大的體會是:

less YAML is not always less complexity.

reusable workflows 可以減少重複, 但不一定會讓整個系統更容易理解。

如果你真正在乎的是:

  • operator clarity
  • reviewability
  • permission visibility
  • GitHub Actions UI 的整潔度

那 flat 入口 workflows + composite actions 很可能比 reusable workflows 更適合。

References

0%