Files
osmWorkflow/.trellis/spec/guides/code-reuse-thinking-guide.md

162 lines
6.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 代码复用思考指南
> 目的:在新增 helper、常量、配置字段或枚举表之前先判断这个项目里"应该复用"和
> "刻意重复"的边界。这里的关键不是追求抽象,而是避免事实漂移。
---
## 先搜索,再决定
改任何值或新增类似逻辑前先跑:
```bash
grep -rn "关键字或现有值" scripts blender config
```
本项目的重复有两类:
- **危险重复**:同一事实被多处维护,漏改会静默错产物
- **可接受重复**:运行时边界不同或独立入口需要保留,抽象会扩大耦合
判断之前不要凭直觉抽取。
---
## 必须复用的事实源
### 九个 osm2streets 图层
JS 侧只认 `scripts/lib/scene-layers.js:15``SCENE_LAYERS`
需要文件名、合并场景、style JSON、QGIS 颜色时,使用同文件导出的派生函数:
- `layerFile(layer)``scene-layers.js:103`
- `mergeScene(getCollection)``scene-layers.js:109`
- `sceneStyle()``scene-layers.js:126`
- `qgisRgba(hex, alpha)``scene-layers.js:143`
不要在 `build-osm2streets-qgis.js``reimport-gpkg.js` 或 QGIS 项目生成代码里再枚举
九个图层。旧问题正是同一顺序复制到四处,漏一处不报错,只让 Blender/Cesium 场景错栈。
Python 侧必须有 `blender/osmassets/catalog.py:28``ROAD_LAYERS`,因为它还声明
Blender 高度与线性颜色。两侧靠 `catalog.check_layers()` 对账集合和顺序;颜色故意不同步。
### 区域输出路径
输出路径只在 `scripts/build-area.js:74``normalizeAreaConfig()` 推导。
低层脚本读取 `_pipeline/osm2streets-qgis.config.json`,不要重新读取
`config/areas/*.json` 或在阶段函数里现场拼路径。
新增产物时,在 `normalizeAreaConfig``outputs` 里加一项,再按需写入
`writeDerivedConfig()``build-area.js:189`)。这样 `intermediates``reimport`
`blender``cesium``preview` 仍然只通过磁盘产物耦合。
### 材质声明
Blender 内材质声明集中在 `catalog.MATERIALS``catalog.py:56`)。
真实 `bpy.types.Material``materials.from_spec()``materials.py:198`)构建。
Cesium 导出调色也属于同一个材质声明:新场景把 `catalog.MATERIALS[*]["cesium"]`
序列化到 `material["cesium_export"]``export_cesium.py` 优先读这个属性。四张
`export_cesium.py` 材质名表仍存在,但只作为旧 `.blend` 的兼容回退。
改材质名时不能只改 `catalog`;必须全仓 grep 材质名,确认新契约和旧回退路径都合理。
---
## 可接受的重复
### 三份 `parseArgs`
`parseArgs` 现在重复在三个独立入口:
- `scripts/build-area.js:50`
- `scripts/build-osm2streets-qgis.js:153`
- `scripts/reimport-gpkg.js:93`
语义一致:`--kebab-case value``kebabCase: "value"`,无值 flag 变字符串 `"true"`
这份重复目前是可接受技术债,因为三个脚本都能独立运行。改其中一处解析语义时,不要顺手
只改一份;要么保持三份一致,要么把"抽公共模块"作为独立重构并跑 parity。
### JS 与 Python 的图层颜色
`scene-layers.js` 的颜色是 QGIS 2D 调试 sRGB hex`catalog.py` 的颜色是 Blender
线性 RGB。`catalog.py:11-15` 明确说颜色不是同步目标。
把两边颜色抽成同一个表不是复用,是破坏两个运行时各自调过的视觉结果。
---
## 重复模式检查
### 看到第二份枚举表
问:
- 这份表是否已经能从 `SCENE_LAYERS``ROAD_LAYERS``MATERIALS` 或配置派生?
- 如果必须跨语言重复,是否已有对账机制?
- 追加顺序是否影响 GLB 材质索引?
没有对账机制的重复表必须特别谨慎。材质名覆盖就是当前已知风险:
`generate_scene.py` 创建材质,`export_cesium.py` 靠字符串覆盖,没有校验。
### 看到多个模块同样预处理
`water.py:9``grass.py:9``scrub.py:8` 都调用 `clip_polygon`,这是对要素模块签名的
统一要求:模块接收边界、自己裁剪、退化输入返回 0。
新增第四个要素模块时先照这个形状写,不要把裁剪逻辑上移到调用方。否则旧模块和新模块
的边界会不同,真实 OSM 的越界几何会按要素类型表现不一致。
### 看到多个地方解析同一格式
优先找已有解析器:
- OSM XML → `osmassets/osm.py:parse_osm()`
- 米制几何 → `osmassets/geom.py`
- GeoJSON 场景合并 → `scene-layers.js:mergeScene(getCollection)`
- 区域配置 → `build-area.js:normalizeAreaConfig()`
如果确实需要新解析器,把输入格式、容错语义和调用者写清楚,并给纯 Python 逻辑补测试。
---
## 什么时候抽象
抽象只在满足至少一条时做:
- 同一事实会被三处以上消费,且有真实漏改风险
- 同一段校验逻辑跨多个入口影响产物安全
- 抽出来后能保留运行时边界,比如纯 Python 逻辑进入 `geom.py` 后可被
`python3 -m unittest discover blender/tests` 覆盖
不要因为代码相似就抽象:
- 三份 `parseArgs` 当前保持独立入口价值
- `ROAD_LAYERS``SCENE_LAYERS` 跨语言且承载不同字段
- 每个要素模块各自调用 `clip_polygon` 是模块边界,不是可消除重复
---
## 提交前自检
- [ ] 已 grep 关键值或新字段
- [ ] 没有新增第二份九图层枚举
- [ ] 没有在阶段函数里重新拼输出路径
- [ ] 改材质名时已检查 `catalog.py``generate_scene.py``export_cesium.py`
- [ ] 新纯几何逻辑放进 `geom.py` 并补 `test_pure.py`
- [ ] 声称产物不变的重构已按[产物一致性指南](./artifact-parity-guide.md)校验
---
## 反模式
| 反模式 | 后果 |
|---|---|
| 新增一份图层名列表 | 回到旧的四份同步,漏改静默错栈 |
| 把两套颜色表统一 | 破坏 QGIS 与 Blender 各自调过的视觉结果 |
| 低层脚本直接读 `config/areas/*.json` | 两层配置边界失效 |
| 只改一份 `parseArgs` 的语义 | 三个入口行为分裂 |
| 把要素模块裁剪逻辑挪到调用方 | 不同要素的越界处理开始漂移 |
| 只改 `export_cesium.py` 的旧回退表,不写 `MATERIALS[*]["cesium"]` | 新 `.blend` 不会携带 Cesium 导出契约 |