SOLID C++ ESP32
硬性限制
- 偏好檔案保持在 400 行 以內;當一個編譯單元出現多重職責時,請切割
- 每個類別最多 約 30 個方法
- 偏好函式主體保持在 約 60 行 以內(提取輔助函式)
- 禁止巢狀類別 — 將內部型別移至自己的標頭檔/編譯單元
- 當專案選擇採用(初始階段/嚴格公開表面)時,每個公開標頭檔 恰好一個 主要型別(
class/struct/enum/enum class)
語言與風格
- 提交的程式碼/註解/文件必須使用 英文
if/for/while/switch一律使用大括號- 非單純邏輯不得使用單行函式主體
- 使用具描述性的名稱(
telemetryManager,而非mgr/tmp,單純的迴圈索引除外) - 偏好每個編譯單元僅有一個
namespace區塊 - 標頭檔宣告意圖;
.cpp檔案則保持簡單直接 I*.h介面(以及其他選擇採用的公開標頭檔)上的公開方法須附上一行///意圖註解
架構(SOLID + DI)
- 偏好使用介面(
I*)於領域邊界 - 在應用程式/領域程式碼中依賴抽象;僅在
main.cpp或明確的組合根(composition root)中建構具體配接器 - 硬體(BLE、Wi-Fi、顯示器、NVS、匯流排)應保持在介面後方,以便主機單元測試使用假物件(fake)— 而非使用
#ifdef修改 - 偏好能在
native/ 主機建置環境中進行單元測試的小型純解析器 - 偏好組合(composition)而非不斷擴大的上帝物件(god object)
- 立即將 FreeRTOS 的
void*轉型為具名型別指標 - 偏好專案輔助函式(例如安全的 C 字串複製)而非
strncpy變體
領域/層級隔離
- 將僅限於集線器(hub)的堆疊(網頁、認證、OTA、HTTP API)排除在橋接器(bridge)/終端(leaf)目標之外
- 勿從錯誤的層級
#include具體配接器的標頭檔;若某守則列出了配接器名稱,請遵守它
生產環境 API 中不得含有測試儀器
生產程式碼不得因測試建置旗標而改變形狀。
- 標頭檔與
.cpp中禁止使用:UNIT_TEST、#ifdef UNIT_TEST、#ifndef UNIT_TEST、#if defined(UNIT_TEST)或任何等效的測試專用閘門(esp_cpp_guardrails 預設會嚴格檢查) - 偏好 DI:提取一個介面,在主機測試中注入一個假物件,或排除裝置配接器編譯單元於
native/ 主機build_src_filter之外 — 絕不要使用 ifdef 來修改生產原始碼 - 平台偵測(
__has_include(<esp_random.h>)、ESP_PLATFORM)是允許的;但會重塑生產邏輯的測試建置旗標則不允許 - 將可攜帶型別保留在標頭檔中(
std::mutex等),或將無條件的裝置包含放在僅屬於裝置的編譯單元中
異味 → 修正:
| 異味 | 修正 |
|---|---|
在服務中使用 #ifndef UNIT_TEST 包圍 Wi-Fi / BLE 呼叫 | 注入 IWifiConnector / IBleClient;在主機測試中使用假物件 |
標頭檔在 UNIT_TEST 時提供不同的型別 | 一律使用可攜式型別,或切割出裝置配接器 |
| 上帝類別需要使用 ifdef 才能在主機上編譯 | 切割職責;組合根負責接線配接器 |
機密
- 絕不要在原始碼中硬編碼 Wi-Fi 密碼、OTA/網頁密碼、裝置密碼、PMK、權杖或區域網路憑證
- 透過環境變數/PlatformIO(或同等工具)使用的建置旗標來注入機密 — 絕不要提交包含真實機密的
.env檔案
雙核心 FreeRTOS(ESP32)
傳統 ESP32 有兩個核心:
| 核心 | ID | 典型用途 |
|---|---|---|
| PRO_CPU | 0 | 與 Wi-Fi / BT / 無線電相關的工作(ESP-NOW TX/RX 迴圈、BLE/SPP 無線電任務) |
| APP_CPU | 1 | 較重的應用工作:顯示器 UI、HTTP/網頁、解析流量、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(除非有文件記錄的例外)
- 守則檢查/測試皆通過