前言
在現代系統分析中,極少有工件像資料流程圖 (Data Flow Diagram, DFD) 這樣經常被誤解。它常被與流程圖混淆,或被錯誤地套用物件導向術語。真正的 DFD 既不是控制流的描繪,也不是類別模型——它是對資料如何在系統邊界內移動與轉換的嚴謹功能規格說明。儘管敏捷方法論與微服務架構興起,DFD 仍然是定義範疇、與非技術利害關係人驗證需求,以及在撰寫任何程式碼之前確保架構一致性的黃金標準。

然而,要產出專業等級的 DFD,不僅僅是畫出泡泡和箭頭而已。它需要嚴格遵守階層分解模型、清楚區分邏輯意圖與實體實作,並執行嚴謹的平衡法則以防止結構錯誤。本指南提供了正式系統分析中所使用的 DFD 詞彙、層級階層與品質不變量的完整參考。無論您是要規劃新的訂單處理系統,還是要區分業務需求與技術設計,以下章節將建立創建兼具分析健全性與實用性 DFD 所需的精確框架。
⚠️ 重要技術說明:PlantUML 與 VP AI Chatbot 的差異
必須特別強調的是,DFD 並非 PlantUML 原生支援的標準圖表類型。PlantUML 主要設計用於 UML 圖表(如類別圖、序列圖),其語法並不直接包含 DFD 的特定符號與佈局規則。
本文所展示的「Diagram as Code」範例之所以能夠實現,是因為 Visual Paradigm AI Chatbot 具備專門的知識庫與自訂渲染引擎。VP AI Chatbot 能夠理解 DFD 的領域語法,並將其轉換為可視化圖表或透過 Graphviz DOT 語言進行精準渲染。這使得用戶能夠以程式碼方式管理 DFD,突破了傳統 PlantUML 的限制,實現了多種自訂類型圖表的自動化生成。
1. 核心建構塊:DFD 的「詞彙」
在深入探討層級與類型之前,您需要了解構成每個 DFD 的四個基本符號。這些符號在所有標記法(Yourdon/DeMarco, Gane & Sarson, SSADM)中是一致的——它們僅在形狀上有所不同。
| 元素 | 用途 | Gane & Sarson 形狀 | Yourdon/DeMarco 形狀 |
|---|---|---|---|
| 外部實體 (終端器) | 系統之外的來源或去向——提供或消耗資料的人員、組織或外部系統 | 圓角矩形 | 正方形 / 方框 |
| 處理程序 | 將輸入轉換為輸出。總是以動詞命名並編號 | 圓角矩形 | 圓形 (泡泡) |
| 資料儲存 | 靜態存放資料的地方——檔案、資料庫或儲存庫 | 開口矩形 | 兩條平行線 |
| 資料流 | 顯示資料在元素間移動的帶標籤箭頭 | 帶標籤箭頭 | 帶標籤箭頭 |
命名慣例(對清晰度至關重要):
- 處理程序: 編號 + 動詞片語 →
1.0 驗證訂單,2.0 檢查庫存。編號是實現分解的關鍵(處理程序2.0分解為2.1,2.2,2.3…)。 - 資料儲存: 編號 + 名詞片語 →
D1 客戶,D2 庫存。 - 資料流: 資料內容的簡短描述 →
訂單請求,付款驗證,庫存數量。
2. 層級階層(透過分解實現抽象化)
分層 DFD 的核心概念是由上而下的分解:從單個不透明的泡泡開始,遞迴地揭露其內部細節,直到每個處理程序都變得微不足道地簡單。
2.1 情境圖 (Level 0)
- 抽象度: 最高可能——整個系統就是一個處理程序。
- 顯示內容: 外部實體,以及連接它們與單一系統泡泡的資料流。僅此而已。
- 刻意隱藏的內容: 所有內部處理程序、所有資料儲存,以及系統內部的所有資料流。
- 目的: 定義系統邊界——即「內部」與「外部」之間的清晰界線。
下圖是訂單處理系統的情境圖。請注意整個系統如何顯示為處理程序 0,且所有細節都被推到了外部世界:
(註:以下 Graphviz DOT 程式碼可由 Visual Paradigm AI Chatbot 解析並渲染)
digraph DFD_Context {
graph [
rankdir = LR
splines = true
overlap = false
nodesep = 0.5
ranksep = 1.2
fontname = "Helvetica,Arial,sans-serif"
fontsize = 12
label = "訂單處理系統 — 情境圖 (Level 0)"
labelloc = t
]
node [
fontname = "Helvetica,Arial,sans-serif"
fontsize = 11
penwidth = 1.5
]
node [shape = box, style = "filled", fillcolor = "#E1F5FE", color = "#0288D1"]
Customer; Supplier; Bank;
subgraph cluster_SystemBoundary {
label = "訂單處理系統";
fontname = "Helvetica,Arial,sans-serif; bold"
fontsize = 14
color = "#757575"
style = "dashed,rounded"
bgcolor = "#FAFAFA"
margin = 20
node [shape = circle, style = "filled", fillcolor = "#E8F5E9", color = "#388E3C", fixedsize = true, width = 1.6]
SYS [label="0\n訂單\n處理\n系統"];
}
edge [
fontname = "Helvetica,Arial,sans-serif"
fontsize = 9
color = "#555555"
arrowsize = 0.8
]
Customer -> SYS [label="訂單\n請求"];
SYS -> Customer [label="訂單\n確認與\n狀態"];
Supplier -> SYS [label="庫存\n可用性"];
SYS -> Supplier [label="庫存\n請求"];
Bank -> SYS [label="付款\n驗證"];
SYS -> Bank [label="付款與\n撥款請求"];
}
解讀邊界: 在此情境圖中,系統本身沒有可見的動作——但每一個外部互動都被列舉出來。這個工件是您與利害關係人簽訂的契約:它捕捉了範疇,並防止範疇蔓延,因為任何未在此圖上的內容都屬於範疇之外。
2.2 Level 1 DFD
- 抽象度: 將單個
0處理程序分解為其主要子處理程序。 - 顯示內容: 主要功能區域、關鍵資料儲存,以及資料如何在它們、儲存體與外部實體之間移動。
- 目的: 提供系統結構的第一個真實視圖。主要功能現在變得可見。
在訂單範例中,處理程序 0 分解為四個主要功能:驗證訂單、檢查庫存、處理付款和產生出貨。請注意資料儲存首次出現在這裡:
digraph DFD_Level1 {
graph [
rankdir = LR
splines = true
overlap = false
nodesep = 0.5
ranksep = 0.8
fontname = "Helvetica,Arial,sans-serif"
fontsize = 12
label = "訂單處理系統 — Level 1 DFD"
labelloc = t
]
node [
fontname = "Helvetica,Arial,sans-serif"
fontsize = 11
penwidth = 1.5
]
node [shape = box, style = "filled", fillcolor = "#E1F5FE", color = "#0288D1"]
Customer; Supplier; Bank;
subgraph cluster_SystemBoundary {
label = "訂單處理系統";
fontname = "Helvetica,Arial,sans-serif; bold"
fontsize = 14
color = "#757575"
style = "dashed,rounded"
bgcolor = "#FAFAFA"
margin = 20
node [shape = circle, style = "filled", fillcolor = "#E8F5E9", color = "#388E3C", fixedsize = true, width = 1.4]
P1 [label="1.0\n驗證\n訂單"];
P2 [label="2.0\n檢查\n庫存"];
P3 [label="3.0\n處理\n付款"];
P4 [label="4.0\n產生\n出貨"];
node [shape = record, style = "filled", fillcolor = "#FFF9C4", color = "#FBC02D", fixedsize = false]
CustomerDS [label="{ <id> D1 | 客戶 }"];
InventoryDS [label="{ <id> D2 | 庫存 }"];
OrderDS [label="{ <id> D3 | 訂單 }"];
PaymentDS [label="{ <id> D4 | 付款 }"];
}
edge [
fontname = "Helvetica,Arial,sans-serif"
fontsize = 9
color = "#555555"
arrowsize = 0.8
]
Customer -> P1 [label="訂單\n請求"];
Bank -> P3 [label="付款\n驗證"];
Supplier -> P2 [label="庫存\n可用性"];
P1 -> P2 [label="有效\n訂單"];
P3 -> P4 [label="付款\n已確認"];
P1 -> CustomerDS [label="驗證並更新\n客戶", dir=both];
P2 -> InventoryDS [label="更新並\n查詢庫存", dir=both];
P1 -> OrderDS [label="記錄\n訂單"];
P3 -> PaymentDS [label="記錄並\n驗證付款", dir=both];
P4 -> OrderDS [label="更新\n狀態"];
P2 -> Supplier [label="庫存\n請求"];
P4 -> Customer [label="出貨\n詳情"];
}
您應該始終檢查的關鍵事項:
- 編號一致性 (
1.0…4.0) 與父層級0匹配。 - 平衡(下文詳述)——情境圖中進出處理程序
0的流程必須等於 Level 1 圖表整體的進出流程。 - 雙向儲存存取(例如
P1 -> CustomerDS [dir=both])繪製為單個合併邊緣,而非兩條雜亂的箭頭。
2.3 Level 2 DFD(及更高層級)
- 抽象度: 進一步分解單個 Level 1 處理程序。
- 顯示內容: 複雜處理程序的細部細節。每個子處理程序都獲得一個原子功能。
- 目的: 您繼續創建 Level 3、Level 4 等,直到每個葉節點處理程序足夠簡單,可以用簡短的敘述或虛擬碼來描述——該終端處理程序稱為功能基元 (Functional Primitive)。
此處我們放大 Level 1 DFD 中的處理程序 2.0 檢查庫存,將其分解為 2.1 查詢庫存、2.2 檢查可用性 和 2.3 保留庫存:
digraph DFD_Level2 {
graph [
rankdir = LR
splines = true
overlap = false
nodesep = 0.4
ranksep = 0.8
fontname = "Helvetica,Arial,sans-serif"
fontsize = 12
label = "訂單處理系統 — Level 2 DFD (2.0 檢查庫存的分解)"
labelloc = t
]
node [
fontname = "Helvetica,Arial,sans-serif"
fontsize = 11
penwidth = 1.5
]
node [shape = box, style = "filled", fillcolor = "#E1F5FE", color = "#0288D1"]
P1_Parent [label="1.0 / 3.0\n(相鄰程序)"];
Supplier;
subgraph cluster_SystemBoundary {
label = "2.0 檢查庫存 (已分解)";
fontname = "Helvetica,Arial,sans-serif; bold"
fontsize = 14
color = "#757575"
style = "dashed,rounded"
bgcolor = "#FAFAFA"
margin = 20
node [shape = circle, style = "filled", fillcolor = "#E8F5E9", color = "#388E3C", fixedsize = true, width = 1.4]
P21 [label="2.1\n查詢\n庫存"];
P22 [label="2.2\n檢查\n可用性"];
P23 [label="2.3\n保留\n庫存"];
node [shape = record, style = "filled", fillcolor = "#FFF9C4", color = "#FBC02D", fixedsize = false]
InventoryDS [label="{ <id> D2 | 庫存 }"];
OrderDS [label="{ <id> D3 | 訂單 }"];
}
edge [
fontname = "Helvetica,Arial,sans-serif"
fontsize = 9
color = "#555555"
arrowsize = 0.8
]
P1_Parent -> P21 [label="有效\n訂單"];
P22 -> P1_Parent [label="庫存\n已確認與狀態"];
Supplier -> P22 [label="可用性\n回應"];
P21 -> P22 [label="庫存\n數量"];
P22 -> P23 [label="可用性\n已確認"];
P23 -> P1_Parent [label="庫存\n已保留"];
P21 -> InventoryDS [label="查詢", dir=both];
P23 -> InventoryDS [label="扣減\n保留量", dir=both];
P23 -> OrderDS [label="更新\n狀態"];
P22 -> OrderDS [label="讀取\n訂單"];
}
何時停止? 經驗法則:持續分解直到每個葉節點處理程序成為功能基元——即簡單到可以用幾行虛擬碼或簡短使用者故事完全指定的處理程序。沒有固定的目標層級;複雜度決定了深度。小型處理程序可能在 Level 1 就是基元;大型處理程序可能需要 Level 3 或 4。
3. 邏輯 vs. 實體 DFD — 意圖維度
這是經常與類別圖術語混淆的軸線。讓我們精確定義:
- 類別圖使用概念/邏輯/實體來表達資料模型的抽象層級。
- DFD 使用邏輯/實體來表達設計意圖——做什麼 vs. 怎麼做——這與層級階層是正交的。
這意味著每個層級(情境、Level 1、Level 2)都可以繪製為邏輯 DFD 或實體 DFD。 它們是獨立的軸線,而非階梯。
3.1 邏輯 DFD — 系統做什麼
| 面向 | 細節 |
|---|---|
| 焦點 | 業務需求以及系統必須完成什麼——不含實作偏見。 |
| 刻意忽略 | 硬體、軟體、資料庫、部門、手動vs自動、檔案格式、時序。 |
| 用於 | 需求分析與業務建模。 |
比較下方的邏輯會員資格 DFD 與其正下方的實體 DFD。相同的系統,相同的層級——但邏輯版本沒有命名任何技術或特定部門,僅包含業務活動與概念性資料儲存:
digraph DFD_Logical {
graph [
rankdir = LR
splines = true
overlap = false
nodesep = 0.5
ranksep = 0.8
fontname = "Helvetica,Arial,sans-serif"
fontsize = 12
label = "邏輯 DFD — 系統做什麼 (無實作偏見)"
labelloc = t
]
node [
fontname = "Helvetica,Arial,sans-serif"
fontsize = 11
penwidth = 1.5
]
node [shape = box, style = "filled", fillcolor = "#E1F5FE", color = "#0288D1"]
Customer; Staff;
subgraph cluster_SystemBoundary {
label = "會員系統 (邏輯)";
fontname = "Helvetica,Arial,sans-serif; bold"
fontsize = 14
color = "#757575"
style = "dashed,rounded"
bgcolor = "#FAFAFA"
margin = 20
node [shape = circle, style = "filled", fillcolor = "#E8F5E9", color = "#388E3C", fixedsize = true, width = 1.4]
P1 [label="1.0\n註冊\n會員"];
P2 [label="2.0\n發出\n續約"];
node [shape = record, style = "filled", fillcolor = "#FFF9C4", color = "#FBC02D", fixedsize = false]
MemberDS [label="{ <id> D1 | 會員紀錄 }"];
}
edge [
fontname = "Helvetica,Arial,sans-serif"
fontsize = 9
color = "#555555"
arrowsize = 0.8
]
Customer -> P1 [label="會員\n申請"];
Staff -> P2 [label="續約\n請求"];
P1 -> MemberDS [label="新增\n會員"];
P2 -> MemberDS [label="更新並\n讀取紀錄", dir=both];
P2 -> Customer [label="續約\n通知"];
}
3.2 實體 DFD — 系統如何實作
| 面向 | 細節 |
|---|---|
| 焦點 | 邏輯模型的具體實現:特定技術、檔案/DB名稱、人員、部門、硬體、時序、協定。 |
| 包含 | DBMS與Schema名稱、訊息佇列、API與協定 (HTTPS, JSON, JDBC, JMS)、人員與部門、自動化選擇。 |
| 用於 | 系統設計與實作規劃。 |
相同的會員系統,現在作為實體 DFD——注意處理程序 1.0 變成了註冊服務 (伺服器),資料儲存變成了 MySQL members_db,出現了電子郵件佇列,且流程標記了具體協定:
digraph DFD_Physical {
graph [
rankdir = LR
splines = true
overlap = false
nodesep = 0.5
ranksep = 0.8
fontname = "Helvetica,Arial,sans-serif"
fontsize = 12
label = "實體 DFD — 系統如何實作 (技術與部門)"
labelloc = t
]
node [
fontname = "Helvetica,Arial,sans-serif"
fontsize = 11
penwidth = 1.5
]
node [shape = box, style = "filled", fillcolor = "#E1F5FE", color = "#0288D1"]
CustomerWeb [label="客戶\n網頁入口"];
FrontOffice [label="前台\n辦公室"];
subgraph cluster_SystemBoundary {
label = "會員系統 (實體)";
fontname = "Helvetica,Arial,sans-serif; bold"
fontsize = 14
color = "#757575"
style = "dashed,rounded"
bgcolor = "#FAFAFA"
margin = 20
node [shape = circle, style = "filled", fillcolor = "#E8F5E9", color = "#388E3C", fixedsize = true, width = 1.5]
SRV [label="註冊\n服務\n(伺服器)"];
node [shape = record, style = "filled", fillcolor = "#FFF9C4", color = "#FBC02D", fixedsize = false]
MySQLDS [label="{ <id> D1 | MySQL\nmembers_db }"];
QueueDS [label="{ <id> D2 | Email\nQueue }"];
}
edge [
fontname = "Helvetica,Arial,sans-serif"
fontsize = 9
color = "#555555"
arrowsize = 0.8
]
CustomerWeb -> SRV [label="HTTPS POST\n/register\n(JSON)"];
FrontOffice -> SRV [label="桌面應用\nAPI 登入"];
SRV -> MySQLDS [label="JDBC Insert\n& Select Txn", dir=both];
SRV -> QueueDS [label="JMS\nMessage"];
SRV -> CustomerWeb [label="HTTP 200\n歡迎郵件"];
}
重點: 成熟的專案會在需求收集期間先產出邏輯 DFD(情境至 Level 2),以便利害關係人在沒有技術雜訊的情況下驗證行為的正確性,然後在設計期間從中衍生實體 DFD——當「做什麼」達成共識後,即可疊加「怎麼做」。層級保持平行:您的實體 Level 1 對應於您的邏輯 Level 1,並豐富了實作細節。
4. 將 DFD 層級映射到類別圖抽象
如果您已經習慣以類別圖抽象思考,這裡有一個近似(有用但不完美)的橋接:
| 類別圖概念 | ≈ DFD 對應 |
|---|---|
| 概念類別圖 (業務層級理解) | 情境圖或 Level 1 邏輯 DFD |
| 邏輯類別圖 (詳細功能規格) | Level 2+ 邏輯 DFD |
| 實體 / 實作類別圖 (技術特定設計) | 實體 DFD |
警告: 此映射僅為心智模型的便利工具,並非形式上的等同。正如前述,系統分析文獻(DeMarco, Gane & Sarson, Yourdon)中的權威術語嚴格區分為情境、Level 1、Level 2… 加上正交的邏輯/實體區別。
5. DFD 的關鍵品質法則
這些不變量是區分專業、平衡的 DFD 與草率圖表的關鍵:
- 命名紀律。 每個處理程序都有動詞+名詞,並已編號,且編號形成嚴格的樹狀結構 (
0→1.0…4.0→2.1…2.3)。每個資料儲存編號為D1,D2, …。每個流程都有描述性標籤。 - 平衡(跨層級一致性)。 父處理程序的輸入和輸出必須完全匹配其子處理程序的組合輸入和輸出。如果處理程序
2.0接收有效訂單並返回庫存已確認,那麼分解2.0的 Level 2 圖表必須接受有效訂單並必須產生庫存已確認——不多也不少。這是分解時最重要的單一規則。 - 禁止實體對實體直接流動。 資料總是透過處理程序流動。外部實體永遠不會直接相互連接或直接連接到資料儲存。
- 禁止實體對儲存直接流動。 外部實體僅透過處理程序與儲存互動(在 DeMarco/Yourdon 慣例中這是嚴格規則)。
- 雙向存取為單一邊緣。 當兩個元素雙向交換資料時(資料儲存常見情況),繪製單個箭頭並設定
dir=both及合併標籤 ("更新並查詢"),而非兩條單獨的單向箭頭——這能保持圖表整潔易讀。 - 止於功能基元。 僅依需要進行分解;終端處理程序應能用幾行虛擬碼描述。
6. 這些圖表中使用的視覺慣例
上述所有範例均遵循標準現代 DFD 樣式,可在 Graphviz 中乾淨渲染:
- 外部實體 — 淺藍色方框配藍色邊框 (
#E1F5FE/#0288D1)。 - 處理程序 — 綠色圓形配綠色邊框 (
#E8F5E9/#388E3C),編號並以動詞命名。 - 資料儲存 — 記錄樣式黃色條 (
#FFF9C4/#FBC02D),標記 ID + 名稱 (D2 | 庫存)。 - 系統邊界 — 虛線圓角容器 (cluster),淺色背景 (
#FAFAFA) 和灰色邊框 (#757575)。 - 邊緣 — 中灰色 (
#555555),小箭頭,透過dot引擎進行軸對齊路由。
7. 展示 DFD 前的檢查清單
在將任何 DFD 視為完成之前,請使用此清單作為自我審查門檻:
- 層級是否清楚標示(情境 / Level n)?編號樹是否與父層級一致?
- 四種符號類型是否正確使用,並符合正確的命名模式?
- 圖表是否與其父層級平衡(進出流程完全匹配)?
- 所有流程是否都標記了有意義的資料描述?
- 雙向儲存/供應商流程是否合併為單個
dir=both邊緣? - 邊界和外部實體是否免除了直接的實體↔實體 / 實體↔儲存流動?
- 每個葉節點處理程序是否符合功能基元的資格?
8. 總結
- 階層 = 層級。 情境 (Level 0) → Level 1 → Level 2 → … 每個層級將一個處理程序分解為更細的子處理程序,直到達到功能基元。
- 意圖 = 邏輯 vs. 實體。 邏輯 DFD 回答做什麼;實體 DFD 回答怎麼做。這兩個軸是正交的——每個層級都可以用任一種方式繪製。
- 不要將 DFD 層級稱為「概念/邏輯/實體」。 那些是類別模型術語。在正式系統分析(DeMarco, Gane & Sarson, Yourdon)中,正確的詞彙是情境 / Level 1 / Level 2 加上邏輯/實體的區別。
- 最佳實踐: 在分析期間建構 邏輯 DFD(Level 0–2)以鎖定需求,然後在設計期間衍生實體 DFD 以規劃實作。
上述四個 Graphviz 圖表展示了完整的進程。每個圖表均可直接從程式碼區塊渲染——您可以將其中任何一個複製到 Graphviz 中以查看渲染結果。再次提醒,雖然這些範例使用 DOT 語法,但 Visual Paradigm AI Chatbot 的專門知識使其能夠超越標準 PlantUML 的限制,支援這種自訂類型的 Diagram as Code 工作流。
結論
構造良好的資料流程圖不僅是視覺輔助工具;它是業務利害關係人與技術團隊之間的理解契約。通過嚴格應用上述原則——維持嚴格的編號階層、強制執行分解層級間的平衡,並保持邏輯與實體關注點的正交性——您將 DFD 從模糊的草圖轉變為精確的工程工件。區分系統必須做什麼(邏輯)與如何構建(實體)尤為關鍵;混淆這兩個軸線是系統分析中範疇蔓延與過早優化的最常見原因。
當您應用這些概念時,請記住 DFD 成功的最終衡量標準不是其美學複雜度,而是其分析效用。明確定義邊界的情境圖可防止後續昂貴的返工;平衡的 Level 2 圖表確保沒有功能需求在分解過程中遺失;而能用三行虛擬碼描述的功能基元則標誌著分解已達到其自然終點。請使用第 7 節提供的檢查清單作為最終門檻,並將 Graphviz 模板視為動態標準而非靜態範例。當以紀律執行時,DFD 仍然是馴服複雜性並交付真正符合業務意圖系統的最強大工具之一。