编码约定(模块边界、命名、错误处理、可测试性)

1) 目标

本约定的目标是让项目在持续迭代中保持:

  • 可读(容易理解)
  • 可改(容易扩展)
  • 可测(容易验证)
  • 可诊断(出问题容易定位)

2) 模块边界(建议的分层)

  • models/:领域模型 + 稳定编码/解析/展示逻辑(不要在这里写 SQL)
  • db/:SQL + 类型转换 + Repository(不要在这里写 UI)
  • services/:跨模块业务计算(偏离/收益等),避免页面堆业务逻辑
  • state/:全局状态(Signal Context),尽量保持“数据结构 + 少量纯函数”
  • pages/:页面级装配与数据流协调(加载/刷新/路由入口)
  • components/:可复用 UI 组件(尽量纯 props 驱动)
  • utils/:与业务无关的工具函数(格式化、通用 helper)
  • error.rs:统一错误类型 AppErrorAppResult<T>

3) 命名与可读性(贴近《代码整洁之道》)

  • 函数名优先用动词短语:
    • find_allfind_by_idset_active
  • 布尔变量表达意图:
    • is_activeinventory_mode
  • 避免缩写与魔法字符串:
    • 类别/口径/工具类型使用 enum + as_str/from_str

4) 错误处理(当前设计与改进方向)

项目已在 src/error.rs 定义统一错误类型:

  • AppError(使用 thiserror
  • type AppResult<T> = Result<T, AppError>

Repository 层(src/db/*_repo.rs)现已返回 AppResult<T>

原则:

  • 不要静默吞错(例如 row_to_xxx 中的 unwrap_or_default() 把脏数据变默认值,仍待改进)
  • 用户输入/DB/IO 必须返回 Result,不要 panic
  • 测试里可以 unwrap,但要保证失败信息可读(expect 更好)

5) 数据建模与持久化

原则:

  • DB 里存稳定编码(TEXT)
  • 模型负责提供编码 ↔ enum 的转换函数
  • 重要不变量写进模型(例如 Asset::validate() / 方案占比合计 100%)

6) Dioxus 组件与状态管理

建议:

  • 页面负责“加载/刷新”,组件负责“渲染/交互”
  • 尽量不要在渲染路径写 state(优先 use_effect
  • 缩小 .read() / .write() 的借用作用域,避免借用冲突

7) 测试策略(学习期可从最小集开始)

建议从两类测试开始:

  • 模型纯函数测试AssetSubCategory::from_codeCategory::from_str、收益/偏离计算
  • DB 集成测试:设置 ASSET_LIGHT_DB_PATH 指向临时文件,跑 init_database,验证 CRUD

目标不是追求覆盖率,而是建立“重构有安全网”的能力。