4. 架构设计阶段的常见错误:过度设计、缺乏模块划分、接口定义不清
架构设计,说白了就是给整个系统画骨架。骨架歪了,后面填再多肉也白搭。我见过太多项目,前期架构图画得天花乱坠,一到落地就各种打补丁。今天咱们就聊聊架构阶段最容易踩的三个坑。
4.1 过度设计:为未来10年买单
过度设计是架构师最容易犯的毛病。总觉得系统要支持百万并发、要兼容所有可能的扩展、要用上最前沿的技术栈。结果呢?项目延期、团队崩溃、业务等不起。
典型症状:
- 引入分布式事务,实际业务单机就能搞定
- 设计6层抽象接口,最终只用了2层
- 预留大量扩展点,但需求从未到来
- 采用微服务架构,团队只有3个人
我曾经接手过一个物联网项目。架构师设计了完整的边缘计算框架,用了Kubernetes、Service Mesh、事件溯源。但实际业务只是定时上报温度数据,单机MQTT就能解决。最后重构花了两个月,全是过度设计欠的债。
我的建议:遵循YAGNI原则(You Ain't Gonna Need It)。只解决当前明确的需求,未来扩展用重构来应对。你想想看,业务活不过半年,你设计个10年架构图给谁看?
4.2 缺乏模块划分:一锅粥式的架构
模块划分不清,代码就会变成一锅粥。业务逻辑、数据访问、UI渲染全搅在一起。改一个功能,牵动全身。测试?根本没法测。
好的模块划分应该遵循高内聚、低耦合。每个模块只做一件事,并且做好。模块之间通过明确的接口通信,内部实现对外部完全透明。
| 划分原则 | 错误做法 | 正确做法 |
|---|---|---|
| 单一职责 | 一个模块处理订单、支付、物流 | 拆分为订单模块、支付模块、物流模块 |
| 接口隔离 | 一个接口暴露所有方法 | 按调用方需求拆分细粒度接口 |
| 依赖方向 | 高层模块依赖低层实现 | 都依赖抽象接口,方向由接口控制 |
| 边界清晰 | 模块间共享全局变量 | 只通过参数传递,不共享状态 |
我记得有个支付系统,订单模块直接操作数据库表,物流模块也操作同一张表。后来要加个优惠券功能,两个模块都改了数据库,结果线上数据错乱。这就是模块边界没划清楚。
避坑指南:我曾经在模块划分上吃过亏。一个模块里塞了用户管理、权限控制、日志记录。后来权限需求变更,改了一周,还引入了新bug。正确的做法是:每个模块的职责用一句话能说清楚,说不清楚就继续拆。
4.3 接口定义不清:沟通的噩梦
接口定义是架构设计的核心产出之一。接口不清,前后端扯皮、模块间联调困难、文档形同虚设。说白了,接口就是模块之间的契约,契约写不清楚,合作就出问题。
接口定义常见问题:
- 参数含义模糊,比如status字段是0表示成功还是1表示成功?
- 返回值结构不固定,有时返回对象,有时返回数组
- 错误码没有统一规范,各模块自己定义
- 缺少版本管理,接口改了调用方不知道
接口定义检查清单:
- 每个接口必须有明确的输入输出定义
- 参数类型、取值范围、默认值都要写清楚
- 错误码统一管理,文档中列出所有可能错误
- 接口版本号放在URL或Header中
- 提供接口变更通知机制
我参与过一个电商项目,订单接口的status字段,前端传1表示待支付,后端却用0表示待支付。联调时查了两天才发现是文档写错了。这种低级错误,完全可以通过接口定义规范来避免。
// 接口定义示例(错误)
POST /api/order
{
"userId": 123,
"items": "商品列表",
"status": 1
}
// 接口定义示例(正确)
POST /api/v1/orders
请求参数:
{
"userId": { "type": "integer", "required": true, "desc": "用户ID" },
"items": {
"type": "array",
"required": true,
"desc": "商品列表",
"items": {
"type": "object",
"properties": {
"skuId": { "type": "string", "desc": "SKU编号" },
"quantity": { "type": "integer", "min": 1, "desc": "数量" }
}
}
},
"status": {
"type": "integer",
"enum": [0, 1, 2],
"desc": "0-待支付 1-已支付 2-已取消"
}
}
4.4 架构设计自检清单
每次做完架构设计,我都会拿这张清单过一遍。嗯,虽然不能保证100%没问题,但至少能筛掉80%的坑。
| 检查项 | 通过标准 | 常见问题 |
|---|---|---|
| 模块划分 | 每个模块职责单一,边界清晰 | 模块间耦合严重,职责重叠 |
| 接口定义 | 输入输出明确,错误码统一 | 参数含义模糊,返回值不固定 |
| 过度设计 | 只解决当前需求,不预支未来 | 引入不必要技术栈,过度抽象 |
| 依赖管理 | 依赖方向合理,无循环依赖 | 模块间相互引用,形成依赖环 |
| 扩展性 | 预留关键扩展点,但不过度 | 要么没有扩展点,要么全是扩展点 |
| 文档完整性 | 架构图、接口文档、数据流图齐全 | 只有口头约定,没有书面文档 |
实用技巧:我习惯在架构设计完成后,找团队里最较真的同事做一次架构评审。让他扮演「杠精」角色,专门挑刺。往往能发现很多自己没注意到的问题。别怕被怼,架构设计阶段发现问题,成本最低。
4.5 架构设计核心流程
下面这张图是我自己总结的架构设计流程。每次做新项目,我都会按这个步骤走一遍。你想想看,流程走对了,结果一般不会太差。
流程走完,架构设计基本就稳了。但别忘了,架构不是一成不变的。业务在变,技术在变,架构也要跟着演进。我见过太多团队,架构评审通过后就再也不碰了,结果半年后架构图跟实际代码完全对不上。
最后提醒:架构设计文档要持续维护。每次迭代都花10分钟更新架构图,比半年后花一周重构划算得多。这是我用血泪教训换来的经验。