工业制造领域 AAA 架构落地指南:分层设计、系统集成、代码示例与避坑实践
文章目录
- 工业制造领域 AAA 架构落地指南:分层设计、系统集成、代码示例与避坑实践
- 一、工业制造里的 AAA 架构,到底指什么
- 二、先看一个工业制造典型场景:报工流程
- 三、AAA 分层在报工场景中的职责划分
- 四、在工业制造系统中,AAA 的模块拆分方式
- 五、MES、ERP、SCADA、WMS 在 AAA 架构中的位置
- 六、AAA 架构下如何处理设备接入
- 七、和 DDD 的关系:AAA 是否等于 DDD
- 八、AAA 架构的优点:工程实践角度看
- 九、AAA 架构的缺点:落地时的真实成本
- 十、最容易踩的坑
- 十一、如何避免 AAA 架构用得过重
- 十二、一个推荐的“轻量 AAA”实施路线
- 十三、一个判断标准:你的 AAA 是否做对了
- 十四、结语
工业制造领域 AAA 架构落地指南:分层设计、系统集成、代码示例与避坑实践
在工业制造系统建设中,团队经常会遇到三类典型问题:
- 业务复杂:工单、工艺、报工、质量、批次追溯、设备联动,规则很多
- 集成复杂:MES 要连 ERP、WMS、QMS、SCADA、设备采集平台
- 变化频繁:设备会换、接口会改、流程会调、工厂之间还不完全一样
如果没有清晰的架构边界,系统很容易在一年后变成这样:
- 业务规则散落在 Controller、SQL、存储过程、定时任务里
- ERP、WMS、SCADA 的调用逻辑到处复制
- 同一套“报工规则”在 5 个地方各写一份
- 现场联调时改了一个接口,影响一大片
- 新人接手几乎无从下手
为了解决这类问题,很多制造企业会引入 AAA 架构。
但问题也随之而来:知道 AAA 是什么,不代表知道怎么落地。
这篇文章不谈空泛概念,重点讲工程实践:
- 工业制造里的 AAA 架构到底怎么理解
- 在 MES/ERP/SCADA 场景里怎么拆模块
- 代码层面如何分层
- 适合哪些场景、不适合哪些场景
- 怎样避免分层过重、抽象失控
一、工业制造里的 AAA 架构,到底指什么
在工程落地里,我更建议把 AAA 理解为下面三层:
- A1:Application Layer(应用层)
- A2:Abstraction / Domain Layer(抽象/领域层)
- A3:Adapter / Access Layer(适配/接入层)
不同公司命名会不同,但核心目的基本一致:
把“业务流程编排”“核心制造规则”“外部系统与设备接入”拆开。
这样做的核心收益是:
当业务变更时,不要改一堆设备接入代码;
当设备协议变化时,不要改一堆工单逻辑;
当外围系统接口变化时,不要把整个 MES 都拖着改。
二、先看一个工业制造典型场景:报工流程
以“工单工序报工”为例,这是 MES 中非常典型的一条主链路。
一个报工动作,实际可能涉及:
- 校验工单状态是否允许报工
- 校验当前工序是否已开工
- 获取设备当前运行状态
- 记录产量、良品数、不良数
- 更新在制品数量
- 同步 ERP 完工数据
- 同步 WMS 入库申请
- 触发 QMS 首检或终检
- 发送产线事件到实时看板
如果这些逻辑全部写在一个 service 里,短期看很快,长期必炸。
三、AAA 分层在报工场景中的职责划分
1. 应用层:负责编排“这次报工要做哪些事”
应用层关注的是 流程,不是细节。
它主要做这些事:
- 接收 API 请求 / 消息 / 调度任务
- 解析请求参数
- 做权限和身份校验
- 调用领域服务完成报工
- 组织事务边界
- 调用外围系统同步逻辑
- 记录审计日志
- 返回结果
它更像“用例协调器”。
例子:应用层伪代码
public class ReportWorkApplicationService {
private final WorkOrderDomainService workOrderDomainService;
private final ProductionExecutionRepository productionExecutionRepository;
private final ErpReportAdapter erpReportAdapter;
private final WmsInboundAdapter wmsInboundAdapter;
private final EventPublisher eventPublisher;
public ReportWorkResult report(ReportWorkCommand command) {
// 1. 查询工单和工序
WorkOrder workOrder = workOrderDomainService.loadWorkOrder(command.getWorkOrderId());
// 2. 执行领域规则
ProductionExecution execution = workOrderDomainService.reportWork(
workOrder,
command.getOperationId(),
command.getGoodQty(),
command.getDefectQty(),
command.getOperatorId()
);
// 3. 持久化执行记录
productionExecutionRepository.save(execution);
// 4. 同步外围系统
erpReportAdapter.syncCompletion(execution);
wmsInboundAdapter.createInboundRequest(execution);
// 5. 发布业务事件
eventPublisher.publish(new WorkReportedEvent(execution.getExecutionId()));
return ReportWorkResult.success(execution.getExecutionId());
}
}
这里要注意什么
应用层不应该:
- 直接写复杂业务规则
- 直接拼设备协议
- 直接写很多 SQL 细节
- 直接解析 ERP 返回格式
否则它会迅速膨胀成“大总管层”。
2. 抽象/领域层:负责制造规则和核心业务语义
这一层是 AAA 是否有价值的关键。
领域层关注的是:
- 什么情况下允许报工
- 报工后状态如何变化
- 良品、不良品、在制品如何计算
- 是否需要触发首检/终检
- 是否满足工艺顺序约束
- 某个设备事件如何影响工单状态
这里沉淀的是 制造业务里稳定、可复用、跨场景存在的规则。
例子:领域层伪代码
public class WorkOrderDomainService {
public WorkOrder loadWorkOrder(String workOrderId) {
// 从 repository 取聚合
return repository.findById(workOrderId);
}
public ProductionExecution reportWork(
WorkOrder workOrder,
String operationId,
int goodQty,
int defectQty,
String operatorId
) {
// 1. 状态校验
if (!workOrder.canReport(operationId)) {
throw new BusinessException("当前工序不允许报工");
}
// 2. 数量校验
if (goodQty < 0 || defectQty < 0) {
throw new BusinessException("报工数量非法");
}
// 3. 执行工单领域行为
workOrder.report(operationId, goodQty, defectQty);
// 4. 生成执行记录
return ProductionExecution.create(
workOrder.getId(),
operationId,
goodQty,
defectQty,
operatorId,
LocalDateTime.now()
);
}
}
这一层不要做成什么样
不要把领域层做成纯转发:
public void report(...) {
repository.report(...);
}
如果没有业务规则、没有行为、没有语义,仅仅是转发,那这层基本没有存在意义。
3. 适配/接入层:负责吃掉外部差异
工业制造系统最大的问题之一就是外部世界太乱:
- ERP 是 SOAP
- WMS 是 REST
- SCADA 是 OPC UA
- 某台设备是 TCP Socket
- 另一台设备走厂商 SDK
- 第三方系统还要文件交换
适配层的价值就是:
把这些差异封装起来,对内提供稳定接口。
适配层的典型职责
- ERP 接口适配
- WMS 接口适配
- QMS 接口适配
- SCADA/设备采集平台接口适配
- 数据库访问
- 消息队列收发
- 文件导入导出
- 协议转换
- 外部错误码转换
例子:ERP 适配器
public class ErpReportAdapter {
private final ErpApiClient erpApiClient;
public void syncCompletion(ProductionExecution execution) {
ErpCompletionRequest request = new ErpCompletionRequest();
request.setOrderNo(execution.getWorkOrderId());
request.setOperationNo(execution.getOperationId());
request.setGoodQty(execution.getGoodQty());
request.setDefectQty(execution.getDefectQty());
ErpResponse response = erpApiClient.reportCompletion(request);
if (!response.isSuccess()) {
throw new IntegrationException("ERP报工同步失败: " + response.getMessage());
}
}
}
设备适配器示例
public class PlcDeviceStatusAdapter {
private final PlcClient plcClient;
public DeviceStatus readStatus(String deviceCode) {
PlcRawData rawData = plcClient.read(deviceCode);
return DeviceStatus.builder()
.deviceCode(deviceCode)
.running(rawData.getSignal("RUN") == 1)
.alarm(rawData.getSignal("ALARM") == 1)
.stop(rawData.getSignal("STOP") == 1)
.timestamp(LocalDateTime.now())
.build();
}
}
适配层的重点
适配层不是简单“包一层 client”,它还要负责:
- 字段映射
- 错误码转换
- 重试策略
- 限流/超时/熔断
- 日志记录
- 幂等控制
- 接口版本兼容
四、在工业制造系统中,AAA 的模块拆分方式
下面给出一个更贴近 MES 场景的模块图思路。
1. 业务模块视角
典型模块可拆成:
- 工单管理
- 工艺路线管理
- 生产执行
- 报工管理
- 质量管理
- 设备状态管理
- 物料与批次追溯
- 仓储协同
- 数据采集与事件中心
2. 架构层次视角
可以按照下面方式组织:
应用层
workorder-appproduction-appquality-apptrace-app
领域/抽象层
workorder-domainproduction-domainquality-domainequipment-domain
适配层
erp-adapterwms-adapterqms-adapterscada-adapterplc-adapterrepository-implmq-adapter
接口层
rest-apijob-schedulermessage-consumer
基础设施层
common-logcommon-eventcommon-authcommon-idempotent
3. 一个推荐的目录结构示例
manufacturing-system/
├── api
│ ├── controller
│ ├── dto
│ └── response
├── application
│ ├── service
│ ├── command
│ ├── query
│ └── assembler
├── domain
│ ├── workorder
│ │ ├── entity
│ │ ├── valueobject
│ │ ├── service
│ │ └── repository
│ ├── production
│ ├── quality
│ └── equipment
├── adapter
│ ├── erp
│ ├── wms
│ ├── qms
│ ├── scada
│ ├── device
│ └── persistence
├── infrastructure
│ ├── config
│ ├── mq
│ ├── lock
│ ├── log
│ └── utils
└── test
这个结构不是唯一标准,但它能比较清楚地体现职责边界。
五、MES、ERP、SCADA、WMS 在 AAA 架构中的位置
这是工业项目里最容易讲空的地方,必须结合实际系统说。
1. MES 在哪里
MES 通常是业务核心,主要承载:
- 工单执行
- 工序控制
- 报工
- 生产过程追踪
- 异常处理
- 质量联动
在 AAA 中,MES 的核心规则大多落在:
- 应用层
- 领域/抽象层
2. ERP 在哪里
ERP 通常提供:
- 主数据
- 生产订单来源
- BOM / 工艺基础数据
- 财务与成本归集
- 完工反馈
- 库存主账
在 AAA 中,ERP 一般位于:
- 适配层外部系统
- 通过
erp-adapter接入
也就是说,ERP 不应该直接侵入 MES 业务代码。
MES 应该依赖自己的内部模型,由适配层完成 ERP 字段映射。
3. SCADA / 设备采集平台 在哪里
SCADA 或采集平台负责:
- 采集设备信号
- 上报状态、告警、参数
- 提供实时监控数据
在 AAA 中,它通常位于:
- 适配层
- 或作为适配层依赖的外部采集通道
例如:
- PLC 原始点位 -> 设备状态对象
- 告警信号 -> 设备异常事件
- 产量计数器 -> 自动报工原始数据
4. WMS 在哪里
WMS 常负责:
- 入库
- 出库
- 库位
- 批次库存
- 物料搬运协同
在 AAA 中,WMS 一般也是适配层集成对象。
MES 在业务完成某个动作后,通过适配器触发:
- 完工入库申请
- 线边仓补料请求
- 在制品转运通知
5. 一个简化的数据流转图
[前端/终端]
|
v
[应用层 Application]
|
v
[领域层 Domain/Abstraction]
|
+-------------------+
| |
v v
[持久化适配] [外部系统适配]
| |
v +----> ERP
Database +----> WMS
+----> QMS
+----> SCADA
+----> Device/PLC
六、AAA 架构下如何处理设备接入
工业制造和普通企业软件的一个核心区别,就是设备接入占比高。
如果设备接入不隔离好,业务代码会迅速变脏。
1. 不要让业务层直接理解 PLC 点位
错误示例:
if (plc.read("M001.RUN") == 1 && plc.read("M001.ALARM") == 0) {
// 允许开工
}
这样写的问题是:
- PLC 地址直接进入业务代码
- 换设备或换点位时业务层被迫修改
- 业务规则和现场信号耦合
正确方式应该是:
DeviceStatus status = deviceStatusGateway.getStatus("M001");
if (status.canStartProduction()) {
// 允许开工
}
这样 PLC 地址、协议细节都留在适配层。
2. 设备模型要做“适度统一”
可以统一这些共性:
- 运行
- 停机
- 故障
- 待机
- 离线
- 当前程序号
- 当前产品号
- 产量计数
- 告警代码
但不要过度统一到丢失差异。
比如某类设备有“模具锁定异常”,另一类设备没有,就不要强行压平。
3. 设备事件建议事件化
比起让业务层定时轮询设备状态,更推荐:
- 设备信号变化 -> 转换为标准事件
- 事件进入消息总线
- 上层消费事件并做业务响应
例如:
DeviceStartedEventDeviceAlarmRaisedEventProductionCounterChangedEvent
这样做的好处:
- 解耦
- 可回放
- 易审计
- 更适合产线联动
七、和 DDD 的关系:AAA 是否等于 DDD
很多人会问,AAA 架构是不是就是 DDD?
答案是:不完全等于,但可以结合。
1. AAA 更像“分层方法”
AAA 更强调:
- 应用怎么编排
- 业务怎么抽象
- 外部怎么接入
它关注的是“系统结构”。
2. DDD 更像“建模方法”
DDD 更强调:
- 领域模型
- 聚合
- 实体
- 值对象
- 领域事件
- 限界上下文
它关注的是“业务语义”。
3. 二者可以结合使用
在工业制造里,一个常见做法是:
- 用 AAA 控制大层次结构
- 在核心域内部,用 DDD 思想做领域建模
例如:
- 工单、工序、批次、设备资源作为领域对象
- 报工、开工、暂停、完工作为领域行为
- 设备异常、质量判退作为领域事件
但不建议把 DDD 的所有术语和模式机械照搬到每个模块。
工业项目更适合“按需采用”。
八、AAA 架构的优点:工程实践角度看
这里不重复泛泛而谈,直接说工程上的价值。
1. 外围系统变化不会直接污染核心业务
ERP 改接口、WMS 改字段、设备换协议时,主要改适配层。
核心工单和报工规则可以保持稳定。
2. 工厂复制更容易
A 工厂和 B 工厂业务相近,但设备、WMS、ERP 版本不同。
如果核心规则在领域层,差异主要在适配层,就能更好复制推广。
3. 规则沉淀更稳定
工单是否能开工、报工怎么校验、批次怎么追溯,这些规则比某个具体接口更稳定。
沉淀在抽象层后,长期收益很大。
4. 更适合多人协作
- 业务开发关注应用和领域
- 集成开发关注 ERP/WMS/设备适配
- 测试可以按层验证
- 运维能更快定位问题
5. 更利于现场联调
现场联调最怕一改接口全系统受影响。
有适配层后,很多问题能在边界层局部处理。
九、AAA 架构的缺点:落地时的真实成本
1. 开发速度在前期通常会下降
尤其是刚开始推行时,团队会感觉:
- 文件变多了
- 跳转变多了
- 小功能也要走分层
- 改一个功能要改多个对象
这是客观存在的成本。
2. 团队不熟时很容易写成“空心架构”
很多项目会变成:
- 应用层只转发
- 领域层只转发
- 适配层也只转发
- 最后真正逻辑还是写在一个 impl 里
结果是结构复杂了,但收益没出现。
3. 抽象一旦做错,代价很大
比如把“工单”“批次”“设备任务”过早统一成一个超级模型。
看起来通用,实际表达能力差,后续只会不断打补丁。
4. 排障路径更长
问题可能出在:
- API 参数
- 应用编排
- 领域规则
- 持久化
- 适配器
- 外部接口
- 消息链路
如果日志不好,分层越清晰,排障反而越慢。
十、最容易踩的坑
下面这些坑在工业项目里非常常见。
坑 1:所有模块一刀切都按重型分层来做
基础资料、字典配置、简单查询模块,并不值得上完整重型模型。
例如:
- 设备台账管理
- 班次字典维护
- 原因代码维护
这些模块更适合轻量实现。
不要把它们和“报工核心流程”用同样重量对待。
坑 2:把领域层做成数据库表镜像
有些项目所谓领域模型,实际上就是:
- 一张表一个 entity
- entity 里只有 getter/setter
- 真正规则都在 service 里
这不叫领域建模,只是“对象化表结构”。
坑 3:适配层没有真正封装外部差异
比如虽然有 erpAdapter,但业务层还是知道 ERP 的字段名、错误码、接口状态值。
这样适配层就失去意义了。
坑 4:对象过多,修改成本极高
一个报工字段 goodQty 可能同时存在于:
- RequestDTO
- Command
- DomainDTO
- Entity
- PO
- DO
- VO
- ResponseDTO
字段一改,改一串。
这种设计在工业项目里极易拖慢交付。
坑 5:为了“通用平台”牺牲业务表达
很多项目想做成超通用制造平台,结果:
- 模型非常抽象
- 业务方听不懂
- 开发写起来费劲
- 现场特例无法表达
工业系统首先要对业务有表达力,然后再考虑通用性。
十一、如何避免 AAA 架构用得过重
这是最关键的一节。
1. 只在“高变化 + 高复杂”处做重抽象
重点对象通常包括:
- 工单执行
- 工序流转
- 报工
- 批次追溯
- 设备状态事件
- 质量判定
这些值得重点做领域抽象。
而这些通常不需要那么重:
- 下拉列表配置
- 基础字典
- 简单报表查询
- 配置管理页面
2. 从一个核心流程开始,不要全域铺开
推荐先选一条主链路,比如:
- 工单下发 -> 开工 -> 报工 -> 完工 -> 入库
在这条链路上验证 AAA 是否真的带来价值。
成功后再推广到质量、追溯、设备联动等模块。
3. 领域层必须有“规则”,没规则就不要硬抽
判断一层是否值得保留,可以问一句:
如果去掉这层,业务规则是否会四处散落?
如果答案是否,那这层可能没必要这么重。
4. 保持适配层稳定,但不过度包装
适配层应该封装差异,但不要无限封装。
举例:
- 对 ERP 提供统一完成报工接口,合理
- 对每一个字段变化都包出三层转换器,通常不合理
5. 控制对象数量
建议按边界真正需要来拆对象:
- 入参对象
- 领域对象
- 出参对象
够用即可。
不要默认一层一个对象族。
6. 把测试重点放在领域规则和集成边界
最值得测的是:
- 核心规则对不对
- 外部接口适配对不对
而不是把大量精力浪费在纯转发类上。
推荐测试分布:
- 领域层:单元测试
- 应用层:关键流程测试
- 适配层:契约测试 / 模拟接口测试
- 全链路:少量端到端验证
7. 增强可观测性
建议至少做这些:
- 请求链路 ID
- 工单 / 批次 / 设备维度日志
- 外部接口调用日志
- 消息发送与消费日志
- 业务状态变更审计
- 失败补偿记录
工业现场出现问题时,这些能力比“理论分层是否优雅”更重要。
十二、一个推荐的“轻量 AAA”实施路线
如果你准备在制造项目里落地 AAA,可以按下面步骤走。
阶段 1:先识别核心对象
先确认最关键的业务对象:
- WorkOrder
- Operation
- ProductionExecution
- DeviceStatus
- MaterialLot
- QualityInspection
不要一上来设计 50 个抽象对象。
阶段 2:收敛外部接口
先把这些接入统一到适配层:
- ERP
- WMS
- QMS
- SCADA
- Device/PLC
哪怕领域层还不完美,先把外部耦合收住,收益就已经很大。
阶段 3:围绕主流程沉淀规则
优先沉淀最核心的几个动作:
- 开工
- 暂停
- 报工
- 完工
- 入库触发
- 质量放行
阶段 4:逐步事件化
将关键事件标准化,例如:
WorkOrderStartedEventWorkReportedEventDeviceAlarmRaisedEventInspectionFailedEvent
这会显著提升联动能力和扩展性。
阶段 5:治理外围模块
对简单模块保持轻量,不要强制套完整模型。
这样才能保证交付速度和架构收益平衡。
十三、一个判断标准:你的 AAA 是否做对了
如果你的系统满足下面这些现象,说明 AAA 大概率是有效的:
- ERP/WMS 接口变更时,核心工单逻辑几乎不用动
- 设备替换时,主要修改适配层
- 核心报工规则在一个地方能找到
- 新增一个工厂时,复用核心模型,替换局部接入即可
- 新人能快速找到“流程层”“规则层”“接入层”
- 日志能清晰定位问题卡在哪一层
反过来,如果你发现:
- 简单功能开发明显变慢
- 抽象层找不到真实业务规则
- 大量类只是转发
- 每次需求改动都要全层联动
- 团队越来越依赖“经验找代码”
那就说明这个 AAA 很可能已经过重,或者边界设计有问题。
十四、结语
在工业制造领域,AAA 架构的价值从来不在于“概念先进”,而在于它是否真正解决了下面这些问题:
- 业务规则是否能沉淀
- 外部系统差异是否被隔离
- 设备接入是否被解耦
- 系统是否还能长期演进
- 现场问题是否能快速定位
所以,AAA 不是越重越好,也不是层数越多越专业。
真正有效的落地方式是:
- 对核心复杂性做清晰抽象
- 对简单模块保持克制
- 对外部接入建立边界
- 对测试和可观测性投入足够重视
一句话总结就是:
工业制造里的 AAA,最佳实践不是“全量标准化”,而是“围绕核心流程做适度架构”。
更多推荐
所有评论(0)