
前陣子接手一個項目的維護清單點開一看8臺不同規(guī)格的設備8個平行的PLC程序文件里面大量復制粘貼的痕跡同名變量在8個工程里各編譯各的改一處漏三處的現象嚴重到客戶只敢在零點停機讓我動程序。這個項目讓我下決心做了ST代碼復用架構的重構用一個設備模板FB把8種機型的控制邏輯全部收斂到同一套代碼里。最終程序本體從三四十個FB縮減成核心的1個模板FB外掛幾個工具FB程序量壓縮了接近七成換型維護時改數據、不動邏輯故障定位時間從半小時級降到分鐘級。這篇就把這個一個設備模板FB覆蓋8種機型的完整設計與落地過程拆開講清楚。內容不綁定某個具體PLC品牌按IEC 61131-3的結構化文本ST思路來寫只要你用的平臺支持UDT和功能塊實例化思路可以直接抄作業(yè)。適合正在被多機型、多版本程序折磨的設備廠工程師也適合想從梯形圖思維轉向數據驅動編程的PLC開發(fā)者。1. 多機型程序為什么會失控復制粘貼模式欠下的債1.1 復制粘貼帶來的隱性成本設備廠做多機型項目時最省事的辦法就是拿上一臺的程序改一改。改IO表、改軸參數、改幾個計時器然后編譯下載看起來半天就能交付一臺。但這種模式下欠下的債往往在半年后集中爆發(fā)。我接手的那批8種機型就存在典型的復制漂移問題最早的兩臺設備程序還算同源到第4臺時某個執(zhí)行機構因為硬件改型換了動作方式于是有人在復制出來的程序里把一段邏輯替換掉了第6臺的工程師又在這個基礎上加了配方切換到第8臺程序結構和第1臺已經面目全非。結果就是每臺設備都帶了一套自己的歷史包袱現場報障時對方工程師說你看一下第4臺能不能參考第6臺的處理我只能苦笑——兩套程序的變量命名都完全對不上了。復制粘貼看起來是單臺成本最低的方案但乘以機型數量之后維護成本是疊加而不是累加的。你在1臺設備上做的任何修正都要手工同步到另外7臺漏一臺就是一顆定時炸彈。更麻煩的是不同機型的程序差異到底是參數不同還是邏輯不同在純復制模式下完全不可控到了后期連寫程序的人自己都說不清第5臺為什么比第2臺多了一個中間繼電器。1.2 按機型維護程序版本走不遠的三個原因很多人會說那我不復制每個機型單獨建工程、單獨維護版本不就行了嗎這種做法的第一個問題在于版本爆炸。8種機型就是8份工程每份工程還有自己的修訂歷史現場改了一版、廠里又改了一版、出差臨時又改了一版最后誰的工程最全都沒人知道。第二個問題是交叉bug無法收斂某個通用邏輯比如安全回路、報警處理、手自動切換在第3臺設備上修好了但第7臺還是舊邏輯客戶現場就會再踩一遍同樣的坑而這個坑明明在另一臺設備上已經填平了。第三個問題最致命工程師的人力被死死綁在按機型維護的模式里一旦老員工離職新來接手的工程師面對8套風格可能完全不同的程序光理解就要花幾個月更別說繼續(xù)改。1.3 破局點把設備差異從代碼里抽出去要解決多機型失控核心思路其實一句話讓程序邏輯關注動作怎么做讓數據關注每個機型的具體參數是什么。動作邏輯寫一遍就夠了機型差異全部交給數據去表達。這個思路落到PLC里就是用一個模板FB多個實例化背景數據塊的結構同一份FB代碼喂給不同機型的數據塊跑出不同的控制行為。所謂覆蓋8種機型本質不是8份程序而是1份邏輯8份參數。這也是為什么這篇博文的重心不在某個具體功能怎么寫而在于你怎么設計這套數據和邏輯的邊界——邊界畫對了8種機型是運氣問題后續(xù)再來新機型也只是新增一份數據的問題。2. 設備模板FB的頂層設計邏輯與數據徹底分離2.1 用UDT把機型翻譯成一張數據表ST代碼復用架構里最核心的數據基礎設施是UDT用戶自定義數據類型。你可以把UDT理解成一張機型的空表格里面定義清楚這個設備有哪些參數維度。我的做法是建一個名為TYPE_MachineConfig的UDT字段分成幾個組第一組是身份信息MachineTypeID機型編號、MachineName機型名稱、FirmwareVersion程序版本這些字段主要用于HMI顯示和追溯不參與邏輯判斷。第二組是工藝時間參數CycleTime目標節(jié)拍、HomeTimeout回原點超時、PositionTimeout定位超時、ActionTime壓合/貼裝動作時間所有這些都用REAL或INT類型單位是毫秒放進數據塊里可在線修改。第三組是運動參數AxisCount軸數量、MaxSpeed最大速度、Acceleration加速度、TargetPositions數組多個目標位置的數組這樣個別機型即使有5個定位點也能用同一個數組字段覆蓋。第四組是使能開關HasUnloader是否有下料剔除、HasVisionCheck是否有視覺校驗、HasTaping是否有貼標動作——這類BOOL字段非常關鍵它們是邏輯分支的開關在程序里用IF HasUnloader THEN ...這樣的寫法讓不同機型走不同的子步驟。這張表設計得好不好直接決定了模板FB能覆蓋多少機型。我在第一版設計里把動作時間和是否有某機構混在了一個字段里結果新機型出現時又要加字段、又要改FB非常被動。后來總結出的經驗是凡是你能預見的差異都用字段表達凡是沒把握的差異用擴展字段通用處理兜底不要讓FB代碼因為數據不夠而被迫跟著改。2.2 FB內部只寫動作不寫哪臺機器有了UDT這張表模板FB內部就只做一件事把動作流程按狀態(tài)機一段段跑完每一步需要什么參數統統從VAR_IN_OUT接進來的Config數據塊里取。我在FB_DeviceTemplate里定義了一個整數型狀態(tài)變量用CASE語句描述整臺設備的工藝循環(huán)代碼看起來大致是這樣FUNCTION_BLOCK FB_DeviceTemplate VAR_INPUT Enable : BOOL; // 總使能來自安全回路/手自動切換 bStart : BOOL; // 啟動指令來自HMI按鈕或上位機 bStop : BOOL; // 停止指令緊急停止鏈之外的操作停止 END_VAR VAR_IN_OUT Config : TYPE_MachineConfig; // 機型參數指向實例自己的DB IO : TYPE_IO_Interface; // IO映射接口后面單獨講 END_VAR VAR State : INT : 0; // 工藝狀態(tài)機0IDLE10回原點20抓取30定位40執(zhí)行... bStepDone : BOOL : FALSE; bError : BOOL : FALSE; ErrorCode : INT : 0; StepTimeout : TON; // 每一步的超時計時器 END_VARCASE State OF 0: // IDLE等待啟動 IF Enable AND bStart THEN State : 10; END_IF; 10: // 回原點 IF IO.bHomeSwitch THEN State : 20; ELSIF StepTimeout.Q THEN bError : TRUE; ErrorCode : 101; // 回原點超時 END_IF; 20: // 抓取/取料 IF IO.bGripperDone THEN State : 30; END_IF; 30: // 定位到目標位置 IF ABS(IO.rCurrentPos - Config.TargetPositions[Config.ActiveTargetIndex]) 0.5 THEN State : 40; ELSIF StepTimeout.Q THEN bError : TRUE; ErrorCode : 102; // 定位超時 END_IF; 40: // 執(zhí)行壓合/貼裝/焊接等動作 IF IO.bActionDone THEN State : 50; ELSIF StepTimeout.Q THEN bError : TRUE; ErrorCode : 103; // 動作超時 END_IF; 50: // 可選的下料/剔除步驟僅部分機型啟用 IF Config.HasUnloader THEN IF IO.bUnloaderDone THEN State : 0; // 循環(huán)完成 bStepDone : TRUE; END_IF; ELSE State : 0; bStepDone : TRUE; END_IF; END_CASE;看見沒有FB里面從頭到尾沒有出現過如果是第3臺設備就怎樣、第7臺設備就怎樣的機型編號判斷。所有差異都通過Config里的BOOL開關、數組下標、超時值來體現。這個設計的好處是當你需要修改某個動作順序時你只需要改這一個FB8種機型立刻全部生效不用再一臺一臺同步。缺點也很明顯——任何一次改動影響的范圍從一臺設備變成了全部設備所以后面我會專門講版本管理和測試清單的配合。2.3 為什么這里選ST而不是梯形圖很多工程師習慣用梯形圖寫設備程序寫到多機型時容易順手在里面加幾條機型判斷的比較指令程序很快就變得不可讀。ST在這個場景下的優(yōu)勢不是高大上而是三個非常實際的點第一ST對數據結構友好。UDT、數組、多維數組、結構體嵌套這些操作在ST里就是很自然的字段訪問而在梯形圖里你需要在DB里逐個展開地址寫起來又長又容易錯。第二ST對分支和循環(huán)的表達力強。CASE、IF-ELSIF-ELSE、FOR循環(huán)寫出來邏輯一目了然維護時能直接看到條件和分支的完整關系。第三ST代碼在版本管理工具里可以像普通文本一樣做差異對比。我用任何文本差異工具都能看到這個模板FB前后兩個版本改了什么而梯形圖導出成文本后對比效果很差。ST并不是萬能的比如位邏輯的簡單聯鎖你用梯形圖可能更直觀但當一個FB要承載8種機型的狀態(tài)機時用ST寫狀態(tài)機必然是首選。2.4 IO差異處理見符號不見地址機型差異里最讓人頭疼的是IO數量不一樣、IO分配完全對不上。如果FB里直接寫%I0.5這種絕對地址換個機型程序立刻崩。所以我的IO處理原則是FB不碰任何物理地址全部通過一個叫做TYPE_IO_Interface的UDT作為接口層。這個UDT里定義的是語義化的BOOL量比如bHomeSwitch回原點到位、bGripperDone抓取完成、bActionDone動作完成、bUnloaderDone下料完成以及一個REAL類型的rCurrentPos當前軸位置。在主程序或OB1里每個機型實例化時都有自己的一張IO映射表把物理輸入點映射到這些語義信號上再把物理輸出點映射到動作指令上。簡單說FB和物理IO之間隔了一層翻譯器型號差異被翻譯器消化掉了模板FB永遠只跟語義信號打交道。這個思想跟面向對象里的接口很像PLC界叫符號訪問但真正落地時關鍵不是有沒有符號而是你把物理映射放在哪個層級。我選擇放在上層專門做一個IO_Assign功能塊每個機型一份IO映射邏輯雖然這部分不能完全復用但它的體量比整個FB要小得多而且邏輯簡單純粹出錯的概率也低。3. 落地實操從零搭出一個覆蓋8種機型的模板FB3.1 第一步把8種設備的工藝動作用一張狀態(tài)圖抽象出來不要一開始就寫代碼。我的經驗和習慣是先拿A3紙把所有機型的工藝流程畫出來找到它們的公共骨架。我當時那8種機型都屬于同一類貼裝設備雖然有的機型有視覺校驗有的有自動下料有的有雙工位但不管怎么變主干流程都繞不開準備→回原點→取料→定位→執(zhí)行壓合動作→檢查→放行。于是我把這個主干流程確定為狀態(tài)機的主路徑把那些部分機型才有的步驟設計成側分支。畫這個狀態(tài)圖的過程中最大的爭執(zhí)往往來自這個步驟到底是所有機型都有還是只有某幾臺有。我的判斷標準很簡單如果有一個動作是至少兩臺設備共用并且出現在主流程相同位置我就把它放進主狀態(tài)機如果它只在一臺設備上出現我就把它抽成可選步驟用Config里的BOOL字段控制。這樣既不會讓8種機型共用一個超級臃腫的狀態(tài)機也不會因為個別特例而破壞模板的整體性。3.2 第二步定義UDT和背景DB8種機型的參數差異怎么放公共骨架確定后下一步就是建立TYPE_MachineConfig這個UDT。我先列了一個8種機型差異清單把軸數、目標位數量、動作時間、有無校驗機構、有無下料機構、有無安全門互鎖差異等信息全部列出來然后設計字段。關鍵技巧是數組字段要按最大的機型來定義。比如8種機型里軸數最多的是4軸那么TargetPositions就定義成ARRAY[1..4] OF REAL軸數少的機型只填前幾項其余默認0但邏輯上不參與。這樣FB代碼里不需要根據軸數去動態(tài)改變數組訪問的邊界只要用Config.ActiveTargetIndex來控制使用哪個目標位置即可。建好UDT后我在程序塊里為8種機型分別建立了8個獨立的背景數據塊分別命名為DB_Machine201、DB_Machine202……每個背景塊里的Config字段類型都是TYPE_MachineConfig但實參值互不相同。PLC平臺在生成背景DB時會自動帶上UDT的所有字段我只需要逐個填參數。這一步我必須強調一個坑不要圖省事讓8個實例共用同一個全局數據塊那樣會出現一臺設備改參數、另外7臺也跟著變的事故。獨立的背景DB是隔離的基礎后面你要在線修改任何一臺設備的參數影響范圍都是這一個DB。3.3 第三步模板FB的ST骨架與三個關鍵設計技巧模板FB的骨架就是前面那段CASE狀態(tài)機代碼但真正讓它能穩(wěn)定覆蓋8種機型靠的是三個額外的設計技巧第一個技巧是主使能鏈條。我把總安全繼電器的狀態(tài)、手自動切換狀態(tài)、急停狀態(tài)全部匯總成一個MasterEnable信號從FB外部串進來FB內部第一個CASE周期就會判斷Enable為FALSE時不管當前狀態(tài)在哪一步立刻把輸出全部清零狀態(tài)機凍結。這個保證了不論哪臺機型安全優(yōu)先級永遠最高不會出現因為參數差異導致某些設備在急停后還繼續(xù)動作的情況。第二個技巧是步進超時參數化。傳統做法是給整個程序寫一個固定掃描超時但不同機型的節(jié)拍差別很大有的機型單循環(huán)8秒有的要25秒。我把每一步的超時時間都做成了Config里可配置的TimeoutXx字段調試時根據每臺設備的實際節(jié)拍微調避免誤報警。第三個技巧是錯誤碼統一編碼。ErrorCode的前兩位是步驟號機構號后三位是具體原因比如102定位超時、201抓取失敗。8種機型共用這套編碼HMI報警界面不需要針對每個機型做不同文本映射這又省了一大塊維護量。3.4 第四步在OB1里實例化8次一個模板吃8份數據數據層準備好后程序集成就變得非常樸素在OB1里連續(xù)調用FB_DeviceTemplate八次每次把對應的背景DB包含各自Config和IO映射作為實參傳進去// 在OB1主程序中的調用示意 FB_DeviceTemplate_Instance_201( Enable : MasterEnable, bStart : HMI_Start_201, bStop : HMI_Stop_201, Config : DB_Machine201.Config, IO : DB_Machine201.IO ); FB_DeviceTemplate_Instance_202( Enable : MasterEnable, bStart : HMI_Start_202, bStop : HMI_Stop_202, Config : DB_Machine202.Config, IO : DB_Machine202.IO );這里要注意TIA這類平臺允許同一個FB生成多個實例化調用每個調用自動帶一份獨立的內部變量存儲區(qū)。我的習慣是給8個調用分別命名為Instance_201到Instance_208方便監(jiān)控時一眼看出哪臺設備在哪個狀態(tài)。這一步做完理論上整套系統就已經能跑起來了。我第一次實際下載運行那天8臺設備先后上電第一臺走完一個完整循環(huán)后后面的7臺逐個跑通那種同一份代碼跑出不同動作的感覺確實很爽但也馬上迎來了第二個問題——現場調試時有些怪毛病根本不是程序邏輯錯而是數據填錯了。4. 8種機型到底差在哪數據解決90%邏輯解決10%4.1 用數據就能搞定的差異很多人聽到一個FB覆蓋8種機型會覺得不可思議其實是因為他們把差異都當成了邏輯差異實際上80%到90%的機型差異都只是參數差異。我按實際項目列個清單第一類是時間類差異。不同機型的目標節(jié)拍不同、動作時間不同、等待時間不同這些全部進入Config的REAL字段。第二類是位置類差異。8種機型的幾個定位點完全不同把它們做進TargetPositions數組每個機型填自己的坐標。第三類是數量類差異。軸數、工位數、點位數量不同時用數組和ActiveTargetIndex來控制當前使用哪個。第四類是機構選配差異。某幾臺設備帶下料剔除機構某幾臺帶視覺校驗這些用BOOL開關控制程序只在開關為TRUE時才執(zhí)行對應分支段。第五類是通訊地址和IO分配差異這部分放進IO映射層解決不讓模板FB感知。這里最核心的思路是參數差異的本質是同一種動作的不同數值邏輯差異的本質是動作是否存在或動作順序不同。前者完全不值得用代碼區(qū)分給數據就行后者才需要謹慎設計分支。4.2 必須用邏輯分支處理的例外那10%的邏輯差異是什么樣我項目里的實際例子有兩個。一個是有視覺校驗功能的機型在定位完成后、執(zhí)行動作前要插入一個拍照并等待結果的步驟這個步驟不僅影響狀態(tài)機的走向還涉及視覺信號交互。另一個是雙工位機型會在主流程里多出一個工位切換的并行操作。處理這些例外時我沒有把它們從模板FB里剝出去而是讓它們在狀態(tài)機里以可選步驟的方式存在。以視覺校驗為例我在狀態(tài)機里保留了一個標記為校驗站的狀態(tài)節(jié)點State35前面用IF Config.HasVisionCheck THEN引導進入否則跳過。這樣模板FB仍然是唯一的主邏輯載體例外動作只是這條主線上的旁支。這個方法的前提是例外數量可控如果一個FB里插了七八個例外分支狀態(tài)機會變得沒人能看懂那時候就要考慮拆成基礎模板FB擴展功能FB的組合結構了。4.3 一張表看清楚8種機型的差異歸屬我把當時整理的差異歸屬表簡化后放在這里方便大家參考這個分析的粒度機型代號軸數量目標位數量有無視覺校驗有無下料剔除有無雙工位節(jié)拍目標差異歸屬M20122無無無8s數據M20223有無無12s數據邏輯視覺M20334無有無10s數據邏輯下料M20434有有無15s數據邏輯視覺下料M20546無有有20s數據邏輯下料雙工位M20646有有有25s數據邏輯全選配M20722無無無8s數據與M201同一模板M20835有無有18s數據邏輯視覺雙工位這張表是我和團隊討論了兩輪才定下來的。定完之后我就能精確告訴客戶和同事哪幾臺的差異只需要填數據哪幾臺需要多寫一小段可選邏輯新增機型時也照這個思路先做差異歸屬分析再決定要不要動FB。5. 換型調試現場填錯數據比寫錯程序更常見5.1 一次IO映射錯誤引發(fā)的誤動作排查全過程模板FB跑通以后現場調試的主要矛盾就從寫邏輯變成了填數據、配映射。我記得調試第5臺雙工位機型時出現了間歇性誤啟動有時候按下啟動按鈕設備不動有時候剛完成一次循環(huán)又自動觸發(fā)第二次。第一反應以為是狀態(tài)機復位邏輯有問題查了半小時代碼沒查出異常。后來打開IO映射導出的表格一比對發(fā)現該機型背景DB里的bUnloaderDone下料完成信號被映射到了某個物理輸入點而那個輸入點實際上接的是安全門到位信號。下料機構還沒動安全門一關程序就以為下料完成了于是狀態(tài)機提前放行緊接著又啟動下一循環(huán)。這類問題的根源在于模板FB把物理IO藏起來了人機界面看到的全是語義信號一旦物理點位重新分配或接線調整映射表必須人工同步。建議是每次換型接線后先做一次信號強制測試——把每個輸入點逐個強制核對HMI監(jiān)控畫面上的語義信號是否跟著變化全部對上號再跑自動流程。這個步驟看起來土但對排查這類數據錯誤非常高效。5.2 在線修改、熱下載與庫更新的坑多機型模板FB有一個隱形的管理難題你改了模板FB8個實例會同時變但理論上是同時變實際下載時PLC可不一定允許你一次全刷下來。在線修改和熱下載在不同平臺有不同限制有些情況下你改了變量表或背景DB的數據類型就需要停機下載全量程序而不能后臺熱更新。我在項目中碰到過一次現場正在生產我想給模板FB加一個報警提示字段結果這個字段的修改牽動了背景DB的結構PLC提示無法在線修改需要初始下載。那天的經驗讓我明白涉及數據結構變更的改動必須提前計劃停機窗口別指望所有優(yōu)化都能在線熱更新。另一個經驗是庫更新傳播。如果你把模板FB做成了可復用的庫元件每次改完庫后所有項目的引用不會自動更新需要手動執(zhí)行更新庫元件版本的操作。我見過有同事改了庫元件忘了同步導致8臺設備有5臺在用新邏輯、3臺還在跑舊邏輯。所以我的管理習慣是庫元件每次修改都記錄版本號項目里統一在發(fā)布前檢查引用版本現場版本不一致時用程序頭部的FirmwareVersion字段做對比一眼就能看出哪臺固件落后了。5.3 8個實例同時工作的掃描周期壓力實測有人會擔心一個FB被調用8次CPU掃描周期會不會扛不住。實際測下來純邏輯指令的負載非常小ST的CASE狀態(tài)機和IF判斷在PLC里都是布爾和整數運算8個實例加一起也就幾百條指令現代CPU完全無壓力。真正的壓力來自兩個地方一是背景DB的數據量大如果UDT里塞了幾百個REAL數組字段8個DB加起來內存占用可觀但PLC內存通常也不是瓶頸二是如果有通訊指令比如和視覺、機器人通訊每個實例都收發(fā)數據時通訊處理時間可能遠超邏輯掃描時間。這種情況我建議把通訊從模板FB里摘出去單獨用通訊管理塊模板FB只讀取已經更新好的通訊結果避免一個FB又要跑工藝又要等通訊導致的時序混亂。5.4 規(guī)范化調試的幾條清單經歷了這一輪8機型的調試我沉淀了一套調試前檢查清單核心幾條是先核對IO映射表與端子接線圖再核對8份背景DB的參數是不是按不同機型的銘牌填寫接著做一次所有輸入信號的強制測試然后手動單步走一遍每個機型的狀態(tài)機最后才能允許自動循環(huán)。這套清單在第一次跑通后我反復用了好幾輪每次都能在正式啟動前揪出至少一兩個參數填錯的問題比到時候停機強太多。6. 再往前走一步從機種模板到平臺化維護6.1 新增一種機型代碼要改幾處這是評估這套架構最直接的試金石。在我這套方案里新增一種機型需要改動的代碼量基本是零要做的事只有三件第一在HMI或全局配置里增加一個機型編號第二復制一份背景DB并改成新機型名第三把新機型的工藝參數和IO映射填進去。如果新機型帶有全新的選配機構還需要在模板FB里加一個可選步驟分支但這種情況通常是少數。換句話說一個FB覆蓋8種機型不是一個終點它更大價值在于新機型開局只需要處理數據不需要動邏輯這對設備廠快速響應新需求的意義非常實際。6.2 用配方表批量生成實例DB的參數當機型數量繼續(xù)增長到十幾、二十臺時人工填DB參數不僅費時還容易錯。我的做法是把TYPE_MachineConfig的字段做成一張Excel配方表用工程腳本把表格內容自動生成PLC數據塊的初始化文件或者導入到配方變量里。這樣新機型到達時工藝工程師在Excel里做完參數生成配置文件我再導入工程背景DB的初始值和配方就全部就位。這個流程的重點是Excel的列頭必須和UDT字段名完全對齊否則腳本轉換時報錯后你得一條條查反而比手工填更慢。6.3 報警、HMI畫面和MES接口的聯動復用模板FB幫我們把控制邏輯收斂了報警、HMI畫面和MES通訊也應該跟著復用。我的做法是讓模板FB輸出一個統一的MachineStatus結構體里面包含當前狀態(tài)編號、當前步驟編號、錯誤碼、運行計數等HMI畫面讀取這個結構體不同機型共用同一張主畫面只是底層的DB實例不同。MES接口也類似上位機只需要和統一的DB結構打交道不必關心當前連的是哪臺機器。這個結構體接口的思路和前面IO接口層的思路是一脈相承的定義好契約內部差異再大也不影響外部交互。6.4 個人維護這個庫兩年的三點體會前陣子我又把這兩年的維護記錄翻了一遍最想分享的體會是模板FB不是一上來就要設計得完美無缺而是先用一個合理的骨架圈住80%的共性然后在每個新機型到來時小步演進。我第一版只覆蓋了3種機型過程里發(fā)現選配機構開關這個設計后才逐步擴展成覆蓋8種。二是每次改動模板FB都必須全量回歸測試哪怕只是加一個字段也要把8臺設備的典型流程各跑一遍我建議把這一步寫進項目流程。三是模板FB的價值要到第二、第三個項目才能真正體現同一套架構如果只服務一個項目前期投入可能不劃算但一旦你面對的是持續(xù)交付的機型族這套架構就是降低維護成本的真正杠桿。