架构优化:模块职责拆分建议 #82

Closed
opened 2026-04-24 09:52:03 +00:00 by xingyue · 1 comment
Owner

背景

对当前工程结构做了一次架构 review,整体三层分包(core → daemon → cli)方向正确,依赖图健康无循环。以下是发现的优化点。

当前代码分布(更新至 ef38b12)

Package LOC (非测试) 占比
daemon ~4,000 57%
cli ~2,480 35%
core 537 8%

daemon 与 core 的比例为 7.4:1,daemon 仍然过胖。

最新变化影响(b033a98 → ef38b12)

最近的 PR 做了一次 workflow 类型系统大重构

  • 旧模型(RFC-002 event-sourced CommandEvent[] 回放)→ 新模型(signal-driven automaton WorkflowMessage[] + typed Moderator<M>
  • Workflow 触发方式从 Reflex 改为 Sense 返回值直接触发,删除了 WorkflowReflexConfig
  • 新增 core/src/sense-workflow-directive.ts(76 LOC),把路由逻辑(routeSenseComputeOutput())下沉到 core

对各优化项的影响见下方。

问题与建议

P0:拆分 nerve-store ⚠️ 更加紧迫

daemon 包在本轮变更中 净增 ~200 LOC

  • log-store.ts 膨胀到 702 LOC(+123),增加了新旧格式兼容解析(thread_command_event / thread_workflow_message 双格式)
  • workflow-manager.ts 膨胀到 634 LOC(+94),新增 typed launch params
  • 存储层(log-store、log-archive、blob-store)现在约 ~900 LOC

CLI 的 daemon-types.ts 仍在手动复制类型(字段从 event 改名为 message,但依然是 "Keep in sync" 注释 + 手抄)。随着 workflow 类型系统变复杂,这个同步炸弹风险在增大。

拆分收益不变:

  • CLI 读日志/blob 可直接引用 store 包,不需要走 daemon IPC
  • 消除 daemon-types.ts 的手动类型复制
  • daemon 包瘦身,职责更清晰

P1:拆分 kernel.ts(God Object)🟢 略有改善

kernel.ts 目前 617 LOC,本轮变更:

  • Signal 路由逻辑已抽到 core 的 routeSenseComputeOutput()
  • Reflex 不再负责触发 workflow(删除 workflowTriggerFn),减少了一个职责

但 kernel 仍然同时负责:配置加载/热重载、Worker 进程生命周期管理、Signal 路由分发、IPC server 启停、文件监听。建议继续拆分 worker 生命周期管理。

P2:明确 core 包的定位 🟢 有进展

core 从 455 LOC 增长到 537 LOC:

  • 新增 sense-workflow-directive.ts(76 LOC)—— 真正的领域行为逻辑
  • types.ts 大幅重构,workflow 类型系统更丰富(泛型 Role<Meta>Moderator<M>START/END 哨兵值等)
  • exports 从 ~15 项增长到 ~22 项

方向是对的——core 正在从"纯类型壳子"向"包含核心领域逻辑"演进。继续观察,如果后续更多行为逻辑下沉到 core,P2 可以降级。

做得好的地方(保持)

  • 进程隔离:sense/workflow 都是 fork,互不影响
  • CLI 动态加载 daemon:避免构建时循环依赖
  • CAS blob-store + append-only log-store:存储设计干净
  • 单向依赖图:无循环依赖
  • 新增:路由逻辑下沉到 core,职责分层方向正确

Phases

  • #85 Phase 1: 拆分 @uncaged/nerve-store
  • #86 Phase 2: 拆分 kernel.ts — 抽离 worker 生命周期管理
  • #87 Phase 3: 明确 core 包定位
## 背景 对当前工程结构做了一次架构 review,整体三层分包(core → daemon → cli)方向正确,依赖图健康无循环。以下是发现的优化点。 ## 当前代码分布(更新至 ef38b12) | Package | LOC (非测试) | 占比 | |---------|-------------|------| | daemon | ~4,000 | 57% | | cli | ~2,480 | 35% | | core | 537 | 8% | > daemon 与 core 的比例为 7.4:1,daemon 仍然过胖。 ## 最新变化影响(b033a98 → ef38b12) 最近的 PR 做了一次 **workflow 类型系统大重构**: - 旧模型(RFC-002 event-sourced `CommandEvent[]` 回放)→ 新模型(signal-driven automaton `WorkflowMessage[]` + typed `Moderator<M>`) - Workflow 触发方式从 Reflex 改为 Sense 返回值直接触发,删除了 `WorkflowReflexConfig` - 新增 `core/src/sense-workflow-directive.ts`(76 LOC),把路由逻辑(`routeSenseComputeOutput()`)下沉到 core **对各优化项的影响见下方。** ## 问题与建议 ### P0:拆分 nerve-store ⚠️ 更加紧迫 daemon 包在本轮变更中 **净增 ~200 LOC**: - `log-store.ts` 膨胀到 702 LOC(+123),增加了新旧格式兼容解析(`thread_command_event` / `thread_workflow_message` 双格式) - `workflow-manager.ts` 膨胀到 634 LOC(+94),新增 typed launch params - 存储层(log-store、log-archive、blob-store)现在约 **~900 LOC** CLI 的 `daemon-types.ts` **仍在手动复制类型**(字段从 `event` 改名为 `message`,但依然是 "Keep in sync" 注释 + 手抄)。随着 workflow 类型系统变复杂,这个同步炸弹风险在增大。 拆分收益不变: - CLI 读日志/blob 可直接引用 store 包,不需要走 daemon IPC - 消除 `daemon-types.ts` 的手动类型复制 - daemon 包瘦身,职责更清晰 ### P1:拆分 kernel.ts(God Object)🟢 略有改善 kernel.ts 目前 617 LOC,本轮变更: - Signal 路由逻辑已抽到 core 的 `routeSenseComputeOutput()` - Reflex 不再负责触发 workflow(删除 `workflowTriggerFn`),减少了一个职责 但 kernel 仍然同时负责:配置加载/热重载、Worker 进程生命周期管理、Signal 路由分发、IPC server 启停、文件监听。建议继续拆分 worker 生命周期管理。 ### P2:明确 core 包的定位 🟢 有进展 core 从 455 LOC 增长到 537 LOC: - 新增 `sense-workflow-directive.ts`(76 LOC)—— 真正的领域行为逻辑 - `types.ts` 大幅重构,workflow 类型系统更丰富(泛型 `Role<Meta>`、`Moderator<M>`、`START`/`END` 哨兵值等) - exports 从 ~15 项增长到 ~22 项 方向是对的——core 正在从"纯类型壳子"向"包含核心领域逻辑"演进。继续观察,如果后续更多行为逻辑下沉到 core,P2 可以降级。 ## 做得好的地方(保持) - 进程隔离:sense/workflow 都是 fork,互不影响 - CLI 动态加载 daemon:避免构建时循环依赖 - CAS blob-store + append-only log-store:存储设计干净 - 单向依赖图:无循环依赖 - ✅ 新增:路由逻辑下沉到 core,职责分层方向正确 ## Phases - [x] #85 Phase 1: 拆分 `@uncaged/nerve-store` - [ ] #86 Phase 2: 拆分 kernel.ts — 抽离 worker 生命周期管理 - [ ] #87 Phase 3: 明确 core 包定位
Owner

Review 意见

P0 拆分 nerve-store 强烈同意

最值得做。cli/src/daemon-types.ts 手抄类型是真正的隐患——daemon 侧改接口编译不报错、运行时才炸。

补充:

  • store 包应同时 export 类型和实现:CLI import 类型 + 只读 API,daemon import 完整读写 API
  • blob-store 和 log-store 如果有耦合(如 log entry 引用 blob hash),拆的时候要一起带走

P1 拆分 kernel.ts 🟡 同意但需细化

610 行 God Object 该拆,但建议先画出 kernel 内部调用关系图再决定切割线。worker 生命周期和 Signal 路由如果强耦合,简单拆文件只是把 God Object 变成两个互相调用的文件,没解决问题。目标是拆完后模块间接口清晰,不是单纯减少行数。

P2 core 包定位 🟡 倾向方向 2

建议走方向 2:重命名为 nerve-sharednerve-types,明确只做共享类型 + 工具函数层。方向 1 容易变成什么都往里塞的垃圾桶。

缺失项

  1. 执行顺序:P0 → P1 → P2 OK,但明确 P0 是否 block P1,不 block 可以并行
  2. 迁移策略:P0 拆 store 涉及 3 个包的 import 路径变更,建议一个 PR 搞定,避免中间态编译不过
  3. 测试覆盖:拆之前确认 store 层现有测试覆盖率,拆完后测试跟着走;没测试的趁拆的时候补上
## Review 意见 ### P0 拆分 nerve-store ✅ 强烈同意 最值得做。`cli/src/daemon-types.ts` 手抄类型是真正的隐患——daemon 侧改接口编译不报错、运行时才炸。 **补充:** - store 包应同时 export 类型和实现:CLI import 类型 + 只读 API,daemon import 完整读写 API - blob-store 和 log-store 如果有耦合(如 log entry 引用 blob hash),拆的时候要一起带走 ### P1 拆分 kernel.ts 🟡 同意但需细化 610 行 God Object 该拆,但建议**先画出 kernel 内部调用关系图**再决定切割线。worker 生命周期和 Signal 路由如果强耦合,简单拆文件只是把 God Object 变成两个互相调用的文件,没解决问题。目标是拆完后模块间接口清晰,不是单纯减少行数。 ### P2 core 包定位 🟡 倾向方向 2 建议走方向 2:重命名为 `nerve-shared` 或 `nerve-types`,明确只做共享类型 + 工具函数层。方向 1 容易变成什么都往里塞的垃圾桶。 ### 缺失项 1. **执行顺序**:P0 → P1 → P2 OK,但明确 P0 是否 block P1,不 block 可以并行 2. **迁移策略**:P0 拆 store 涉及 3 个包的 import 路径变更,建议一个 PR 搞定,避免中间态编译不过 3. **测试覆盖**:拆之前确认 store 层现有测试覆盖率,拆完后测试跟着走;没测试的趁拆的时候补上
This repo is archived. You cannot comment on issues.
No Label
2 Participants
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: uncaged/nerve#82