SOLID C++ ESP32
硬性限制
- 优先将文件控制在 400 行以内;当翻译单元出现多个职责时请拆分
- 每个类最多 约 30 个方法
- 优先将函数体控制在 约 60 行 以内(提取辅助函数)
- 禁止嵌套类 —— 将内部类型移至其自己的头文件/翻译单元
- 当项目选择启用时(启动/严格交付面),每个公开头文件 恰好包含一个 主要类型(
class/struct/enum/enum class)
语言与风格
- 所有提交的代码/注释/文档必须使用 英语
- 始终使用大括号包裹
if/for/while/switch - 非简单逻辑的函数体不得为单行
- 使用描述性名称(
telemetryManager,而不是mgr/tmp,除非是简单的循环索引) - 优先在每个翻译单元使用一个
namespace块 - 头文件声明意图;
.cpp文件保持简洁直接 - 公开方法(位于
I*.h接口及其他选中的公开头文件中)需要一行///意图注释
架构(SOLID + 依赖注入)
- 优先在领域边界使用 接口(
I*) - 在应用/领域代码中依赖抽象;仅在
main.cpp或显式的组合根中构造 具体适配器 - 硬件(BLE、Wi-Fi、显示、NVS、总线)应隐藏在接口之后,以便主机单元测试使用模拟对象 —— 而非使用
#ifdef进行手术 - 优先使用在
native/ 主机构建上可进行单元测试的小型纯解析器 - 优先使用组合而非不断膨胀的神对象
- 立即将 FreeRTOS 的
void*转换为具名类型指针 - 优先使用项目辅助函数(例如安全的 C 字符串拷贝)而非
strncpy变体
领域/层隔离
- 将仅集线器使用的栈(web、认证、OTA、HTTP API)排除在桥接/叶子目标之外
- 不要从错误的层
#include具体适配器头文件;如果护栏规则列出了适配器名称,请遵守它
生产 API 中不得含有测试仪器
生产代码 不得 被测试构建标志所影响。
- 头文件和
.cpp中禁止出现:UNIT_TEST、#ifdef UNIT_TEST、#ifndef UNIT_TEST、#if defined(UNIT_TEST)或任何等效的测试专用门控(esp_cpp_guardrails 默认强制禁止) - 优先使用依赖注入:提取一个接口,在主机测试中注入模拟对象,或 排除 设备适配器的翻译单元使其不参与
native/ 主机build_src_filter—— 绝不要用 ifdef 来桩化生产源代码 - 平台检测(
__has_include(<esp_random.h>)、ESP_PLATFORM)是可以的;但改变生产逻辑的测试构建标志则不行 - 在头文件中保留可移植类型(
std::mutex等),或在仅设备使用的翻译单元中包含无条件的设备头文件
气味 → 修复:
| 气味 | 修复 |
|---|---|
服务中围绕 Wi-Fi / BLE 调用使用 #ifndef UNIT_TEST | 注入 IWifiConnector / IBleClient;在主机测试中使用模拟对象 |
当 UNIT_TEST 时头文件桩化为不同类型 | 总是使用可移植类型,或拆分设备适配器 |
| 神类需要 ifdef 才能在主机上编译 | 拆分职责;组合根连接适配器 |
密钥
- 永远不要 在源代码中硬编码 Wi-Fi 密码、OTA / Web 密码、设备密钥、PMK、令牌或 LAN 凭据
- 通过环境变量/构建标志注入密钥(由 PlatformIO 或同等工具消费)—— 绝不要提交带有真实密钥的
.env
双核 FreeRTOS(ESP32)
经典 ESP32 有两个核心:
| 核心 | ID | 典型用途 |
|---|---|---|
| PRO_CPU | 0 | Wi-Fi / BT / 无线电相关工作(ESP-NOW 收发循环、BLE/SPP 无线电任务) |
| APP_CPU | 1 | 较重的应用工作:显示 UI、HTTP/Web、解析突发数据、SD 卡、非无线电循环 |
默认规则(仅在记录的特殊情况下覆盖):
- 使用
xTaskCreatePinnedToCore(..., kRadioCoreId)将无线电/栈敏感的任务固定到核心,其中kRadioCoreId = 0 - 将 UI/重载非无线电任务固定到
kAppCoreId = 1 - 避免在核心 0 上执行长时间的阻塞工作;这会饿死无线电栈
- 优先使用具名常量(
kRadioCoreId/kAppCoreId)而非魔数0/1
验证
- 在结构性更改后运行项目的护栏脚本(或
tools/esp_cpp_guardrails) - 添加最小的主机/单元检查,当新逻辑被破坏时能够失败
- 接口更改后要构建
- 当行为、脚本、硬件假设或架构发生变化时更新 README
- 当项目要求时,优先在合并前进行阻塞性代码质量审查
检查清单
- 大括号无处不在;标识符/注释使用英语
- 不超过约 400 行 / 约 30 个方法;无嵌套类
- 具体适配器仅在组合根处;领域依赖于
I* - 头文件中无
UNIT_TEST/ 测试 ifdef;在.cpp中也尽量避免 - 无硬编码密钥
- 新的公开接口方法带有
///注释 - 无线电任务在核心 0 上;重载应用工作在核心 1 上(除非有记录的特例)
- 护栏/测试通过