骨架:訂單履約場景狀態(tài)機與異常全解析)
干了這么多年我為什么還在強調(diào)先把流程想清楚再做系統(tǒng)處理流程設計與系統(tǒng)設計這兩個詞程序員天天掛在嘴邊但真正能說明白的沒幾個。尤其是流程設計很多人覺得畫個流程圖、箭頭連一連、節(jié)點擺一擺就算完事。實際工作里流程設計決定的是系統(tǒng)的骨架系統(tǒng)設計決定的是血肉。骨架錯了后面填充多少功能模塊都是白搭。這篇文章我不會講教科書式的理論也不會空談方法論。我拿一個真實的訂單處理場景來做完整的拆解演示把流程設計、狀態(tài)機落地、異常處理、監(jiān)控埋點這幾個環(huán)節(jié)全部走一遍。適合正在做后端系統(tǒng)、微服務架構或者需要從零搭一套業(yè)務系統(tǒng)的開發(fā)者參考。也適合產(chǎn)品經(jīng)理和技術負責人看因為很多沖突的根源恰恰是流程沒定義清楚就進入編碼了。1. 先把處理流程和系統(tǒng)設計的邊界劃清楚1.1 處理流程到底在解決什么問題處理流程解決的是業(yè)務層面的問題一件事從一個狀態(tài)到下一個狀態(tài)經(jīng)過哪些環(huán)節(jié)每個環(huán)節(jié)做什么決策異常情況下往哪走。它不關心代碼怎么寫不關心你用MySQL還是Redis不關心接口是同步還是異步。它只回答一個問題數(shù)據(jù)在系統(tǒng)中是怎么流動的。舉個最簡單的例子電商下單用戶提交訂單系統(tǒng)校驗庫存鎖定庫存生成支付單用戶支付回調(diào)通知異步發(fā)貨這就是一條主線流程。但真實場景沒這么簡單。庫存不足怎么辦、超時未支付怎么辦、支付回調(diào)失敗怎么辦、發(fā)貨失敗怎么辦這些分支都屬于流程設計的范疇。系統(tǒng)設計解決的是技術層面的問題流程確定之后每個環(huán)節(jié)用什么組件實現(xiàn)、數(shù)據(jù)怎么存儲、接口怎么定義、并發(fā)怎么控制、異常怎么兜底。系統(tǒng)設計必須服從流程設計而不是反過來。如果流程沒定清楚就上來設計表結構大概率會返工。很多項目組犯的典型錯誤是產(chǎn)品畫了兩頁流程圖開發(fā)就直接開搞。結果流程里支付成功后的狀態(tài)扭轉和退款后的狀態(tài)扭轉語義重疊后面排錯排到懷疑人生。根本原因不是開發(fā)能力不行是流程設計階段壓根沒把狀態(tài)定義清楚。1.2 為什么系統(tǒng)設計經(jīng)常被流程設計拖后腿我接觸過很多項目系統(tǒng)架構看著挺合理服務拆分也干凈但聯(lián)調(diào)的時候就暴露出各種別扭。仔細一拆八成是流程設計階段埋的雷。一個典型場景運營后臺要支持訂單改價。產(chǎn)品定義的流程是訂單詳情頁-點擊改價-輸入新價格-確認提交。開發(fā)拿到需求后開始設計訂單表加個改價記錄字段接口加個updatePrice方法完事。但是改了價之后支付單金額變了沒如果支付通道已經(jīng)生成了支付二維碼二維碼里的金額是按照原價生成的用戶掃了碼會提示金額不一致這個流程分支誰來處理此時開發(fā)才發(fā)現(xiàn)流程圖上訂單改價這個節(jié)點根本沒有向下游延伸。為了補救只能在代碼里if-else一堆判斷屬于典型的流程沒想明白就動手。系統(tǒng)設計本身是有章法的——分層、模塊化、抽象接口、控制反轉這些技術手段都有成熟套路。但流程設計沒有標準答案每個業(yè)務都不一樣依賴的是思考的完整性。這兩個東西放到一起做真正難的不是技術實現(xiàn)而是怎么把流程中的每個分支、每個異常情況都識別出來再落到系統(tǒng)設計里。1.3 流程設計的基本步驟我不說廢話直接列第一步明確主流程。從觸發(fā)點開始到終態(tài)結束先把主干畫出來。不要管異常不要管擴展純粹一條主線。第二步識別分支。每個節(jié)點問三個問題成功之后去哪、失敗之后去哪、超時之后去哪。第三步定義狀態(tài)。給流程中的每個關鍵環(huán)節(jié)定義狀態(tài)名注意區(qū)分業(yè)務狀態(tài)和流程狀態(tài)。第四步確定流轉條件。什么情況下允許從A狀態(tài)到B狀態(tài)什么情況下禁止流轉要有明確規(guī)則。第五步補異常兜底。異常分支、補償邏輯、人工介入點必須在流程圖上體現(xiàn)出來。這五步走完流程設計才算初步完成。這時候再進入系統(tǒng)設計你會發(fā)現(xiàn)自己設計表結構、定義接口、劃分模塊的時候思路清晰得多。2. 一個案例拆到底訂單履約流程的完整設計思路2.1 案例背景與需求分析為了演示方便我虛構一個項目某跨平臺訂單系統(tǒng)的訂單履約模塊。背景是用戶在平臺下單之后訂單要經(jīng)歷支付、審核、揀貨、出庫、配送、簽收等環(huán)節(jié)其中還穿插著退款、改地址、攔截等操作。這個項目最開始的版本只做了最簡單的正向流程——下單、支付、發(fā)貨、完成。加上退款之后就亂套了用戶在配送中申請退款倉庫已經(jīng)出庫了退款該不該退貨要不要追回后續(xù)狀態(tài)怎么流轉順著這個案例我把處理流程設計的每一步都走一遍重點展示怎么預判和拆解復雜分支。在設計之前我先把業(yè)務規(guī)則問清楚用戶申請退款在什么節(jié)點之前可以直接退款在什么節(jié)點之后必須攔截物流訂單已出庫但未簽收用戶申請退款是走攔截還是等簽收后再退攔截成功和攔截失敗退款流程分別怎么走訂單改地址和退款同時發(fā)生先處理哪個這些問題全部都問到業(yè)務方確認清楚之后再來畫流程。2.2 一級流程的拆解主鏈路與支鏈路主鏈路是這樣的用戶下單支付系統(tǒng)審核風控校驗推送倉庫揀貨出庫配送簽收完成支鏈路至少有這幾條支付超時自動取消用戶在待發(fā)貨時申請退款用戶在已發(fā)貨時申請退款物流配送異常拒收、超時、丟失訂單攔截這些支鏈路不能獨立設計因為支鏈路和主鏈路共享同一個訂單狀態(tài)它們之間會發(fā)生狀態(tài)競爭。這里我強烈建議先定義狀態(tài)清單再畫流程圖。很多人習慣上來就畫箭頭畫到一半就發(fā)現(xiàn)圖太亂。實際正確做法是先把所有可能的狀態(tài)窮舉出來再定狀態(tài)間的遷移規(guī)則。2.3 節(jié)點級細化每個環(huán)節(jié)的輸入、處理、輸出流程不能只畫到模塊級別關鍵節(jié)點必須細化到輸入-處理-輸出這個粒度。拿支付回調(diào)節(jié)點舉例輸入支付通道的回調(diào)通知包含訂單號、支付金額、支付時間、渠道流水號處理校驗簽名、校驗訂單狀態(tài)、校驗金額一致性輸出支付成功狀態(tài)、支付單流水記錄、觸發(fā)后續(xù)流程事件細化到這個程度系統(tǒng)設計才能跟上。因為你明確知道了這個節(jié)點要接什么外部系統(tǒng)、要做什么校驗、要產(chǎn)出什么結果后面定義接口和數(shù)據(jù)結構的時候完全是按圖索驥。在真實項目中這個環(huán)節(jié)最花時間但最值得花。我把整個訂單履約流程按節(jié)點拆完之后發(fā)現(xiàn)原本以為要建20個接口的模塊其實有12個是多余的通過狀態(tài)機內(nèi)部流轉就能解決。這就是流程細化的直接收益。3. 從流程到系統(tǒng)狀態(tài)機設計與核心邏輯實現(xiàn)3.1 狀態(tài)清單定義方法與注意事項狀態(tài)清單在流程設計中是重中之重。我通常把狀態(tài)分為三級來管理一級狀態(tài)訂單的粗略生命周期待支付、已支付、履約中、已完成、已關閉。 二級狀態(tài)一級狀態(tài)下的細分比如履約中可以細分為待發(fā)貨、已發(fā)貨、配送中。 三級狀態(tài)具體動作位比如已發(fā)貨可以細分為待攬收、運輸中、待派送。為什么要分三級因為不同角色關注的狀態(tài)粒度不一樣。用戶在App上看到的是已發(fā)貨客服看到的是運輸中運營看到的是待攬收。如果只建一個狀態(tài)字段就得不停給不同角色做狀態(tài)翻譯費勁且容易出錯。狀態(tài)命名我建議用英文字母加數(shù)字的組合做系統(tǒng)內(nèi)部編碼顯示層再做映射。用中文狀態(tài)名直接存數(shù)據(jù)庫編碼風格會亂而且后面加狀態(tài)需要改一堆代碼。注意狀態(tài)字段和業(yè)務流程字段必須分開。比如已發(fā)貨是一個狀態(tài)物流單號是一個業(yè)務字段不能把物流單號的有無作為判斷狀態(tài)的條件。狀態(tài)機只依據(jù)狀態(tài)字段流轉業(yè)務字段只做信息補充。這個原則能避免很多隱性耦合。最后是狀態(tài)流轉表。我整理了一個表格把核心狀態(tài)遷移規(guī)則全部列出來。這個表在評審會議上比任何流程圖都好用一目了然能看到有沒有漏掉轉移。當前狀態(tài)觸發(fā)動作目標狀態(tài)前置條件后續(xù)動作待支付用戶支付成功已支付金額校驗一致創(chuàng)建履約單已支付系統(tǒng)風控審核通過待發(fā)貨風控標記通過通知倉庫待發(fā)貨用戶申請退款退款中無出庫記錄自動退款流程待發(fā)貨倉庫確認揀貨揀貨中庫存鎖定成功通知物流已發(fā)貨用戶申請退款退款攔截中存在物流單號發(fā)起物流攔截退款攔截中攔截成功退款中物流商確認可攔截創(chuàng)建退貨單退款攔截中攔截失敗待簽收物流商確認無法攔截提示用戶等簽收后退有了這張表系統(tǒng)設計里的狀態(tài)機代碼基本就能照抄了。3.2 狀態(tài)機的控制邏輯與代碼落地狀態(tài)機的代碼落地方式有很多種簡單的用if-else嵌套講究點的用狀態(tài)模式再講究點用現(xiàn)成的狀態(tài)機框架。我個人的經(jīng)驗是業(yè)務流量不大、狀態(tài)數(shù)量在十來個以內(nèi)老老實實用表驅動的方式就夠了不要為了設計模式而設計模式。表驅動的本質就是把狀態(tài)遷移規(guī)則配置化。偽代碼大致是這樣的# 遷移規(guī)則配置 TRANSITIONS { (待支付, 用戶支付成功): 已支付, (已支付, 風控審核通過): 待發(fā)貨, (待發(fā)貨, 用戶申請退款): 退款中, (待發(fā)貨, 倉庫確認揀貨): 揀貨中, (已發(fā)貨, 用戶申請退款): 退款攔截中, (退款攔截中, 攔截成功): 退款中, (退款攔截中, 攔截失敗): 待簽收, } def trans(current_state, action): key (current_state, action) if key not in TRANSITIONS: raise IllegalStateTransition(current_state, action) return TRANSITIONS[key]代碼不復雜但關鍵在于遷移動作和狀態(tài)更新必須在同一個事務里完成。比如已支付到待發(fā)貨這個遷移除了修改狀態(tài)字段可能還要插入一條風控審核記錄、觸發(fā)一個MQ消息通知倉庫。如果先改狀態(tài)再發(fā)消息消息發(fā)送失敗狀態(tài)就漂移了如果先發(fā)消息再改狀態(tài)下游消費者看到的狀態(tài)可能還是舊的。我實際項目中踩過這個坑當時的解法是把狀態(tài)變更和業(yè)務動作放進同一個本地事務表通過事務消息保證最終一致。代碼結構上狀態(tài)機只是控制中樞真正的業(yè)務邏輯在監(jiān)聽器側實現(xiàn)。3.3 并發(fā)場景下的狀態(tài)流轉安全流程設計階段不考慮到并發(fā)系統(tǒng)設計階段就會很難補。訂單系統(tǒng)里最典型的并發(fā)問題用戶點擊退款的同時倉庫完成了出庫。兩個操作同時進行狀態(tài)到底是變成退款中還是已發(fā)貨解決辦法是在狀態(tài)機執(zhí)行層加鎖。實現(xiàn)方式有三種第一種數(shù)據(jù)庫行鎖。在訂單表上執(zhí)行SELECT ... FOR UPDATE拿到鎖之后再判斷當前狀態(tài)是否允許流轉。簡單粗暴流量不大的時候完全夠用。 第二種分布式鎖。用Redis實現(xiàn)鎖定訂單ID作為key。適合訂單服務拆分成多個實例的架構。 第三種CAS更新。更新時帶上當前狀態(tài)作為條件UPDATE order SET status 新狀態(tài) WHERE id ? AND status 舊狀態(tài)受影響行數(shù)為0說明有并發(fā)沖突。我傾向推薦第三種加第一種的組合。CAS輕量且無鎖競爭開銷但受限于只能比較一個舊狀態(tài)如果狀態(tài)機遷移條件復雜比如只有已支付且審核通過才能流轉到待發(fā)貨CAS就沒法直接表達這時候行鎖更可靠。不管選哪種有一個共識必須堅持狀態(tài)流轉必須是有條件的不是無腦賦值。所有入口的狀態(tài)校驗都要做服務內(nèi)部之間調(diào)用也一樣不要信任上游已經(jīng)校驗過。3.4 異步流程與重試機制的取舍流程設計還有一個常見問題哪些環(huán)節(jié)同步執(zhí)行、哪些異步執(zhí)行原則很簡單用戶在請求鏈路上必須等待的結果同步不在關鍵路徑上的動作異步。比如支付回調(diào)之后必須同步更新訂單狀態(tài)并返回成功給支付渠道否則渠道會持續(xù)重試。而通知倉庫這個動作就不該在回調(diào)線程里同步做因為倉庫系統(tǒng)的響應時間不可控如果在回調(diào)線程里同步調(diào)用回調(diào)響應超時會引發(fā)連鎖問題。異步化的實現(xiàn)方式業(yè)界通常使用消息隊列。在這個案例中訂單狀態(tài)更新后發(fā)送一個已支付事件倉庫服務監(jiān)聽事件后開始揀貨。這里有一個細節(jié)消息發(fā)送必須是先更新狀態(tài)事務提交成功后再發(fā)消息。如果事務沒提交就發(fā)了消息下游立馬查到舊狀態(tài)就產(chǎn)生了消息亂序問題。我常用的方案是把消息發(fā)送放進TransactionSynchronization的回調(diào)中事務提交成功后統(tǒng)一發(fā)送。如果發(fā)送失敗本地記錄一條事件發(fā)送日志有定時任務兜底補償。4. 異常處理、監(jiān)控埋點與人工介入設計4.1 流程設計里最容易漏掉的異常分支我問過不少開發(fā)者你們的流程圖畫了異常分支嗎多數(shù)人會說畫了但仔細看就會發(fā)現(xiàn)異常分支只是畫了個失敗箭頭指向一個處理失敗的節(jié)點就完了。這是完全不合格的。異常分支必須要能回答四個問題失敗后能不能重試重試有次數(shù)上限嗎重試失敗之后人工怎么介入人工介入的操作入口落在哪個系統(tǒng)我們用配送超時這個場景舉例。物流接口返回配送超時這是一個異常。簡單的處理是把這個訂單標記為配送異常然后人工介入。但合理的處理應該多一步先判斷訂單類型如果是普通訂單進入自動重試流程重新分配配送資源如果是加急訂單直接轉人工處理。這一步為什么不簡單因為異常處理本身也要走流程它不是一個孤立動作。如果是退款申請中支付渠道退款失敗可能需要自動重試 告警 人工介入三層組合每層都有自己的狀態(tài)流轉規(guī)則。4.2 超時、補償與狀態(tài)回滾的實操設計超時在流程設計中的定義要具體到數(shù)值和動作。拿待支付超時取消舉例訂單創(chuàng)建時間超過30分鐘未支付系統(tǒng)掃描任務發(fā)現(xiàn)后主動取消訂單取消動作執(zhí)行前再校驗一次支付狀態(tài)這里有一個細節(jié)很多人忽略站在某個時間點掃描超時訂單和訂單實際超時之間有時間差。假設掃描任務是每10分鐘執(zhí)行一次某訂單在第31分鐘被掃描到實際它的狀態(tài)是已超時1分鐘。沒問題。但如果用戶在第29分鐘完成了支付第30分鐘掃描任務執(zhí)行它理所當然不應該取消這個訂單。所以掃描任務必須再校驗一次當前狀態(tài)仍是待支付而不是只看是否超過30分鐘。補償邏輯方面訂單取消后如果發(fā)現(xiàn)庫存已經(jīng)預占需要釋放庫存。如果發(fā)現(xiàn)優(yōu)惠券已鎖定需要回滾優(yōu)惠券。這些補償操作不是主流程的一部分但缺了就會出嚴重資損問題。我在項目里專門建了一張compensation_task表記錄所有需要補償?shù)娜蝿找约把a償執(zhí)行狀態(tài)由獨立的任務調(diào)度器驅動確保主流程和補償流程解耦。4.3 監(jiān)控指標與告警閾值怎么定流程設計收尾階段必須把監(jiān)控指標定義出來。很多項目運行半年之后才補監(jiān)控屬于亡羊補牢。每個狀態(tài)節(jié)點至少要有三件事的監(jiān)控第一件流轉量。每個狀態(tài)入口流入的訂單量、出口流出的訂單量要能畫出流量趨勢圖。哪天突然某狀態(tài)入口流量下跌說明上游出了問題。 第二件滯留量。某個狀態(tài)的訂單數(shù)量在時間維度上的堆積情況。待發(fā)貨狀態(tài)堆積超過2小時可能倉庫同步出了問題。 第三件失敗量。每個流轉動作的失敗次數(shù)以及失敗原因分布。告警閾值不要拍腦袋定。先找一段歷史數(shù)據(jù)看基線基線基礎上再定告警閾值。比如正常情況流轉失敗率在0.1%以下那告警閾值可以定在0.5%連續(xù)觸發(fā)5分鐘就報警。閾值太低容易頻繁誤報導致告警疲勞閾值太高會漏掉真正的故障。5. 踩坑實錄那些流程設計不完善引發(fā)的生產(chǎn)事故5.1 案例一狀態(tài)機缺少冪等導致重復退款某個項目上線了退款功能第一天就出問題用戶發(fā)起一次退款申請結果微信支付側打了兩筆退款。查日志一看原因是支付回調(diào)接口被渠道重試了三次每次重試都走了發(fā)起退款的邏輯沒有做冪等校驗。排查結果很清晰流程設計階段支付回調(diào)節(jié)點只畫了驗簽、改狀態(tài)、發(fā)事件沒有畫重復回調(diào)這個分支。系統(tǒng)設計階段也沒有在退款入口處設計冪等表。教訓凡是涉及資金的流程節(jié)點必須默認它是會被重試的。外部系統(tǒng)回調(diào)、內(nèi)部消息重發(fā)、定時任務掃描任何一個環(huán)節(jié)觸發(fā)兩次都不該產(chǎn)生副作用。冪等設計不是狀態(tài)機的一部分但必須在狀態(tài)機旁邊同步考慮。5.2 案例二分支條件過于粗略導致訂單卡死另一個項目退款攔截中狀態(tài)下物流商回調(diào)結果是攔截失敗。開發(fā)人員設計的時候只處理了攔截成功和攔截失敗兩個分支但真實物流商的回調(diào)既不是成功也不是失敗而是處理中。這個處理中狀態(tài)沒有對應分支訂單就卡在退款攔截中一直不動。后來排查定位到是分支遺漏補了一個處理中轉超時監(jiān)控的邏輯。但補這個邏輯的過程很痛苦因為涉及數(shù)據(jù)庫字段變更和存量數(shù)據(jù)的回填。這個案例告訴我們的道理是外部系統(tǒng)的返回值不要想當然認為只有成功和失敗兩種。第三方系統(tǒng)往往有受理中已下發(fā)待確認等各種中間態(tài)流程設計階段必須要能完整識別這些狀態(tài)。5.3 案例三狀態(tài)定義不統(tǒng)一導致跨系統(tǒng)數(shù)據(jù)對不上訂單系統(tǒng)和財務系統(tǒng)對賬出現(xiàn)大量差異。原因是訂單系統(tǒng)的已完成和財務系統(tǒng)的已完成定義不同。訂單系統(tǒng)的已完成指的是用戶簽收財務系統(tǒng)的已完成指的是資金清算完畢。兩個系統(tǒng)之間的狀態(tài)映射關系沒有在流程設計階段對齊對賬全是差異。后來專門梳理了兩個系統(tǒng)的狀態(tài)映射表定義了維度統(tǒng)一的對賬口徑差異才慢慢清零。這個坑的教訓是流程設計不只是在單個系統(tǒng)內(nèi)部設計跨系統(tǒng)協(xié)作時狀態(tài)口徑必須先拉齊。哪里是上游系統(tǒng)的終態(tài)、哪里是下游系統(tǒng)的起始態(tài)邊界必須清楚。6. 實操檢查清單開始編碼前我必過一遍的20條這些檢查項都是實際項目總結出來的分享出來供參考主流程是否覆蓋了從觸發(fā)到終態(tài)的全路徑每個節(jié)點的成功-失敗-超時三個出口是否完整定義狀態(tài)之間是否存在跳轉遺漏是否存在多個動作競爭同一狀態(tài)的并發(fā)場景是否定好了處理策略所有外部系統(tǒng)調(diào)用是否都考慮了冪等所有異步流程是否都有補償機制超時時間是否設定具體數(shù)值并確認業(yè)務可接受每個入口是否做了前置狀態(tài)校驗狀態(tài)變更和數(shù)據(jù)寫入是否在同一事務中消息發(fā)送是否在事務提交之后是否有存量數(shù)據(jù)的狀態(tài)遷移方案跨系統(tǒng)的狀態(tài)映射是否明確人工介入節(jié)點有哪些操作入口是否已定義每個異常分支是否定義可重試次數(shù)和重試間隔是否保留狀態(tài)變更歷史表便于排查和回溯各節(jié)點是否有對應的監(jiān)控看板告警閾值是否基于歷史基線設定狀態(tài)機執(zhí)行失敗時是否記錄上下文信息日常運維操作是否也需要走狀態(tài)機不允許繞過規(guī)則改庫新老流程的灰度切換方案是否提前設計這20條全過完了流程設計才算真正落地。沒有過完就動手寫代碼后面大概率要回頭補課。7. 流程設計工具與文檔沉淀的個人經(jīng)驗流程設計用什么工具不核心但值得說一句。Visio、draw.io、ProcessOn都可以用關鍵是看團隊協(xié)作效率。我習慣用draw.io免費的支持在線協(xié)作存到倉庫里還能做版本管理。但比工具更重要的是文檔規(guī)范化。我每個項目的流程設計文檔固定包含五張圖業(yè)務流程圖、狀態(tài)流轉圖、時序圖、異常分支圖、系統(tǒng)部署交互圖。外加一張狀態(tài)遷移表、一張冪等方案表、一張監(jiān)控指標表。這個結構用熟了之后新同事上手也快。文檔不要一次性寫完流程設計文檔應該是活文檔。每次流程調(diào)整先更新文檔再改代碼。如果代碼改了文檔沒改這個文檔很快就廢掉了。我可以分享一個實際心得畫流程圖的動作本身并不產(chǎn)生價值真正產(chǎn)生價值的是你在畫的過程里被迫把每個分支都想清楚。所以哪怕你手繪在白板上只要問題想透了也一樣有效。我曾經(jīng)帶著團隊不開電腦直接在白板上推演流程用了一下午把一套訂單系統(tǒng)的所有狀態(tài)和分支全部過了一遍后面編碼順暢到不可思議。畫得丑沒關系邏輯閉環(huán)才是重點。8. 關于流程復用與設計規(guī)范的延伸思考處理流程設計積累到一定程度會沉淀出一批可復用的流程模式。比如訂單創(chuàng)建-支付-履約是一個模式審批流轉-執(zhí)行-結果回傳是另一個模式。如果公司內(nèi)部有多個業(yè)務線把這些通用流程抽象成公共模塊或配置化引擎能節(jié)省大量重復設計成本。但做抽象要克制。抽象程度越高學習成本越高。技術團隊在早期階段我更建議先服務好具體業(yè)務把一兩個流程做扎實沉淀出項目自己的最佳實踐再考慮橫向擴展。我所在的項目組后來做了一個輕量級的流程配置引擎把狀態(tài)機規(guī)則、節(jié)點處理邏輯、事件分發(fā)機制統(tǒng)一管理起來。新業(yè)務接入時只需要配置狀態(tài)和轉移規(guī)則再實現(xiàn)少量節(jié)點處理器整個流程就跑起來了。這是流程設計能力沉淀后的自然結果同時也印證了流程設計做到位之后系統(tǒng)設計可以變得非常輕。