Initialize Trellis project guidelines
This commit is contained in:
158
.trellis/spec/guides/code-reuse-thinking-guide.md
Normal file
158
.trellis/spec/guides/code-reuse-thinking-guide.md
Normal file
@@ -0,0 +1,158 @@
|
||||
# 代码复用思考指南
|
||||
|
||||
> 目的:在新增 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`)构建。
|
||||
|
||||
注意当前有一个未完成迁移:`export_cesium.py:68`、`:80`、`:86`、`:95` 的四张表
|
||||
仍按材质名字符串匹配。改材质名时不能只改 `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` 的语义 | 三个入口行为分裂 |
|
||||
| 把要素模块裁剪逻辑挪到调用方 | 不同要素的越界处理开始漂移 |
|
||||
| 只在 `catalog.CESIUM_EXPORT` 加导出覆盖 | 当前不会生效;导出器没读它 |
|
||||
Reference in New Issue
Block a user