Data Flow Diagram (DFD) 與 Entity Relationship Diagram (ERD) 實作練習


假如有進貨單格式如上,以往都是人工製作表單,現在老闆要我把這個作業電腦化,我應該怎麼做呢?

(仔細檢視上面的進貨單,如果A公司要運送貨物給B公司,對A公司來說是出貨單,對B公司來說才是進貨單。出貨單才會需要運送地址,進貨單只需要供應商編號或是名稱。除非進貨會到不同倉庫,例如B公司有台中倉庫以及台南倉庫,以下分析過程先忽略進貨地址。)

先進一步了解,什麼是進貨? 進貨是指產品從供應商運送到我們公司,他並不是一個單獨的作業 (從進貨單上有採購單號可以知道),也就是不會突然有一個進貨產生,因此再了解公司的作業後,會知道如下的情況 : 

(1) 當公司需要某些產品,會先向供應商詢價。
(2) 供應商會回覆報價單。
(3) 公司如果接受供應商的報價,會轉為採購單,送給供應商。
(4) 供應商如果接受採購,即會安排出貨。
(5) 公司接到後會將採購單轉為進貨單,並查核進貨狀況,轉為應付帳款。

因此我們要做的,就是把這些作業電腦化。

第一步要做的就是先找出這個作業的實體 (Entity),公司、公司人員、供應商、產品、詢價單、報價單、採購單、進貨單,這些都是實體,哪些才是要用到的實體呢?

因為要做出資料流流向圖 (Data Flow Diagram,DFD),詢價單、報價單、採購單、進貨單這些都算是資料,因此不算是DFD中的實體。而產品這個實體在系統中不會有行動,也都算是資料的一部分,因此也不算是DFD中的實體。

什麼是資料流流向圖? https://www.mysql.tw/2018/03/dfd-data-flow-diagram.html

剩下公司、公司人員、供應商,電腦化系統需要確認產生動作的人員,因此公司的負責人員是這個系統中的實體,而供應商、供應商的負責人員,該哪個當成DFD中的實體呢? 

因為通常供應商有固定的負責窗口,因此供應商、供應商的負責人員是一樣的意思,我們就以供應商為DFD中的實體。

因此初步的DFD,也就是Level 0的DFD (又可稱為Context Diagram)如下 :




這個圖的意思就是,我們把這個系統姑且稱為「MIS管理系統」,「負責人員」會輸入資料 (例如產生詢價單),然後系統會發出電子郵件通知「供應商」要求報價,當「供應商」報價確認後會在系統外通知「負責人員」 (例如電子郵件或是電話)。

當然你也可以讓「供應商」透過系統去通知「負責人員」,這時Confirm這個線就會經由系統,而不是在系統外通知「負責人員」,但是這樣做就需要讓「供應商」可以登入系統,這樣太複雜了,所以就保持上圖的樣子就好。

Context Diagram 通常用來表示系統與外界的關係,因此大多只會有系統與實體,而不表現Data store。你也可以在Context Diagram 中再加入主管做審核,或是管理人員做備份等作業,但是為了簡化我們的主題,這個圖只標示「負責人員」,因為他是資料的產生者/操作者,不能再簡化。

因此在做這類DFD時,可以先以最簡化的想法來做,然後需要再擴大時再畫出更多細節。

資料流向圖 (Data Flow Diagram,DFD) 有以下幾個規則 :

(1) 每個Process要有input及output。
(2) 每個Data store要有input及output。
(3) 每個Data store的input及output要經由Process,也就是不能由負責人員去接Data store。
(4) 每個Data store不能直接與另一個Data store連接,必須透過另外一個Process。
(5) 每個Entity不能直接與另一個Entity連接,必須透過另外一個Process。

其實很直觀去看以上的規則,很合情合理,因為一個程序或是資料儲存一定會有輸入,也一定會有輸出;實體也無法直接存取資料儲存,當然要透過程序;資料儲存也不會直接存取資料儲存,當然也是透過程序;實體當然不會輸入給另一個實體,也是需要透過程序。

現在把Level 0 的DFD再細分,就變成以下的Level 1 DFD :



有人可能會疑問 : 上面的Data store有些沒有input,有些沒有output。

例如,product data store沒有input,是因為它的input在另外編修product的DFD中。accounting data store沒有output,是因為進貨查核後,重要的是寫入accounting,在其他模組才需要從accounting 讀出。

另外,有人可能會疑問 : 採購與進貨程序不需要讀取product、supplier、staff嗎? 當然需要,只是因為太擁擠,才沒有劃出。總之,上面的圖可以看成「示意圖」,因為免費版本的LucidChart無法畫太複雜的資料。上述的DFD其實只是一部分而已,並未完整描述整個系統。

當你細分為各Level的DFD時,要記得各線條不要交叉,如果會交叉,表示需要再細分下層的DFD。所以上圖算是Level 1的DFD,你也可以把各Process再往下層DFD發展。

在Level 1的DFD,畫出了七個Data store,就可以開始來製作Entity Relationship Diagram (ERD) 。

我們現在只聚焦在進貨單,也就是進貨程序下的Inventory Data store。

與Inventory Data store相關的Entity Relationship Diagram (ERD) 如下圖 : 



什麼是實體關係圖? https://www.mysql.tw/2013/03/entity-relationship-model.html

因為我們使用免費的Lucidchart,物件太多而無法把完整的ERD畫在同一個文件,所以用另外一個ERD來表示畫不下的部分 :


由上述的ERD,我們就可以得到這個系統關於進貨需要五個表單(table) : inventory、supplier、staff、inventory_item、product。

再經由邏輯關聯就得到以下的邏輯資料庫 (紅色為主鍵,綠色為外鍵): 

(什麼是外鍵?)

每個關聯 (菱形的部分),就會產生主鍵與外鍵的關係。例如product與inventory_item之間,以及inventory與inventory_item之間。

product (product_id, product_name, product_price)

staff (staff_id, staff_name, staff_phone)

supplier (supplier_id, supplier_name, supplier_contact, supplier_addr, supplier_tel)

inventory (inventory_id, supplier_id, staff_id, invoice_date, invoice_no, po_id, tax_category, paid_amount, total, pay_due_date)

inventory_item (inventory_id, item_id, product_id, unit_price, amount)

當然以上只是部分欄位,再仔細討論後還可能修改增刪欄位。


另外如詢價 (Quotation) 及採購 (Purchase) ,也是類似方式,產生如下 :

quotation (quot_id, supplier_id, staff_id, quot_date, tax_category)

quotation_item (quot_id, item_id, product_id, unit_price, amount)

purchase (po_id, quot_id, supplier_id, staff_id, po_date, tax_category, total)

purchase_item (po_id, item_id, product_id, unit_price, amount)


其中可以討論幾個問題 :

(1) 在quotation、purchase、inventory表單內都有supplier_id及staff_id,可否將purchase及inventory的supplier_id及staff_id拿掉?

原本的結構,要抓出supplier_name,可以使用如下指令
SELECT inventory.inventory_id, supplier.supplier_name FROM inventory
JOIN supplier ON inventory.supplier_id = supplier.supplier_id;

拿掉inventory的supplier_id及staff_id後,要抓出supplier_name,可以使用如下指令
SELECT inventory.inventory_id, supplier.supplier_name FROM inventory
JOIN purchase ON inventory.po_id = purchase.po_id
JOIN supplier ON purchase.supplier_id = supplier.supplier_id;

以上的指令差別在哪裡?

(2) purchase表單中的total,可以計算而得,還需要total欄位嗎? 

如果沒有total欄位,每次需要時都要重新計算,會影響效率。但是如果有total欄位,雖然不用重算,但是萬一purchase表單中有數字更動而沒有同步重新計算total的話,total的數據就會不正確。但是通常會保留total欄位,讓效率好一點,但是要記得total數據的同步更新。

(3) 如果把quotation_item、purchase_item與inventory_item中加上product_name,你覺得如何?

要不要在quotation_item、purchase_item與inventory_item保留product_name欄位跟total欄位看似類似,但是實務上通常不會需要經常取得product_name,因此加上product_name只是多此一舉。

(4) 如果進貨有各地不同的倉庫,也就是需要進貨地址,inventory應該怎麼修改?

inventory (inventory_idsupplier_idstaff_id, invoice_date, invoice_no, po_id, tax_category, paid_amount, total, pay_due_date)

以上如果進貨還需要分進貨到不同的倉庫,就需要再加上warehouse_id,然後再增加一個warehouse表單。

上述範例為產生資料庫結構的大致流程,下面範例就是包含系統開發流程 : 
UML練習範例 : 線上商店 (Online Shopping) 的Use Case Diagram/Activity Diagram/ER Diagram/DFD/Class Diagram


相關參考資料 :
https://www.geeksforgeeks.org/dfd-for-food-ordering-system/
https://www.lucidchart.com/pages/data-flow-diagram
https://www.visual-paradigm.com/guide/data-flow-diagram/what-is-data-flow-diagram/

張貼留言

0 留言