iT邦幫忙

2026 iThome 鐵人賽

DAY 1
0

Day 1|先畫誰靠誰,再談加規則

先講背景:為什麼今天不先加規則?

你如果在 AI 快速生成專案,最常見的感覺是這樣:

  • 今天有功能可以跑
  • 明天再改一個欄位要開很多檔
  • 三天後又突然有三個地方壞掉

這篇不是先談「怎麼修」,而是先做一件很務實的事:先知道現況。

第 0 天的專案我故意把節奏放寬(沒有先加任何規矩、檢查),讓 vibe-order 能用即可。結果留下 13 次存檔、可下單,也有測試結果。

今天我做的事很簡單:先畫出誰靠誰地圖,留下第一次量到的對照數字。
這張圖,技術上叫依賴圖。結帳櫃台要問倉庫有沒有貨,這就是靠;把每個櫃台畫成點、誰找誰畫成箭頭,就是這張圖。有了它,後面要加規矩才不會一上來卡住全線。

這篇適合誰?

你可以直接看:

  • 你已經有用 AI 打很多次存檔,想確認架構是否變「越來越黏」
  • 你在 apps/*packages/* 這種 workspace 裡開發
  • 你有基本 TypeScript/JavaScript 基礎,想要有「可量測」的起步,不想先背架構術語

這篇對兩種情況用處不大。一個人自己玩的專案,先不用看。還不必切套件邊界,也先不用看。

白話比喻:把專案想成餐廳

先把專案想成一間外帶餐廳:

  • checkout = 收銀台
  • inventory = 倉庫
  • loyalty = 點數櫃台
  • 每個 packages/*index.ts = 前台櫃台

正常流程是:收銀台要點數就到 loyalty 的櫃台(index.ts)問,像是 loyalty/src/index.ts
問題是,若收銀台直接闖進點數櫃台後場(loyalty/src/...)改程式,櫃台改版時收銀台也會一起壞。
這種跨邊界、越界去翻後場的行為,就是我們這篇要抓的重點之一。

更簡單的 TypeScript 例子(你會比較好懂)

舉一個下單後要做三件事的例子:

  1. 下完單要傳訂單編號(orders
  2. 要加點數(loyalty
  3. 要處理時間格式(date-fns

比較穩定的寫法,通常是這樣,走每個套件的對外入口。下面的 alias 是示意;vibe-order 實際使用的是 @vibe-order/*

import { placeOrder } from "@orders"
import { grantPoints } from "@loyalty"
import { formatTwTime } from "@shared/time"

混亂版常常是:

import { placeOrder } from "@orders/src/commands/create.ts"
import { grantPoints } from "@loyalty/src/engine/bonus.ts"
import { DateTime } from "luxon"
import { format } from "date-fns"

你會看到的代價是:

  • 內部路徑一改,使用者都受影響
  • 兩套時間函式庫混在一起,規則不一致
  • 需求很小時,卻有越來越多「看似無關」的檔案要改

所以 Day 1 不急著修,先量測:到底真的在哪裡繞邊界。

這天要量兩件事

1) 量「誰要找誰」

我用 dependency-cruiser 16.10.4 做靜態 import 圖,輸出 reports/ 三個檔(JSON、DOT、Markdown),重點是每個節點的:

  • Ce:它要找多少別人(出去打電話)
  • Ca:有多少人來找它(被叫進來)
  • I = Ce / (Ce + Ca):比較像總機,還是比較像倉庫

2) 量有沒有衝進後場

窗口是每個櫃台的 index.ts。不走窗口、直接 import packages/B/src/...,就是衝進後場(技術上叫穿層匯入)。
短期比較快,櫃台一改版,結帳櫃台也一起壞。

本次實測結果

套件 Ce Ca I
apps/web 7 0 1.00
checkout 6 1 0.86
cart 1 2 0.33
inventory 0 2 0.00
orders 0 2 0.00

結帳櫃台很明顯比較像總機:要找 6 個來源,只有 1 個節點會來找它,所以 I 比較高。
這不代表它壞,只代表它依賴的來源比較多;後面我會觀察,這些來源改動時,它是不是也常得跟著改。

https://ithelp.ithome.com.tw/upload/images/20260915/20184292HPsOrH4Ghj.png
圖 1|Day 1 套件依賴圖。箭頭由依賴端指向被依賴套件;橘色為 packages/checkout,藍色為 apps/web。來源:vibe-order 本地實測。

我先期待找到的問題,這次反而是 0 條

第 0 天第 3 句提示詞本來最容易被我猜中的情境是:

「加忠誠點數功能,結帳完成就加點。」

我原本擔心的是它會直接 import @loyalty/src/...
實測卻是 fa23997 這次存檔走點數櫃台的窗口 packages/loyalty/src/index.ts,沒有衝進後場。

也就是說:這次最壞猜想沒發生,窗口還算有在走;但結帳櫃台已經要找 6 個別人,仍是盯梢重點。

最容易踩坑的三件事(我真踩到)

這份圖不是一次跑就對。這次我跑到第 4 輪才算乾淨:

  1. 第一輪:dependency-cruiser 沒有設定檔會直接失敗。
  2. 第二輪:從 repo 根目錄讀 apps/web/tsconfig.json,TS18003。
  3. 第三輪:.next/ 和測試聚合檔一起被掃進去,模組暴增。

只排除建置產物與不想量的文件,才得到 20 個模組、11 個節點,當作第一次量到的對照數字。

這張圖沒辦法回答的問題(你不能把它當健康檢查報告)

只看靜態 import,這裡看不到的是:

  • 動態 import()
  • DI 容器/runtime 注入
  • 用字串字面值拼出來的關聯
  • 資料庫、外部 API 等協作關係

所以「0 條衝進後場」只代表這次掃到的靜態邊界有走窗口,不能等於系統完全沒有黏在一起的問題。
它的價值是:先把能量、能重跑的對照數字放下來,後面再加會擋下來的規矩(護欄)才有得比。

明天會做什麼

明天是 Day 2:先用同一組 day0/prompts.md,對照第 1~11 句每次存檔的改動量,看看提示詞越多時,改動是不是越「大包」。
先有 Day 1 的對照數字再做 Day 2,才能知道是專案變複雜,還是 AI 開發方式在偏。

來源與 AI 使用揭露

本文的數字與結論都來自本地實測,包含:

  • npm install --save-dev 'dependency-cruiser@^16'
  • node scripts/diagnose/dep-graph.mjs
  • npm run diagnose:deps

腳本雛形由 Claude Code 協作草擬,實際執行與調整由 Codex 與 vibe-order 專案結果對齊。
程式目前只在本機實驗 repo,不直接對外提供連結;發文前我會再做一輪人工複核。


下一篇
Day 2|後面的提示詞,不一定改比較兇
系列文
Vibe 完之後:30 天給 AI 蓋的小商店裝上護欄2
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言