項目原因:
之前參與過一些 工作流 的項目,都是基於 某些 機構現有的 工作流引擎。
項目進行中,最鬧心的 莫過於 業務代碼 和 流程代碼 的 混淆一起。
見過的工作流是怎樣的:
>首先一個基於 Silverlight 的 流程UI設計器; 通過設計器 得到一個 流程XML 和 布局JSON 兩個文件(布局JSON文件當然對 后期運行是 沒有用的);
>業務單據 填寫信息,點擊“保存”,執行:保存單據數據,從 流程引擎 讀取 XML 得到 流程對象,設置下一步 跳轉 節點 N1,分發待辦;
>審批單據 填寫意見,點擊“審批”,執行:修改單據狀態,從 流程引擎 讀取 XML 得到 流程對象,設置下一步 跳轉 節點 N2,分發待辦;
>審批單據 填寫意見,點擊“駁回”,執行:修改單據狀態,從 流程引擎 讀取 XML 得到 流程對象,通過條件,設置下一步 跳轉 節點 N1 或者 N0 或者 NX,分發待辦;
於是,每一個 單據 的 按鈕事件 都得 調用一串 工作流代碼,跳轉到 哪個流程 也是 代碼 說了算。
於是,我開始質疑:流程設計器中 的 連線,連線上的判斷條件 莫非就是 裝飾?
不然,為什么 跳轉 哪個節點,回退到哪個節點,條件判斷 都在 業務代碼中 完成的 —— 和 流程設計器 的 設計,除了 N1,N2,N0,NX 有關系之外,基本沒有啥 關系。
我希望的工作流是怎樣的:
>首先一個 流程UI設計器,通過設計器 得到一個 流程XML 和 布局文件(反正也不參與后續,什么格式無所謂);
>業務單據 填寫信息,單擊“保存”,執行:保存單據數據,一行代碼 告訴 流程引擎:出庫審批 的 O20131015001 單據,啟動流程;
>審批單據 填寫意見,單擊“審批”,執行:修改單據狀態,一行代碼 告訴 流程引擎:出庫審批 的 O20131015001 單據,激發流程;
>審批單據 填寫意見,點擊“駁回”,執行:修改單據狀態,一行代碼 告訴 流程引擎:出庫審批 的 O20131015001 單據,激發流程;
>於是,整個過程中:業務只需要 辦完自己需要辦的事情,然后通知 流程引擎 自己去分析流程 到了哪一步,自己分析下一步該怎么辦;
打個比方:
1. 出庫人員 填寫一個 單據,單據拿給 秘書;
2. 秘書拿給 經理,經理填寫 同意;
3. 秘書再拿給 老板,老板填寫 同意/駁回;
突發意外:老板 人間蒸發了;
2. 秘書拿給 經理,經理填寫 同意;
於是下一個環節就是錯誤,這個錯誤的處理有兩種:
>秘書直接對經理說:老板沒了,沒有下一步審批人,您填寫的單據無法流轉,因為是同一個事務,您的“同意”也是無效的;您如果寫 “不同意”,就不會有任何錯誤;
>秘書拿上經理同意的單據走了。然后她一分析:找不到老板;她不好擅自做主,於是給公司所有管理層 發了 一封郵件:老板不在,很多單據 無法審批,流程走不通;
秘書的處理方式,就像 我所看所想的 工作流引擎:
>前者,因為老板沒了,經理的 同意 成了一個錯誤;
>后者,經理 直接就同意了——他不用管 下一步 該誰審批,也不用管 錯誤時 他該怎么做;
這個比方中,秘書 就扮演了 流程引擎 的作用:她負責將單據 按照她 知道的流程 走下去;出現錯誤,他會按照 制度 通知指定的管理層;
好的流程引擎,就像一個好的秘書(前面 老板蒸發,經理為難 的例子 可能不那么 嚴重,下面 的例子呢?);
如果哪天,經理人間蒸發了,出庫人員 單據寫好了,客戶拖着 貨物 已經開車跑了;
>前者,秘書告訴 出庫人員:經理不在了,你的單據無法流轉,因為是同一個事務,你的單據也是無效的;(單據可以填寫失敗,但是公司的貨物可是已經 拖走了的)
>后者,秘書收到 單據,她一分分析:找不到經理;她不好擅自做主,於是給公司所有管理層 發了 一封郵件:經理不在,很多單據 無法審批,流程走不通;
流程引擎:只應該負責流程的傳遞,而不是 破壞 具體數據和決策。
后期維護:
哪天,老板娶了個 搞經融的 老婆;老板審批之后,老婆想查閱(不是審批)一下財務;
業務代碼 和 流程代碼 混合的項目,除了修改 流程設計器 加節點 之外,還要 修改業務代碼:N2節點,老板審批成功,則給老婆發一封郵件;
而 業務代碼 和 流程代碼 分離的項目,流程設計器 中 增加一個 節點(執行插件,發送郵件,郵件接收人 從 XML 讀取);
程序結構圖:
最后的簡潔:
>不同類型的代碼 分離,永遠是 軟件設計 的 潮流趨勢:比方說 MVC框架,性能是比 WebForm 慢的,但是 因為實現了 代碼分離,減少的是后期 維護成本;
>流程引擎,只應該負責流程的傳遞,而不是因為流程的 錯誤 而 破壞 具體數據和決策;
>作者 將會 以 本文思想,完成 自己心目中的 流程引擎,敬請關注(抽象程度將在 工作流之上,工作流 只是 流程引擎的 一個 分支插件);