当前位置: 首页 > news >正文

【从零开始学架构】状态机不是增加架构复杂度,而是停止猜测

复杂流程最容易变乱的地方,不是代码一开始写错了,而是状态被一点点藏起来了。

一开始,流程可能很简单。一个请求进来,做解析,做校验,生成结果。几个if就够了。

后来业务开始变化:有些情况要重试,有些情况要等用户确认,有些情况要从上一轮继续,有些情况不能继续但也不能直接失败。于是代码里慢慢出现了很多字段:

resolved pending retryCount currentIndex snapshot answerJson ambiguous hasMore

每个字段单独看都合理。但问题是,真正的业务状态不在任何一个字段里,而在这些字段的组合里。

维护者想知道“系统现在到底在哪里”,必须在脑子里同时拼出一组判断:

snapshot != null answerJson != null resolved == false ambiguous == true currentIndex < total retryCount < 1

这时,流程已经不是靠代码表达了,而是靠人脑临时还原。

这就是复杂流程变乱的起点。

架构的目标,是减少脑内状态

很多人把架构理解成“增加层次”。但真正有价值的架构,不是层越多越好,而是让系统更容易被理解、验证和修改。

如果一个改动要求维护者同时记住:

当前字段 历史快照 前端回答 当前下标 重试次数 是否 pending 是否 resolved 是否 ambiguous

那系统复杂度就已经压在人身上了。

状态机的意义,是把这些负担从人脑里拿出来,放回系统表达里。

好的状态机不一定复杂。它可能只是几个状态名,一张转移表,几个 helper 方法。

但它能让团队快速回答三个问题:

我现在在哪里? 我为什么来到这里? 我接下来能去哪里?

能回答这三个问题,流程就不再只是代码的堆叠,而开始有了架构。

所以,状态机不是架构炫技。

它是一种克制的整理方式:当流程已经复杂到需要人脑猜测时,把状态命名出来,把转移写清楚,把隐含秩序显性化。

真正的架构不是增加层,而是减少维护者必须在脑子里同时保存的隐含状态。

一、流程变乱,是因为状态被藏起来了

很多系统并不是没有状态,而是状态没有名字。

比如一个流程里出现了这些判断:

如果有历史快照,就恢复上下文 如果有用户回答,就合并答案 如果还有未处理项,就继续推进 如果发现歧义,就返回前端 如果已经解决,就跳过当前链路

这些判断背后其实已经有状态:

正在恢复 正在处理 等待用户 继续推进 已经完成

但如果代码里没有这些名字,维护者看到的就只是零散字段和分支。

这会带来一个很大的问题:每一次维护,都要重新推理一遍流程。

改一个 bug 时,要先弄清楚:

这个 resolved 是本轮解决,还是上一轮解决? 这个 pending 是等用户,还是等自动修复? 这个 index 指当前项,还是下一项? 这个 snapshot 是输入协议,还是内部机器态?

当这些问题不能被代码直接回答时,系统就开始依赖“熟人知识”。

老同学知道哪里不能动,新同学只能小心试。架构的负担没有消失,只是转移到了人的脑子里。

二、状态机,就是让状态显性化

状态机的本质很简单:

当前在哪里 + 遇到什么事 + 接下来去哪

也可以写成:

state + event -> next state

它不是一个框架,也不是一种复杂设计模式。它首先是一种表达方式。

例如,一个复杂流程可以从零散字段,翻译成这些明确状态:

PARSING 正在解析 PROCESSING 正在处理 WAITING_USER 等待用户输入 RESUMING 正在从用户回答恢复 RETRYING 正在重试 RESOLVED 已完成 BLOCKED 已阻断

一旦状态有了名字,很多问题就变简单了。

之前维护者要问:

为什么 resolved=false,但又没有继续执行? 为什么有 snapshot,还重新解析了? 为什么用户回答了,还是继续澄清?

现在可以问:

当前是不是 WAITING_USER? 收到 ANSWER_RECEIVED 后,是否应该进入 RESUMING? RESUMING 完成后,应该回到 PROCESSING,还是直接 RESOLVED?

这就是状态机最大的价值:它把隐含流程变成可讨论的业务语言。

状态机不是让代码多一层,而是让维护者少猜一层。

三、能暂停、能恢复、要记住位置,就是状态机

不是所有流程都需要状态机。

一个简单函数,输入参数,返回结果,中间没有暂停、没有恢复、没有跨请求上下文,那不需要状态机。硬加状态,只会增加复杂度。

但如果一个流程满足三个条件,就应该用状态机视角去看它。

  • 第一,它会暂停。比如系统处理到一半,发现信息不够,需要等用户确认;或者要等人工审核;或者要等外部系统回调。

  • 第二,它会恢复。用户回答后,系统不是重新走一个全新流程,而是要接上之前停住的地方继续。

  • 第三,它要记住位置。恢复时,系统必须知道之前处理到哪里了,当前项是什么,哪些已经解决,哪些还没解决。

这三个条件合起来,就是典型状态机:

能暂停 能恢复 要记住上次停在哪里

这类流程如果没有显式状态,最后一定会用各种字段拼出来:

snapshot 表示暂停现场 currentIndex 表示处理位置 pending 表示等待输入 answerJson 表示恢复事件 resolved 表示是否完成

字段越来越多,状态越来越隐蔽。

所以判断一个流程需不需要状态机,不要先问“要不要引入状态机框架”,而要问:

它是不是已经在用字段模拟状态机?

如果答案是肯定的,架构问题就不在于是否增加抽象,而在于是否应该把这些隐形状态命名出来。

四、不引框架,先命名状态和转移

Ponytail 的思路不是上来重写,也不是上来引框架。

它会先问:第一个能解决问题的台阶是什么?

面对混乱流程,第一个台阶通常不是新框架,而是命名。

先命名状态:

PARSING PROCESSING_ITEM WAITING_USER_INPUT RESUMING_FROM_ANSWER RESOLVED BLOCKED

再命名事件:

PARSE_SUCCESS ITEM_OK AMBIGUITY_FOUND ANSWER_RECEIVED NO_MORE_ITEMS UNRECOVERABLE_ERROR

然后写清楚转移:

PARSING + PARSE_SUCCESS -> PROCESSING_ITEM PROCESSING_ITEM + ITEM_OK -> PROCESSING_ITEM PROCESSING_ITEM + AMBIGUITY_FOUND -> WAITING_USER_INPUT WAITING_USER_INPUT + ANSWER_RECEIVED -> RESUMING_FROM_ANSWER RESUMING_FROM_ANSWER + ANSWER_MERGED -> PROCESSING_ITEM PROCESSING_ITEM + NO_MORE_ITEMS -> RESOLVED PROCESSING_ITEM + UNRECOVERABLE_ERROR -> BLOCKED

做到这里,很多时候已经够了。

代码不一定马上拆成很多类,也不一定需要一个状态机引擎。只要状态、事件、转移被显式表达,维护者就能知道系统此刻在哪里。

下一步才是收口判断。

把散落在各处的字段组合:

snapshot!=null&&answerJson!=null&&!resolved

收口成一个业务方法:

isResumingFromAnswer()

把字符串判断:

resultJson.contains("\"ambiguous\":true")

收口成:

hasPendingClarification()

把下标判断:

currentIndex<items.size()

收口成:

hasMoreItems()

这就是最小改造。

不改变业务结果,不大拆结构,不急着抽象,只是让原本藏在脑子里的状态进入代码。

http://www.jsqmd.com/news/1093373/

相关文章:

  • 私域直播SaaS大乱斗:小鹅通、微赞、有赞、悦邻,到底谁更适合“卖菜”的?
  • 将 Rust 绑定到 .NET 10:Oxigraph 的 FFI 桥接实践
  • 【毕业设计】基于 SpringBoot 的文章发布与评论互动博客系统 个人博文编辑、分类与归档管理系统设计与实现(源码+文档+远程调试,全bao定制等)
  • 第11章:对话管理与会话持久化
  • 国内智慧交通数字孪生头部企业汇总,一站式建设方案对比推荐
  • 盯盘与研究辅助AI工具选择与流程适配指南
  • 2026 珠三角磁吸手机支架转轴源头厂家盘点|5 家实体工厂选型指南
  • Rust的Send与Sync:理解线程安全标记trait
  • Prisma安装使用
  • 从0到1:企业级AI项目迭代日记 Vol.56|每一个“差点能用”,都是一次真实的用户流失
  • 用AI自动提取小红书抖音脚本文案,同步Obsidian素材库
  • 162.乐理进阶:和声大调与旋律大调的实战应用与听觉辨识
  • 告别传统写作繁琐流程:gradpaper 的全流程辅助模式新在哪?
  • 拒绝玄学调参!开发者必修的 Prompt Engineering 十二式核心心法
  • 5分钟免费实现VR视频转2D播放的终极方案
  • Lemo-AI vs 顶尖产品:记忆驱动的智能革命
  • GPT-5.6发布前被叫停
  • MSPM0 DEBUGSS调试子系统:从SWD接口到功耗分析与安全控制
  • 海洋定点长期流速观测该选用哪款单点海流计?偶信告诉你答案
  • AI大模型就业:实践笔记 93
  • 密码学系列之流密码RSAECC等
  • NET 代码保护实战:从混淆到虚拟机保护
  • 【课程设计/毕业设计】基于 SpringBoot 的博客点赞收藏与数据统计系统 校园知识分享博客管理系统的设计与实现【附源码、数据库、万字文档】
  • Java毕业设计-基于 Web 的网络域名管理系统的设计与实现 基于 Web 架构的域名信息管理系统设计与开发(源码+LW+部署文档+全bao+远程调试+代码讲解等)
  • 【通信原理笔记】【三】模拟信号调制——3.3 包络调制(AM):从数学原理到工程权衡
  • 【排故】Linux 镜像恢复 VNC 黑屏卡死:NFS 开机挂载阻塞故障完整排障
  • all-MiniLM-L6-v2 完整详解
  • Windows风扇智能控制终极指南:如何用FanControl告别噪音与过热
  • 零代码玩转AI自动化:EasyClaw全流程实操指南(安装部署+多平台互联+Agent调教)
  • Java计算机毕设之基于 SpringBoot 的极简个人创作博客平台设计与实现 自媒体轻量化博客运维管理系统设计与实现(完整前后端代码+说明文档+LW,调试定制等)