Appearance
数据存储、语义与追溯设计(V10)
数据设计不是“最后选个 CSV 还是数据库”。更重要的是:这个值是什么、来自哪里、用什么单位、什么时候写、写失败后系统做什么、以后还能不能证明当时发生了什么。
V10 同样不要求每次改一个导出列都重新设计整个存储体系。
1. 先分任务
| 当前任务 | 推荐路径 |
|---|---|
| “这个字段现在保存到哪里?” | Read-Only Trace |
| 增加/修改一个明确导出列 | Execution / MicroPatch |
| 修改一个正式阈值/单位并影响存储 | DomainConstraint / Measurement Semantics |
| “旧版本记录正常,新版单位错了” | RegressionFix |
| 修改 Schema、历史兼容、迁移规则 | Execution + V2/V4 compatibility |
| 新系统的数据/追溯方案 | Discovery / Data Design |
小改只沿当前字段的数据链追踪,不全库扫描所有数据库和文件。
2. 先分清 6 类数据,不要全部叫“测试数据”
| 类型 | 示例 | 重点 |
|---|---|---|
| RawData | 原始报文、ADC、示波器原始峰值 | 是否能复盘底层事实 |
| EngineeringData | A、V、℃、mm 等工程量 | Conversion、单位、精度 |
| DerivedResult | 平均、峰值、判定、统计结果 | 算法版本、阈值来源 |
| Configuration | 参数、通道、范围、阈值 | owner、版本、兼容、回退 |
| OperationalLog | 用户操作、状态变化 | 谁、何时、做了什么 |
| DiagnosticEvidence | 错误码、SCPI、协议原文、堆栈 | 现场定位与证据等级 |
同一个项目可以只保存其中一部分,但要明确这是设计选择,不要无意间混在一起。
3. RawValue 和 EngineeringValue 不能互相冒充
典型链:
text
RawValue
→ Decode
→ Conversion
→ EngineeringValue
→ Aggregation / Threshold
→ Result
→ Display / Save / MES例如:
text
Scope RawPeak = 0.125 V
Sensitivity = 0.005 V/A
EngineeringCurrent = 25 A日志如果只写:
text
原始电流 = 0.125 A就已经失去语义真实性。
涉及测量值时至少核对:
text
RawValue
EngineeringValue
Conversion
ThresholdBasis
Aggregation
LoggedUnit完整方法见 测量值语义。
4. 一条关键结果最好能回答“怎么算出来的”
推荐追溯链:
text
Test / Task Id
→ Parameter Version
→ Device / Channel
→ Raw Evidence
→ Conversion
→ Engineering Data
→ Algorithm / Threshold
→ Event / Operator Action
→ Final Result并不是所有项目都必须永久保存全链。
但如果某个结果用于:
- 客户验收;
- 质量追溯;
- 故障分析;
- 测试判定;
- 安全联锁;
就应该能说明证据保留到哪一层。
5. Timestamp 先确定“谁的时间”
常见来源:
text
HostTime
DeviceTime
ExternalSystemTime
AcquisitionIndex不要看到一个 DateTime.Now 就默认它是测量发生时间。
例如设备带自己的采样时间,而上位机晚 200 ms 收到数据:
text
DeviceTimestamp = 测量发生时间
HostReceiveTime = 上位机收到时间两者都有价值,但语义不同。
对于高频数据,如果真实顺序比墙钟时间更重要,还应保留 sequence/index。
6. 保存失败的后果必须显式定义
“保存失败”也不是固定等于“停止测试”。
可以是:
text
Information
AlarmOnly
Advisory
InterlockFault例如:
原始调试日志保存失败
可能是:
text
AlarmOnly
→ 当前测试继续
→ 提示维护人员法规/质量要求规定测试结果必须落盘
可能是:
text
InterlockFault
→ 不允许把本轮标记为有效完成后果必须来自业务要求,而不是由 IOException 自己决定。
详细语义见 行为与告警语义。
7. 文件还是数据库:先看访问方式,不看“哪个更高级”
CSV / JSON / 二进制文件适合
- 一次测试一份结果;
- 查询简单;
- 现场需要人工复制/查看;
- 部署要简单;
- 原始波形/大块数据天然是文件。
SQLite 适合
- 单机应用;
- 需要条件查询;
- 数据关系不复杂;
- 不想部署服务端数据库。
PostgreSQL / MySQL 等适合
- 多客户端;
- 集中查询;
- 业务已有数据库平台;
- 需要权限、事务或统一运维。
不要为了一个“历史列表”就自动引入服务端数据库。
8. Source of Truth:同一个参数不要四处都是权威值
例如一个最大电流:
text
XAML 默认值
ViewModel 常量
appsettings.json
数据库配置表
MES 下发
设备能力如果都能改,迟早不一致。
需要明确:
text
DomainConstraint Owner
External Contract
Device Capability
User Override正式范围变化参考 业务约束跨层传播。
9. 配置数据需要区分“用户偏好”和“业务规则”
例如:
| 配置 | 类型 |
|---|---|
| 窗口宽度 | UserPreference |
| 曲线刷新间隔 | Display/Performance Setting |
| 最大允许高压 | DomainConstraint / DeviceCapability |
| 调试模式临时上限 | EngineeringOverride |
| MES 字段单位 | ExternalContract |
这决定:
- 是否需要版本;
- 是否需要迁移;
- 是否允许用户直接编辑;
- 是否传播到外部系统和设备。
10. 写入策略:别让保存线程反过来拖死采集
需要回答:
text
WriteMode: immediate / batch / end-of-test
BufferCapacity:
Backpressure:
FlushPolicy:
StopPolicy:
FailureConsequence:例如高频原始数据:
text
采集
→ bounded queue
→ batch writer
→ file满队列时到底:
- 阻塞采集;
- 丢弃数据;
- 降采样;
- 报警;
- 停止测试;
属于业务决策,不能由 ConcurrentQueue 默认行为代替。
资源生命周期详见 线程、设备会话与资源生命周期。
11. 文件完整性:写成功和结果完整不是一回事
至少考虑:
- 中途断电;
- 软件异常退出;
- 文件被占用;
- 临时文件未 rename;
- Flush 未完成;
- 一次测试只写了一半;
- 导出时读取到仍在写的文件。
根据重要性选择:
text
temp + atomic replace
append + record framing
transaction
checkpoint
end marker / completed flag不要对普通调试日志过度设计事务;也不要让正式验收结果只靠“文件存在”判断完整。
12. Schema / 字段语义变化要考虑历史兼容
如果改变:
- 字段名;
- 数据类型;
- 单位;
- 枚举值;
- JSON/XML schema;
- CSV 列顺序;
- 数据库字段;
先问:
text
旧数据要不要继续读?
旧配置要不要兼容?
旧版本软件是否会读新文件?
新版本是否要展示旧结果?
外部系统契约是否允许变化?内部表示变化不等于外部格式必须变化
例如内部从分钟统一为秒:
text
Internal = seconds
Existing file/MES contract = minutes完全可以通过边界转换保持兼容。
13. RegressionFix:数据问题以前正常就比较同一字段的全链
用户说:
text
以前导出的电流是对的,这版变成小数值了先比较:
text
KnownGood Raw
→ Conversion
→ DTO/Model
→ Saved Field
→ Display/Export再看最近 changed files。
优先找第一个语义差异,不要先把整个数据层重构。
14. 操作日志和诊断日志用途不同
OperationalLog
面向追溯:
text
谁
何时
做了什么
参数是什么
结果是什么DiagnosticDetail
面向定位:
text
底层命令
原始响应
异常类型
错误码
堆栈
session
时间线操作员主界面可以只展示摘要,原始诊断仍应保留到维护日志。见 操作员界面与维护诊断分层。
15. 新系统最小数据字典
text
Field
BusinessMeaning
Source
RawOrEngineering
Type
Unit
Precision
TimestampSource
Persistence
Export
Compatibility
Notes示例:
text
ChargeCurrent
充电阶段工程电流
Scope CH2
Engineering
float
A
0.01
HostReceiveTime + SampleIndex
Result CSV
Yes
V1+
Raw voltage stored separately for diagnosis不要只写“float current”。
16. 数据保存验证按风险选
V1
纯导出格式/列标题:
- 生成一份文件;
- 列名/格式正确;
- 原业务数据不变。
V2
数据语义、配置、数据库、兼容:
- known input → expected stored value;
- 单位/Conversion;
- roundtrip;
- 旧配置/旧记录(若相关);
- save failure path。
V3
保存后果影响测试流程:
- 保存失败时是否继续/停止;
- 流程状态和结果有效性;
- stop 时 queue drain;
- workflow smoke。
V4
Schema/外部契约/发布兼容变化:
- migration;
- old/new compatibility;
- representative historical data;
- external consumer acceptance。
17. 两个可直接复制的 Prompt
查一个字段现在怎么保存
text
$host-computer-dev
只做 Read-Only Trace。
字段/数值:
【填写】
请追踪:
Source → Raw/Engineering → Conversion → Model/DTO → Persistence/Export → Unit。
说明当前 timestamp 来源和最终保存位置。
不要修改代码、构建或分析整个数据库。修改一个数据字段/规则
text
$host-computer-dev
这是一个已明确的数据修改。
CurrentBehavior:
RequestedBehavior:
NonGoals:
请先判断是否涉及:
- Measurement Semantics;
- DomainConstraint;
- Schema/Compatibility;
- External Contract。
只沿相关字段的数据链修改,不重构无关存储模块。
完成后按 V1–V4 选择 focused verification;如果旧数据兼容不相关,不要自动设计迁移。18. 常见反模式
| 反模式 | 后果 |
|---|---|
| Raw 和工程量字段名混用 | 日志/追溯失真 |
| 保存失败一律 Stop | 非关键日志故障阻断试验 |
| 所有配置都当 DomainConstraint | 小设置变成跨层重流程 |
| 内部单位变化机械修改外部格式 | 破坏兼容 |
| 一次测试文件存在就算完整 | 半文件被当有效结果 |
| 无界保存队列 | 长稳内存增长 |
| 一个字段修改全数据库扫描 | 小改成本失控 |
| 只保存最终判定、不保留关键证据 | 现场无法复盘 |
下一步
一句话原则
先保证数据语义真实,再决定怎么存;保存失败的业务后果要显式定义,兼容只在实际相关时做。