第三章 系统架构规划:货架系统整体架构设计、模块划分原则、接口定义规范
做货架系统这么多年,我最大的体会是:架构设计决定了项目成败的80%。很多团队一上来就画图纸、算承重,结果做到一半发现模块之间打架,接口对不上,返工成本高得吓人。
我个人习惯,拿到需求后先花一周时间做架构规划。别急着动手,想清楚了再干,反而更快。
3.1 整体架构设计:从顶层到底层
货架系统说白了就是一个承载-存取-管理的闭环。我把它分成三个层次:
| 层级 | 核心功能 | 典型组件 |
|---|---|---|
| 应用层 | 人机交互、业务逻辑 | WMS接口、扫码终端、看板系统 |
| 控制层 | 设备调度、状态监控 | PLC控制器、传感器网络、电机驱动 |
| 执行层 | 物理承载、机械动作 | 立柱、横梁、导轨、货叉 |
你想想看,如果应用层直接去控制电机,那代码得多乱?我在项目中遇到过一家工厂,他们把扫码逻辑写进了PLC程序里,结果每次换产品型号都要改底层代码,维护成本直接翻倍。
3.2 模块划分原则:高内聚、低耦合
模块怎么切?我总结了四个字:职责单一。每个模块只做一件事,并且做好。
举个例子,一个典型的货架系统可以拆成这些模块:
- 货位管理模块:负责货位的分配、释放、状态维护
- 存取调度模块:负责任务排队、路径规划、冲突解决
- 设备控制模块:负责电机启停、传感器读取、异常处理
- 数据同步模块:负责与上层WMS/ERP的数据交换
- 安全监控模块:负责超载检测、防撞保护、急停逻辑
嗯,这里要注意:不要为了复用而过度拆分。我曾经把一个货位管理模块拆成了「货位分配」和「货位释放」两个子模块,结果发现它们共享了80%的代码逻辑,反而增加了接口复杂度。后来我学乖了,模块粒度以「一个人能独立维护」为标准。
3.3 接口定义规范:稳定、清晰、可扩展
接口是模块之间的契约。契约定好了,各干各的,互不干扰。
我习惯用RESTful风格来定义接口,虽然货架系统是嵌入式环境,但接口设计的思想是通用的。
举个例子,存取调度模块对外暴露的接口:
// 请求格式
{
"taskId": "TASK_20240301_001",
"type": "store", // store: 入库, retrieve: 出库
"sku": "SKU_A001",
"quantity": 10,
"priority": 1 // 1-5, 1最高
}
// 响应格式
{
"taskId": "TASK_20240301_001",
"status": "accepted", // accepted, queued, rejected
"estimatedTime": 12.5, // 秒
"location": "A-03-12" // 分配的货位
}
为什么要定义得这么细?因为接口一旦发布,改起来就是牵一发动全身。我在项目中遇到过最惨的一次,是接口返回的字段名从「location」改成了「binLocation」,结果下游三个系统全部要改,光联调就花了两周。
3.4 接口设计的三个关键点
第一,接口要幂等。同一个请求发两次,结果应该一样。比如入库任务,如果第一次成功了,第二次再发应该返回「已存在」而不是再执行一次。否则,网络重试时就会出大问题。
第二,接口要异步。货架系统的操作通常需要几秒到几十秒,不能阻塞调用方。我习惯的做法是:接口立即返回一个taskId,然后通过回调或轮询获取结果。
第三,接口要容错。输入参数校验要严格,但返回信息要友好。比如「quantity不能为负数」比「参数错误」有用得多。
| 接口属性 | 要求 | 反例 |
|---|---|---|
| 幂等性 | 重复请求不产生副作用 | 重复入库导致库存翻倍 |
| 异步性 | 立即返回,不阻塞 | 接口等待10秒才返回 |
| 容错性 | 输入校验+友好提示 | 直接抛500错误 |
3.5 架构文档:写清楚,更要画清楚
光有代码不够,文档必须跟上。我要求团队必须输出三张图:
- 架构总览图:展示所有模块和它们之间的依赖关系
- 时序图:展示一个典型任务的完整流程,比如「入库任务从WMS下发到货叉动作」
- 接口清单表:列出所有接口的URL、请求格式、响应格式、错误码
文档不是写给别人看的,是写给自己看的。三个月后你回头改代码,没有文档,你连自己写的接口都记不清。
下一章,我会讲货架系统的结构力学计算,那是真正考验数学功底的地方。到时候我会分享一个我踩过的坑——立柱截面选小了,结果货架装到一半发现变形了...嗯,那真是血的教训。