开发是自己可控的,集成要迁就别人的系统、别人的节奏、别人的历史烂账。集成的工作量通常不是「对接」,而是「对齐」。
三条真实集成链路:① 经销商门店远程双签——门店在手机上签认订单与工单,核心是「谁在什么状态下可以签、签了能不能撤、纠纷以谁为准」;② 黑湖小工单集成——明确哪些字段单向同步、哪些不做双向;③ prod 写桥边界治理——所有写生产库的请求必须经过写桥层,禁止业务代码直连改表。
延伸:基础 15 · 读懂 monorepo 讲你项目 4 包结构与包间引用规则(集成边界的代码级对应)。
一个系统从零开发,需求是我定的、表结构是我定的、节奏是我控的。而集成意味着:我得去动别人的东西。这四件事会同时把项目拖慢:
| 维度 | 自己开发 | 集成别人的系统 |
|---|---|---|
| 需求 | 自己定义,自己改 | 对方的历史包袱不能改,只能适配 |
| 节奏 | 我说了算 | 要看对方的版本计划和排期 |
| 数据 | 字段想怎么设计就怎么设计 | 字段语义可能和你的理解完全不同 |
| 责任 | 出问题我修 | 出问题要先分清是谁的锅 |
这五个问题答不上来的,不要开工,先做接口探查。接口探查是独立的一个小交付,也可以单独收费。
| # | 问题 | 答不上来意味着什么 | 怎么查 |
|---|---|---|---|
| 1 | 对方系统有没有 API | 可能根本没有接口,只能走文件甚至 RPA,工期和稳定性都要重估 | 看对方开放平台文档,或直接问技术对接人 |
| 2 | 文档是否稳定、是否完整 | 接口随时会变,你写的代码随时会挂 | 要一份版本化的接口文档 + 一个可用的测试环境 |
| 3 | 谁有改动权限 | 你提的字段变更没人拍板,扯皮无解 | 要一个明确的对接人和变更审批路径 |
| 4 | 数据谁对不对 | 出问题时责任无法归属,验收无法进行 | 约定「以谁的数据为准」,并写进单据 |
| 5 | 出错时谁负责 | 线上故障时你在查日志、对方在查日志,没人修 | 约定告警接收人和响应时限 |
同一个业务目标,可能有五条技术路径。选错路径,代价会在上线后加倍还给你。
| 模式 | 实时性 | 开发成本 | 稳定性 | 适用场景 |
|---|---|---|---|---|
| API 直连 | 秒级 | 中(要看对方文档质量) | 高,但受对方版本影响 | 双方技术团队都在场、有正式文档和测试环境 |
| Webhook 回调 | 秒级 | 中高(要处理重试、去重、验签) | 中,链路更长 | 对方不方便被你轮询,需要事件驱动时 |
| 文件交换(CSV / Excel) | 按批次,可做到当天/每小时 | 低 | 高(可重跑、可人工核对) | 对方没有 API、或者数据量大到接口不划算 |
| 数据库直读 | 高 | 看似低,实则高 | 低 | ⚠️ 只读可以勉强接受;可写等于把生产库交出去 |
| RPA / 人工兜底 | 最差 | 看起来低,长期最高 | 最低(依赖界面和人工) | 只作为前三者都不可行时的最后手段,且必须写明是临时方案 |
项目:德莉玛门店订购系统。业务场景:经销商门店要在手机上远程签认订单和工单——门店收到货单或工单派工后,在手机上看明细、确认签认,留痕作为后续对账和结算的依据。
一张订单实际有两个独立的确认动作:一是门店确认「我收到的是这一单」,二是技术确认「这一单按这个技术条件做」。这两件事在不同时间、由不同人、在不同状态下发生——所以链路必须是两条独立的签认记录,而不是一个签两次。
把签认拆成两个节点,节点之间有前置依赖:门店签在前,技术确认在后,技术确认页必须能看到门店签认的明细快照。任何一个节点撤回,下游节点自动失效,不允许出现「门店撤了但技术还留着」的状态。
每次签认落四个东西:操作人ID、角色、签认时刻(精确到秒)、设备与网络来源。时间戳统一存UTC,展示时再按门店时区渲染——这里踩过坑,见模块 11 的「口径不一致」。
门店网络经常不稳。所以签认动作先落本地队列,恢复网络后自动补传,本地保留原始签名图与快照摘要。补传走幂等键,重复提交不会产生第二条签认记录。
| 问题 | 不提前定会怎样 | 本项目的定法 |
|---|---|---|
| 谁在什么状态下可以签 | 订单已作废还能被签,或者同一单被两个人签 | 按状态机开权限:只有「已派工」状态的门店单可门店签,只有「门店已签」状态可技术确认 |
| 签了之后能不能撤 | 一方反悔直接改数据,留痕失效,纠纷时无法举证 | 只能「作废重签」,不能修改或删除原签认;作废需要填原因 |
| 纠纷时以谁为准 | 各执一词,最后谁声音大听谁的 | 以服务端留痕为准;本地离线签名只是补传来源,不作为最终依据 |
第二个案例更偏架构。背景:黑湖是第三方生产工单 SaaS,门店/生产相关的工单要和我们自己的生产数据打通。
集成最容易出事的不是技术,是双向同步打架。两个系统都改同一条记录时,谁覆盖谁?
| 字段类别 | 同步方向 | 为什么这么定 |
|---|---|---|
| 工单号、创建时间、门店信息 | 单向写入:黑湖 → 我方 | 这是对方的主数据,我方只读不写,避免两边打架 |
| 工单状态流转 | 单向写入:黑湖 → 我方 | 状态机的解释权归对方,我方不参与判断 |
| 技术确认结论、尺寸与工艺参数 | 只回传摘要:我方 → 黑湖 | 回传的只是给对方看的摘要,不回传完整明细,避免黑湖侧被当成生产数据源 |
| 价格、成本、毛利 | 任何方向都不走 | 核心商业数据,绝不出我方边界 |
| 客户联系方式 | 脱敏后单向 | 第三方只需知道「送这一单」,不需要完整客户档案 |
先说概念。prod 写桥是把生产数据库(prod)与外层桥接层隔开的那一层:所有要写生产库的请求,必须经过写桥;禁止任何业务代码直接连库写表。
错误做法(直连写库):
业务服务A ─┐
业务服务B ─┼──直连──▶ prod MySQL ← 谁的 SQL 谁负责,没人知道
运维脚本 ─┘
正确做法(写桥收口):
业务服务A ─┐
业务服务B ─┼──▶ prod 写桥 ──▶ prod MySQL
外部集成 ─┘ │
├─ 统一鉴权 / 参数校验
├─ 统一幂等键
├─ 统一审计日志(谁、什么时候、改了什么)
└─ 统一限流与失败告警
写桥本身不碰业务逻辑,它是边界层。它存在的唯一理由是:让「谁能写生产数据」这个问题有唯一答案。
这张表是我在项目里实际落地并和运维对齐过的版本,交付时直接给客户看:
| 角色 / 通道 | 读生产数据 | 写生产数据 | 必须走的路径 | 留痕要求 |
|---|---|---|---|---|
| 应用服务(后端业务代码) | ✅ 走只读副本或主库只读连接 | ✅ 允许 | 必须经prod 写桥,走内部服务间认证 | 写桥记录操作人、业务ID、变更前后值 |
| 运维脚本(修数据、导数据) | ✅ | ⚠️ 原则上不允许;确需时走工单审批 | 只读脚本直接连;写操作走写桥的运维通道并绑定审批单号 | 脚本名、执行人、审批单号、影响行数,全部落审计表 |
| 外部集成(黑湖、第三方 SaaS) | ❌ 不可直连 | ❌ 绝不允许 | 只经对外 API 通道,写桥内部再落库 | 按外部系统ID 记录来源,支持按来源反查和回滚 |
| 任何人 | 按需申请 | 🚫 不得直连改表 | —— | —— |
集成出问题,八成不是代码写错,而是边界没管住。这四条是硬要求,不是最佳实践。
这五类是我见过的失败原因排序,括号里是我认为最值得警惕的一项。
| 原因 | 表现 | 对策 |
|---|---|---|
| 没有真实联调环境 | 对方只给了一个测试账号,字段结构和生产完全不同,联调通过、上线即挂 | 开工前必须拿到真实环境或与生产同构的环境,拿不到就把「环境差异风险」写进报价单 |
| 依赖对方排期 | 你的开发做完了,对方接口还没好,整个项目停在那里等你,但延期责任在你 | 合同里写清对方配合事项是前置条件,并约定顺延规则;关键路径上不要只排一条路 |
| 字段语义不一致(括号里最隐蔽的一项) | 同一个「厚度」,我方按毫米、对方按厘米;同一个「数量」,一方按件一方按套。接口返回 200,数据全错 | 做字段映射表并逐字段确认口径:单位、量纲、时区、是否含税、是否含包装。语义对齐必须在编码前做完 |
| 没有对账机制 | 双方数据谁也不对谁,月底对账才发现差了三个月的数据 | 集成第一天就定对账口径和频率:行数、金额、关键状态。详见模块 11 的对账表 |
| 失败静默(括号里最致命的一项) | 接口返回成功,但实际什么都没写进去——因为异常被 try/catch 吞了,或者对方内部失败了却仍返回 200 | 写操作必须回读校验:写完立刻按业务键查一次,查不到就记为失败并告警。绝不把「返回 200」等同于「成功」 |
我的核心观点是:集成的工作量不是「对接」,是「对齐」。调通接口通常只占两成,剩下八成是对齐字段语义、对齐状态、对齐异常、对齐责任、对齐验收口径。所以我报价按对齐的工作量估,不按接口数量估。
第一步不是写代码,是接口探查。开工前我必须能答出五个问题:对方有没有 API、文档稳不稳、谁有改动权限、数据以谁为准、出错谁负责。这五个里只要有一个答不上来,我就不开工——先做一轮探查,产出接口清单、字段映射表、权限责任矩阵。这五个问题答不上来就签固定总价,等于替对方的历史包袱买单。
第二步选路径,顺序是:能用 API 不用文件,能用文件不用 RPA,RPA 是最后手段。原因很实在——前两者出问题能查能重跑,RPA 出问题我连它为什么错都要问一遍;而且 RPA 一定要在合同里写明是临时方案,界面一改版就失效。
举个我真实做过的例子:德莉玛门店订购系统要做经销商门店远程双签,让门店在手机上签认订单和工单。我把签认拆成两个节点——门店签在前、技术确认在后,后一个必须看到前一个的明细快照,节点之间有前置依赖,任一节点撤回下游自动失效。这里真正花时间的不是接口,是三个业务问题:谁在什么状态下可以签、签了能不能撤、纠纷时以谁为准。这三条开工前不和业务方逐条确认,代码写得再对也留不住证据。
另一个例子是黑湖小工单集成。黑湖是第三方生产工单 SaaS,我定的原则是先定清楚哪些字段走哪个方向:工单号、创建时间、门店信息、状态流转全部单向从黑湖写入我方;技术确认结论只回传摘要,不回传完整明细;价格成本毛利任何方向都不走;客户联系方式脱敏后单向。凡是需要双向写同一个实体的字段,一律先停下来问「两边同时改听谁的」——这问题问不清楚,说明业务规则没想清楚,代码写了也是错的。
这里我想重点讲一下 prod 写桥边界治理,因为这是我在架构上最坚持的一件事。prod 写桥是把生产数据库和外层桥接层隔开的那一层:所有要写生产库的请求必须经过写桥,禁止任何业务代码直连连库写表。写桥本身不碰业务逻辑,它是纯边界层,存在的唯一理由是让「谁能写生产数据」这个问题有唯一答案。业务服务可以经写桥写,运维脚本原则上只读、确需写入要绑审批单号,外部集成只经对外 API 通道,任何人不得直连改表。
为什么不直接让业务服务连库?因为服务一多,SQL 就散在各处,出事根本查不到是谁改的。走桥之后我就能立刻回答三个问题:是谁改的、什么时候改的、能不能回滚——审计日志里都有。顺带在桥上统一挂幂等键、参数校验、限流和失败告警,这是收口带来的额外收益。数据库直读这个模式我的态度是:只读可以,写绝对不行。第三方拿到整库权限,今天读订单明天就能读价格,今天是合作方,明天可能是竞品。
最后是四条必守的红线:一要可观测,每次调用有日志、失败有告警,因为集成故障最贵的形态是「失败了但没人知道」,可能三天后才发现数据已经错了三批;二要幂等,重复调用不能产生重复单据,因为网络重试、消息重投、定时补偿都会触发重复调用,那是常态不是异常;三是不越权,第三方只能拿它该拿的字段,价格成本和完整客户档案在对外通道里默认拿不到;四是要能降级,判断标准很简单——把对方接口全断掉,我的主流程还能不能出结果?不能就不合格。
一句话收口:集成治理的核心是对齐,不是对接。技术手段都可以换,但这五问、四条红线和那张写权限表是我认为真正能复用到下一个项目的东西。