很多项目能跑,但活不久。
很多系统上线很快,但三个月后就开始痛苦。
真正拉开差距的,不是技术选型,而是工程结构

如果你学后端只是为了“写接口”,那结构不重要。
但如果你的目标是“构建系统”,那结构就是一切。

这一课讲的是:
👉 一个后端工程,第一天结构不对,后面全是灾难。

一、为什么工程结构决定系统寿命

大多数后端项目,不是死于并发,不是死于性能,而是死于:

  • 业务膨胀
  • 模块互咬
  • 改动恐惧
  • 新人不敢动
  • 重构成本极高

这些问题,几乎都指向一个根因:

❌ 结构承载不了复杂度

工程结构的唯一使命:

👉 让复杂度有秩序,而不是扩散。

二、从“写接口”到“建系统”:结构设计的核心问题

一个真正的后端系统,第一天必须回答清楚四个问题:

  1. 谁负责对外沟通
  2. 谁负责业务规则
  3. 谁负责数据世界
  4. 谁负责系统能力

如果这些边界模糊,项目一定会变成:

Controller 写业务
Service 写 SQL
Entity 当返回对象
工具类到处飞

👉 结果一定是系统不可控。

三、推荐工程结构(架构型后端起手式)

不是“三层”,而是“五层结构”:

com.xxx.project

├─ interfaces / controller     接口适配层
├─ application / service       业务编排层
├─ domain                      业务核心层 ⭐
├─ infrastructure              技术实现层
│   ├─ persistence             数据库实现
│   ├─ cache                   Redis
│   ├─ mq                      消息
│   └─ external                三方系统
└─ common                      通用规范/工具

这是架构分层,不是文件分类。

四、每一层“只干一类事”(这是工程纪律)

✅ 1. interfaces / controller —— 协议适配层

只负责:

  • HTTP 参数接收

  • 参数校验

  • DTO 转换

  • 返回结构

禁止:

  • 业务规则

  • SQL

  • 状态机

  • 复杂逻辑

它解决的是:

👉 外部世界如何进入系统

类比:

Android Activity / Flutter Widget

✅ 2. application / service —— 业务编排层

负责:

  • 业务流程组织
  • 权限控制
  • 事务边界
  • 多 Domain 协作

不关心:

  • HTTP
  • ORM
  • 框架细节

它解决的是:

👉 一次业务“怎么完成”

✅ 3. domain —— 业务核心层(系统灵魂)

这里放:

  • 业务对象
  • 业务规则
  • 状态变化
  • 行为封装

示例:

order.cancel();
user.upgradeVip();
account.freeze();

禁止出现:

  • SQL
  • HTTP
  • DTO
  • 框架注解

👉 Domain 表达的是业务语义,不是数据结构

有没有这一层,决定你是:

❌ CRUD 工程师
✅ 架构型后端

✅ 4. infrastructure —— 技术实现层

这里放:

  • 数据库实现
  • Redis 实现
  • MQ 实现
  • 三方 SDK

它的职责:

👉 给业务层提供“技术能力”

它可以变,但不应该撼动业务结构。

✅ 5. common —— 系统公约层

  • 统一返回
  • 异常体系
  • 日志规范
  • 工具能力

👉 这是系统的“宪法层”。

五、DTO / Entity / Domain 怎么拆(90% 混乱源头)

❌ 灾难模型

一个 User 同时是:

  • 数据库表
  • 接口返回
  • 业务对象

结果一定是:全系统强耦合

✅ 正确拆法:三个世界,三套模型

1️⃣ DTO(接口世界)

DTO = Data Transfer Object
👉 中文:数据传输对象

它的本意非常直白:

专门用来“在边界之间传输数据的对象”。

UserCreateRequest
UserResponse

特点:

  • 为接口而生
  • 快速变化
  • 表达协议

2️⃣ Entity / PO(数据世界)

UserEntity

特点:

  • ORM 映射
  • 对应表结构
  • 技术对象

3️⃣ Domain(业务世界)

User

特点:

  • 有行为
  • 有规则
  • 有状态约束

👉 三个世界,绝不混用。

六、一个“下单业务”的标准工程落位

Controller
  → OrderCreateRequest DTO
     → OrderApplicationService
        → OrderFactory.create()
        → order.submit()
        → stock.freeze()
        → orderRepository.save(order)

你会发现:

  • Controller 不懂业务
  • Repository 不懂流程
  • Domain 不懂 HTTP

👉 每一层都“很傻”,系统才会“很稳”。

七、为什么这种结构能“活三年”

因为它天然支持:

✔ 业务膨胀
✔ 模块拆分
✔ 技术替换
✔ 多端接入
✔ 微服务演进

当你要:

  • 加 Redis
  • 拆服务
  • 换 ORM
  • 接新客户端

你会发现:
👉 大部分修改,不会触碰 Domain。

================================================

补充:为什么要把 interfaces 拆成 http / rpc / mq / job / webhook / admin?

很多同学看到分层结构里出现 interfaces 会误解成“Java interface 的地方”。
这里的 interfaces 不是语法关键字,而是架构概念——系统对外的入口层(Inbound Adapters / Interface Adapters)。

一句话定义:

interfaces = 外部世界进入系统的所有触发点
(HTTP、RPC、消息、定时任务、三方回调、管理后台……)

当你的系统不止有 HTTP 接口时,这一层就必须拆细,否则会出现典型混乱:

  • MQ 消费逻辑写进 Service
  • Job 直接操作 Repository
  • Webhook 回调与普通 API 混在一起
  • Admin 接口和用户接口混权限、混语义

所以我推荐把 interfaces 拆成下面这套结构:

interfaces
 ├─ http
 │   ├─ controller
 │   ├─ dto
 │   └─ assembler
 ├─ rpc
 ├─ mq
 ├─ job
 ├─ webhook
 └─ admin

这套结构的核心价值:按“触发源”划分入口边界

1)interfaces/http:普通 HTTP API 入口

适用场景:App/Web/小程序调用的 REST API。

建议再细分三个子包:

  • controller:只处理协议(路由、参数、校验、返回)
  • dto:请求/响应模型(Request/Response)
  • assembler:DTO ↔ Command/Domain 的转换器(隔离协议世界与业务世界)

✅ 命名规范

  • Controller:OrderController
  • Request:CreateOrderRequest
  • Response:OrderResponse
  • Assembler:OrderAssembler(或 OrderConverter

✅ 核心纪律

  • Controller 禁止写业务规则
  • DTO 禁止进入 domain / application
  • Assembler 负责“翻译”,不是写业务

2)interfaces/rpc:服务间调用入口(Dubbo/gRPC/Feign)

适用场景:系统被其他系统调用(内部服务间)。

为什么单独分一层?

  • RPC 的协议、鉴权、幂等、版本管理,和 HTTP 不一样
  • RPC 是内部合同,稳定性要求更高

✅ 命名规范

  • OrderRpcService
  • 若区分读写:OrderQueryRpcService / OrderCommandRpcService

核心原则仍然一样:RPC 层只做入站适配,调用 application。

3)interfaces/mq:消息消费入口(Kafka/RabbitMQ/RocketMQ)

适用场景:事件驱动架构(支付成功、库存冻结、用户注册等事件)。

MQ 消费本质是“外部事件触发系统”,因此必须属于 interfaces

✅ 命名规范(推荐 Consumer)

  • OrderPaidConsumer
  • UserCreatedConsumer
  • InventoryReservedConsumer

✅ 核心纪律

  • Consumer 只负责:反序列化/校验/幂等入口处理 → 调 application
  • 禁止:Consumer 里写业务流程、写 SQL、写复杂判断

4)interfaces/job:定时任务入口(xxl-job/quartz/schedule)

适用场景:超时关单、对账、定时同步、日报生成等。

Job 是“时间触发系统”,依然是入口,不属于业务层。

✅ 命名规范

  • OrderTimeoutJob
  • DailyReportJob
  • SyncCatalogJob

✅ 核心纪律

  • Job 不直接操作 Repository / DB
  • Job 只触发 application 的用例流程

5)interfaces/webhook:三方回调入口(支付/物流/开放平台)

适用场景:微信支付回调、Stripe webhook、物流状态回调、OAuth 回调等。

为什么不放在 http?

因为 webhook 的语义更像“外部系统事件”,它往往有:

  • 签名验签
  • 重试/幂等
  • 特殊返回格式约束
  • 安全策略与普通 API 不同

✅ 命名规范

  • WechatPayWebhookController
  • StripeWebhookController

核心原则:验签/解析/去重 → 调 application。

6)interfaces/admin:后台/运营入口(内部人员使用)

适用场景:运营后台、管理后台、内部管理接口。

为什么要单独分?

  • 权限模型不同(admin 往往更高权限)
  • 返回字段不同(更详细、更偏运维/管理)
  • 防止“误用/误暴露”接口

✅ 命名规范

  • AdminOrderController
  • AdminUserController

强烈建议 admin 的路由前缀统一:/admin/**

7)一张“入口层的统一原则”总结

无论是 HTTP / RPC / MQ / Job / Webhook / Admin,它们都必须遵守同一条架构约束:

✅ interfaces 只做入站适配,不做业务

标准调用路径必须是:

interfaces → application → domain → infrastructure

interfaces 层负责:

  • 接收输入(协议适配)
  • 校验(格式与基本合法性)
  • 组装/转换(DTO ↔ Command/Domain)
  • 调用 application 用例

真正的业务规则必须沉到:

  • application(流程编排、事务边界)
  • domain(业务规则、状态变化)

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐