適讀人群:參與過工作流功能開發的程序員。(有可能你並不知道,你現在做的功能就是一個工作流功能)
一、 什么是工作流
舉個很土的例子。程序員出差,回來后要報銷票據。公司規定票據需要由員工所屬經理審批,然后交由財務審批,財務審批通過程序員才可以拿到錢。在這個過程中,經理可以駁回申請,財務也可以駁回申請,駁回后單據回到程序員編輯草稿的狀態。見下圖。
這就是一個工作流,一個單據由多個角色的用戶審批,不同角色看到的界面是不同的,每一個狀態都對應一個界面,例如程序員能夠看到“開始”和“草稿”的頁面,能夠編輯報銷單據的名稱和金額等信息,可以點擊“保存草稿”和“提交經理審批”按鈕;經理能夠編輯“經理審批理由”,可以點擊“同意”和“駁回”按鈕;財務能夠編輯“財務審批理由”,可以點擊“同意”和“駁回”按鈕等。
二、 為什么要使用工作流
因為客戶的需求總是在變更,我們開發程序編碼到一半的時候需求就會有顛覆性的修改。好的設計師不是設計出多么牛X的構架,而是設計出的程序易於快速適應需求的變更。下面來看看客戶是如何變更需求的。
以上一節中的報銷審批為例。客戶提出修改要求,所有程序員的報銷都提交給經理審批,那經理每天不用干正事了,時間都花在審批報銷上了,以后報銷這種小事,大於1000元的再來找經理審批,小於等於1000元的直接找財務就行了。流程見下圖。
過兩天可能客戶又說,還是要經理審批500元以上的審批吧,畢竟有些時候那些500-1000元的報銷單據財務不能直接做主。這樣的修改倒還好說,比較只要修改一個系統常量就搞定,如果客戶再說,我們不需要經理審批了,整個流程只要財務審批即可,那程序的修改可就大了。流程見下圖。
我相信各位肯定見過比這更狗血的需求變更。牢騷抱怨不能解決問題,更合理的設計才是王道。所以如果你的需求需要這種不同人員對一個單據進行的審批,那么請使用工作流。
三、 工作流的組成
本文不具體介紹工作流的編碼,如果各位想落地了解工作流的具體編碼,可以查閱微軟的WF工作流引擎或者JBPM開源工作流引擎。
工作流只要有節點狀態和流轉事件兩部分組成。
以上面報銷流程為例,包括“開始”在內的所有矩形都是節點狀態(“草稿”、“經理待審批”、“財務待審批”、“財務審批通過”)。所有的節點狀態都對應一個界面。相應的人員在對應的節點狀態打開報銷單據的時候才能進行自己的操作,不然只能進行只讀查看。例如當前單據處於“經理待審批”狀態,那么如果經理打開這個單據能夠編輯自己的審批意見,並且可以選擇點擊“通過”或者“駁回”按鈕。如果程序員進入這個單據,只能看到自己以前編輯過的內容,不能再次編輯,也不能進行經理和財務的操作。
到這里就不難理解流轉事件了,流轉事件就是一個狀態到下一狀態的觸發事件。還以報銷流程為例,圖中由一個節點狀態指向另一個節點狀態的線既為流轉事件。程序員點擊“提交”按鈕,就是將當前為“草稿”節點狀態的單據流轉到了“經理待審批”狀態的事件。
節點狀態與流轉事件的關系一般保存在配置文件中,例如JBPM就保存在XML文件中,WF更直觀,它附帶一個工作流的圖形編輯器,編輯好圖形后自動保存到對應的XAML文件中。以上面用戶的需求修改為例,如果客戶要求整個流程中不需要經理審批環節,那么只需要在配置文件中做修改,講“草稿”狀態下的“提交審批”流轉事件直接指向“財務待審批”即可,只是這樣一個簡單的修改即可完成客戶那復雜的修改需求,所以這里就是工作流的精華所在了。
除此之外我們還可以改造工作流引擎,在流轉事件中加入一些通用功能,例如郵件提醒、短信提醒等功能。例如增加如下需求,所有報銷審批操作執行成功后都要郵件提醒下一個狀態環節的負責人,程序員提交“草稿”后單據進入“經理待審批”狀態,那么就需要郵件通知經理,催促他盡快處理這位經理名下的報銷單據。
四、 需要注意的一些事情
我在這里給出一些工作流節點命名的一些建議。盡量以“待”字開頭,例如“經理待審批”、“財務待審批”,這樣命名可以體現出當前狀態需要由何種角色的人員來處理,而且也便於需求的變更。這里強烈不推薦使用“已”字命名,例如“程序員已提交”、“經理已審批”等。那么如果這樣設計,程序員在草稿狀態提交后就進入“程序員已提交”狀態,經理審批通過后進入“經理已提交”狀態。
這時客戶變更需求,要吧“程序員已提交”狀態刪除,那么這時候程序員在草稿狀態提交后就流轉到了“經理已審批”狀態。這樣理解起來就有些混亂了。
這里需要聲明一點,圖中的“結束”狀態在設計程序的時候不對應具體界面,指向“結束”的流轉事件也就沒有具體的按鈕觸發。也就是說“結束”狀態只是一個虛的狀態,指向“結束”狀態的節點狀態我們都認為它是一種終結的狀態。例如“財務審批通過”狀態就不可能再向其他狀態流轉了,那么它就是一種結束的狀態。上面的例子中只有一個結束狀態,我們這里再做一次需求的變更,所有的駁回操作不回到“草稿”狀態,都流轉到對應的結束狀態。如圖所示。
其實所有的人都希望將工作聚焦在當前需要完成的工作,其次是將要進行的工作。而那些已經完成的工作只有年終總結的時候需要統計一下。例如經理最希望看到當前待審批的報銷單,如果經理忙完了手頭的工作不免好奇心起會去關心一下還處於草稿狀態的報銷單,至於“經理駁回”狀態下的報銷單,可能只是年終總結的時候大BOSS需要看一下數量而已。所以在設計經理的報銷單查詢頁面時,應該默認查詢出所有“經理待審批”狀態的報銷單。所有的角色都希望默認查詢出自己對應狀態的報銷單據。財務的操作也應該是如此這里不再冗述。再舉一個例子,有時候大BOSS希望知道某一時間段內有多少報銷單已經完成了(這是所說的已完成就是已經結束的報銷單,包括“財務審批通過”、“經理駁回”和“財務駁回”),那么只需要從工作流中查詢出指向結束的節點狀態報銷單即可。
我再聲明一點,雖然“經理駁回”與“財務駁回”在某些業務上是相同的,但是請不要因為節省編碼而將這兩種狀態設計成一種狀態,比較人家客戶的業務人員在提出需求的時候是分開命名的,這也就意味着這是兩種不同的業務,誰知道哪天客戶心血來潮需要在“經理駁回”狀態下添加一個流轉事件允許返回到“草稿”狀態。到那時候可能我們可憐的程序員就要在某些代碼上瘋狂的加標志位了。
五、 寫在最后
細心的人可能會有這樣的想法,程序員在“草稿”狀態下可以無限制的保存當前編輯的報銷單,那么這個保存事件是不是應該也是一種流程,是不是應該從“草稿”到“草稿”的流轉呢?
本文只是簡介了一下簡單工作流的設計,在實際的設計中還有很多復雜的流程,例如某些業務需要在某個狀態節點由一群人來審批,這群人審批都通過了才可以流轉到下一個節點;某些業務是由多個狀態起始,最后結束的時候匯聚到一個狀態,有點形似 Y 型流程設計。