Browse Source

docs(adr): 架构审查候选 #3/#4/#5 重评结论(均不做)

/improve-codebase-architecture 报告余下三候选,#1/#2 落地后逐一重评(/grilling):

- #5 oplog recorder:已被 #1 (ADR-0030) 吸收——两处手搓 writeInitialOplog
  随建档机制收敛,现仅 OpportunityIntakeImpl 一处;ADR-0030 记闭环,不立票
- #4 LeadOpportunityConverter:仍不抽——port 侧已瘦成薄 adapter,预期的
  事务/补偿复杂度未现,依旧单调用者无杠杆;两处手搓守卫是转商机两阶段时序
  的刻意前置拦截、非坏味道;ADR-0022 §4 记重评
- #3 DisplayNameEnricher:不抽——真孪生仅 dictNames 10 行,三源 enricher
  会是宽接口+薄实现的 shallow module,与深模块目标相悖;ADR-0022 §4 记重评
master
luoweijian 2 weeks ago
parent
commit
7417b835e2
  1. 4
      docs/adr/0022-lead-module-read-write-separation-deep-modules.md
  2. 2
      docs/adr/0030-opportunity-intake-deep-module.md

4
docs/adr/0022-lead-module-read-write-separation-deep-modules.md

@ -63,6 +63,10 @@ List<LeadHistoryDTO> listHistory(Long leadId); // 历史时间线(VISI
拆完后 `LeadServiceImpl` 只剩**写侧命令编排**。剩余命令若强按 command 三分只会造 shallow 转发层。唯一还算深的候选 `convertToOpportunity`(端口协调 + 事务边界 + 幂等前置)目前只有单一调用点、约 45 行,抽独立协调器 earns 不到 keep——**推迟到商机模块落地、事务/补偿变复杂时再抽**(届时它才够深)。
> **重评(2026-08-25,`/improve-codebase-architecture` 候选 #4 + `/grilling`):仍不抽。** 触发条件(商机模块已落地)虽至,但 [ADR-0030](0030-opportunity-intake-deep-module.md) 将建档机制收进商机侧深模块 `OpportunityIntake` 后,`convertToOpportunity` 的对端(outbound port 实现)已瘦成薄 adapter,当初预期的「事务/补偿变复杂」未在 crm-lead 侧出现:异常翻译只一层、事务就是方法上一个 `@Transactional`。依旧单一调用者(无杠杆)、隔离价值不足,抽出主要是搬家而非建深模块。方法内两处手搓守卫(状态 3/4 + 持有人)**非坏味道**:转商机是「先建商机、后迁状态」两阶段时序,守卫必须在 port 调用**前**拦截(避免商机已建而线索状态未改),而 `ConvertCmd` 的声明式 guard 在 port **后**才跑、挡不住此处;口径已由 `LeadConstants` 常量单一来源,手搓的只是判断、非复制口径。若将来真出现多调用者或跨库补偿事务,本条再重开。
> **重评(2026-08-25,`/improve-codebase-architecture` 候选 #3 + `/grilling`):不抽 `DisplayNameEnricher`。** 两个读模块 `LeadViewQueryImpl` / `OpportunityViewQueryImpl` 的 code→name 回显中,真逐字复制的只有 `dictNames(groupCode, codes)` 那 10 行(循环调 `DictQueryService.getItem` + 攒 Map);dept/region 的 `listByIds`/`listByCodes`→`toMap` 是 MyBatis-Plus/stream 惯用法,无抽取价值。统管 dict+dept+region 三源的 enricher 会是**宽接口 + 薄实现**(每个 caller 需描述「哪些字段→哪个组码/哪种源」)——正是 shallow module 的定义,与本 ADR 追求的深模块相悖。seam 唯一合法落点也只有 crm-rule(聚齐 dict/auth/region 三源、被两读模块依赖不成环),但落点合法不等于值得建。维持现状;若将来第三个视图模块再次复制 `dictNames`,则优先把那 10 行收进 `DictQueryService.batchNames`(零新增 seam,两侧本已依赖 crm-dict)而非建 enricher。
## Consequences
- **LeadServiceImpl 瘦身**:530 → **437 行**,11 → **8 依赖**(移走 5:`objectMapper`/`leadHistoryMapper`/`sysRegionService` + 2 死依赖 `leadAttachmentMapper`/`sysDeptService`;新增 `leadViewQuery`),职责收敛为单一的「写侧命令编排」。

2
docs/adr/0030-opportunity-intake-deep-module.md

@ -40,5 +40,5 @@ status: accepted
- **BUG 修正随迁**:线索转商机路径 `oppSource` 恒落 `opp_source_01`(守护测试 `open_leadConvert_setsOppSource`),产品口径自此在代码成立。
- 测试 replace 不 layer(ADR-0022/0026 先例):机制断言上移 `OpportunityIntakeImplTest`(12 例,两来源分支全覆盖),adapter 测试只留翻译断言(port 2 例 + service 4 例);删机制用例不降覆盖。
- 术语沉淀:`crm-opportunity/CONTEXT.md` 新增「商机建档」「进入方式」。
- 候选 #2(`ILeadService` 泄漏 / `ConvertibleLeadCatalogPort`、#3(DisplayNameEnricher)、#4(LeadOpportunityConverter)、#5(oplog recorder)不在本票范围;将来若抽 oplog recorder,`writeInitialOplog` 是第一候选。
- 候选 #2(`ILeadService` 泄漏 / `ConvertibleLeadCatalogPort`已随后落地(见 [ADR-0031](0031-convertible-lead-catalog-port-seam.md))。候选 #3(DisplayNameEnricher)、#4(LeadOpportunityConverter)另行评估。**候选 #5(oplog recorder)已被本模块吸收**——两条入口原各自手搓的 `writeInitialOplog`(`new OpportunityOplog()` + 8 setter)随机制收敛,现仅存 `OpportunityIntakeImpl.writeInitialOplog` 一处;报告预判「likely folded into #1」成立,故 #5 不单独立票。将来若跨「建档初始日志 + 状态迁移历史」再抽统一 recorder,本方法仍是第一候选。
- 决策来源:`/improve-codebase-architecture` 审查(2026-08-25,候选 #1)+ grilled consensus;实现接力见 handoff `opportunity-intake-20260825`

Loading…
Cancel
Save