文章目录


工业制造领域 AAA 架构落地指南:分层设计、系统集成、代码示例与避坑实践

在工业制造系统建设中,团队经常会遇到三类典型问题:

  1. 业务复杂:工单、工艺、报工、质量、批次追溯、设备联动,规则很多
  2. 集成复杂:MES 要连 ERP、WMS、QMS、SCADA、设备采集平台
  3. 变化频繁:设备会换、接口会改、流程会调、工厂之间还不完全一样

如果没有清晰的架构边界,系统很容易在一年后变成这样:

  • 业务规则散落在 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-app
  • production-app
  • quality-app
  • trace-app

领域/抽象层

  • workorder-domain
  • production-domain
  • quality-domain
  • equipment-domain

适配层

  • erp-adapter
  • wms-adapter
  • qms-adapter
  • scada-adapter
  • plc-adapter
  • repository-impl
  • mq-adapter

接口层

  • rest-api
  • job-scheduler
  • message-consumer

基础设施层

  • common-log
  • common-event
  • common-auth
  • common-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. 设备事件建议事件化

比起让业务层定时轮询设备状态,更推荐:

  • 设备信号变化 -> 转换为标准事件
  • 事件进入消息总线
  • 上层消费事件并做业务响应

例如:

  • DeviceStartedEvent
  • DeviceAlarmRaisedEvent
  • ProductionCounterChangedEvent

这样做的好处:

  • 解耦
  • 可回放
  • 易审计
  • 更适合产线联动

七、和 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:逐步事件化

将关键事件标准化,例如:

  • WorkOrderStartedEvent
  • WorkReportedEvent
  • DeviceAlarmRaisedEvent
  • InspectionFailedEvent

这会显著提升联动能力和扩展性。


阶段 5:治理外围模块

对简单模块保持轻量,不要强制套完整模型。
这样才能保证交付速度和架构收益平衡。


十三、一个判断标准:你的 AAA 是否做对了

如果你的系统满足下面这些现象,说明 AAA 大概率是有效的:

  • ERP/WMS 接口变更时,核心工单逻辑几乎不用动
  • 设备替换时,主要修改适配层
  • 核心报工规则在一个地方能找到
  • 新增一个工厂时,复用核心模型,替换局部接入即可
  • 新人能快速找到“流程层”“规则层”“接入层”
  • 日志能清晰定位问题卡在哪一层

反过来,如果你发现:

  • 简单功能开发明显变慢
  • 抽象层找不到真实业务规则
  • 大量类只是转发
  • 每次需求改动都要全层联动
  • 团队越来越依赖“经验找代码”

那就说明这个 AAA 很可能已经过重,或者边界设计有问题。


十四、结语

在工业制造领域,AAA 架构的价值从来不在于“概念先进”,而在于它是否真正解决了下面这些问题:

  • 业务规则是否能沉淀
  • 外部系统差异是否被隔离
  • 设备接入是否被解耦
  • 系统是否还能长期演进
  • 现场问题是否能快速定位

所以,AAA 不是越重越好,也不是层数越多越专业。
真正有效的落地方式是:

  • 对核心复杂性做清晰抽象
  • 对简单模块保持克制
  • 对外部接入建立边界
  • 对测试和可观测性投入足够重视

一句话总结就是:

工业制造里的 AAA,最佳实践不是“全量标准化”,而是“围绕核心流程做适度架构”。


Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐