需求分析与设计:需求调研方法、系统边界划分、服务接口设计原则、RESTful API 设计规范

好,咱们进入第二章。需求分析与设计。

说实话,很多开发兄弟觉得这章“虚”,不如直接写代码实在。我以前也这么想。直到有一次,我花了两周写了一个服务,结果产品经理说“这不是我要的”。嗯,从那以后,我再也不敢跳过需求分析了。

这一章,咱们把需求调研、边界划分、接口设计这几个硬骨头啃下来。

2.1 需求调研方法:别让“我以为”毁了项目

需求调研,说白了就是搞清楚“到底要做什么”。我见过太多项目,开发闷头做,做完发现跟用户想要的差了十万八千里。

2.1.1 常见的调研方法

我个人习惯把这几种方法组合着用,效果最好:

方法 适用场景 我的经验
用户访谈 探索性需求,了解痛点 别问“你想要什么”,问“你现在怎么做的”
问卷调查 大规模收集意见 问题别超过15个,否则没人填完
竞品分析 明确功能基线 别只抄功能,要分析人家为什么这么做
原型演示 验证需求理解是否一致 用Axure或Figma画个低保真,比写文档管用
数据分析 优化已有系统 埋点数据不会骗人,但要注意样本偏差
我的小技巧:每次访谈结束后,当天必须整理出“用户原话+我的理解+待确认项”三栏表。拖到第二天,很多细节就忘了。

2.1.2 需求调研的避坑指南

我曾经在一个电商项目中踩过坑。业务方说“要一个促销功能”,我们直接开干。结果做出来,人家要的是“满减”,我们做的是“打折”。返工了两周。

所以,调研时一定要做到:

  • 场景化追问:“什么情况下会用这个功能?”
  • 量化指标:“每天大概处理多少笔?”
  • 异常流程:“如果网络断了怎么办?”

2.2 系统边界划分:画好你的“一亩三分地”

系统边界,就是明确“你的服务管什么,不管什么”。我见过最乱的系统,就是所有逻辑都揉在一个服务里,改一个功能,重启整个系统。

2.2.1 划分原则

我一般遵循这几个原则:

  1. 业务职责单一:一个服务只做一件事,比如“订单服务”只管订单,“支付服务”只管支付。
  2. 数据独立:每个服务有自己的数据库,别共享一个库。否则耦合度太高。
  3. 变更频率一致:经常一起改的功能,放在一个服务里;很少改的,单独拆出来。
  4. 团队结构对齐:一个服务由一个团队负责,避免跨团队扯皮。
核心思想:高内聚,低耦合。说白了,就是让每个服务内部关系紧密,服务之间关系简单。

2.2.2 边界划分的常见模式

举个例子,一个典型的电商系统,我会这样划分:

电商系统边界划分示例 用户服务 注册/登录/权限 商品服务 商品信息/库存 订单服务 订单创建/状态 支付服务 支付/退款 物流服务 配送/轨迹 通知服务 短信/邮件/推送 说明 每个服务独立部署、独立数据库 服务间通过 API 或消息队列通信
注意:边界划分不是越细越好。服务拆得太碎,会带来分布式事务、网络延迟、运维复杂度飙升等问题。我建议初期先粗分,随着业务发展再逐步拆分。

2.3 服务接口设计原则:接口是契约,不是实现

接口设计,是服务之间通信的“合同”。合同写得好,大家合作愉快;合同写得烂,天天扯皮。

2.3.1 四大核心原则

原则 解释 反面案例
接口幂等性 同一个请求执行多次,结果一样 支付接口没做幂等,用户点了两次,扣了两笔钱
接口无状态 每次请求都包含所有必要信息 依赖 Session 存储用户信息,导致无法水平扩展
接口版本化 变更时保留旧版本,逐步迁移 直接修改接口,导致调用方全部报错
接口可测试性 接口逻辑清晰,容易构造测试用例 一个接口做了10件事,测试用例写不出来
关于幂等性:我习惯在请求中加一个 idempotent_key(幂等键),服务端根据这个键去重。这样即使客户端重试,也不会产生重复数据。

2.4 RESTful API 设计规范:让接口像 URL 一样直观

RESTful API,说白了就是用 HTTP 协议的方法(GET、POST、PUT、DELETE)来操作资源。你想想看,如果接口设计得乱七八糟,前端同学会骂娘的。

2.4.1 资源命名规范

  • 使用名词复数:/users 而不是 /getUser
  • 层级关系用斜杠:/users/123/orders
  • 不要用动词:/orders/create 是错的,应该用 POST /orders
  • 查询参数用于过滤:/orders?status=paid&page=1

2.4.2 HTTP 方法使用规范

方法 用途 是否幂等 请求体
GET 获取资源 是 无
POST 创建资源 否 有
PUT 全量更新资源 是 有
PATCH 部分更新资源 否 有
DELETE 删除资源 是 无

2.4.3 状态码使用规范

我见过很多项目,不管成功还是失败,一律返回 200。然后自己在 body 里写一个 code 字段。这种做法,说实话,很不专业。

正确的做法是:

  • 200 OK:GET 成功、PUT 成功
  • 201 Created:POST 创建成功
  • 204 No Content:DELETE 成功
  • 400 Bad Request:参数错误
  • 401 Unauthorized:未认证
  • 403 Forbidden:无权限
  • 404 Not Found:资源不存在
  • 500 Internal Server Error:服务器内部错误

2.4.4 一个完整的 RESTful API 示例

假设我们要设计一个“用户订单”相关的 API:

# 获取用户列表
GET /api/v1/users

# 获取单个用户
GET /api/v1/users/{user_id}

# 创建用户
POST /api/v1/users
Content-Type: application/json
{
    "name": "张三",
    "email": "zhangsan@example.com"
}

# 更新用户信息
PUT /api/v1/users/{user_id}
Content-Type: application/json
{
    "name": "李四",
    "email": "lisi@example.com"
}

# 删除用户
DELETE /api/v1/users/{user_id}

# 获取用户的订单列表
GET /api/v1/users/{user_id}/orders?status=paid&page=1&size=20
关键点:URL 中只出现名词和斜杠,动词用 HTTP 方法表达。查询参数用于过滤、分页、排序。

2.4.5 错误响应格式

我曾经在一个项目中,每个接口的错误格式都不一样。有的返回 {error: "xxx"},有的返回 {message: "xxx"}。前端同学对接的时候,快疯了。

所以,我建议统一错误响应格式:

{
    "code": 40001,
    "message": "参数校验失败",
    "details": {
        "field": "email",
        "reason": "邮箱格式不正确"
    }
}

这样,前端可以根据 code 做统一处理,根据 message 展示给用户,根据 details 定位具体问题。

注意:不要直接把后端异常堆栈抛给前端。这既不安全,也不友好。统一在网关层做异常拦截和格式化。

好了,这一章的内容就这些。需求调研、边界划分、接口设计,这三件事做好了,后面的开发工作会顺畅很多。记住,磨刀不误砍柴工。