SOLID C++ ESP32
厳格な制限
- ファイルは 400 行未満 を推奨。翻訳単位が複数の責務を持つようになったら分割する
- クラスあたり最大 約 30 メソッド
- 関数本体は 約 60 行以内 を推奨(ヘルパー関数を抽出する)
- ネストされたクラスは禁止 — 内部型は専用のヘッダー/翻訳単位に移動する
- プロジェクトがオプトインした場合(立ち上げ/厳格な表面)パブリックヘッダーには 1つのみ のプライマリ型(
class/struct/enum/enum class)を置く
言語とスタイル
- コミットされたコード/コメント/ドキュメントは 英語 で記述
if/for/while/switchには常に中括弧を使用- 非自明なロジックに対して単一行の関数本体は禁止
- 説明的な名前を使用(
telemetryManagerであってmgr/tmpではない。ただし自明なループインデックスは除く) - 翻訳単位ごとに 1つの
namespaceブロックを推奨 - ヘッダーは意図を宣言し、
.cppファイルは簡潔で直接的に記述 I*.hインターフェース(およびオプトインしたその他パブリックヘッダー)の公開メソッドには、1行の///意図コメントが必要
アーキテクチャ(SOLID + DI)
- ドメイン境界では インターフェース(
I*)を推奨 - アプリケーション/ドメインコードでは抽象に依存し、具体的なアダプターは
main.cppまたは明示的なコンポジションルートでのみ 構築する - ハードウェア(BLE、Wi-Fi、ディスプレイ、NVS、バス)はインターフェースの背後に隠蔽し、ホストの単体テストではフェイクを使用する(
#ifdefによる手術は行わない) native/ ホストビルドで単体テスト可能な小規模な純粋パーサーを推奨- 巨大な神オブジェクトを育てるよりもコンポジションを推奨
- FreeRTOS の
void*はすぐに名前付き型付きポインタにキャストする strncpyの亜種よりもプロジェクトのヘルパー(例:安全な C 文字列コピー)を推奨
ドメイン/レイヤーの分離
- ハブ専用のスタック(web、認証、OTA、HTTP API)をブリッジ/リーフターゲットから遠ざける
- 間違ったレイヤーから具体的なアダプターヘッダーを
#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など)を保持するか、デバイス専用翻訳単位には無条件のデバイスインクルードを保持する
臭い → 修正:
| 臭い | 修正 |
|---|---|
Wi-Fi / BLE 呼び出しのまわりに #ifndef UNIT_TEST があるサービス | IWifiConnector / IBleClient を注入し、ホストテストでフェイクを使用 |
ヘッダーが UNIT_TEST 時に異なる型をスタブ化する | 常にポータブル型を使用するか、デバイスアダプターを分割 |
| 神クラスがホストでコンパイルするために ifdef を必要とする | 責務を分割し、コンポジションルートでアダプターを配線 |
シークレット
- Wi-Fi パスワード、OTA / web パスワード、デバイスシークレット、PMK、トークン、LAN クレデンシャルをソースコードに決してハードコードしない
- PlatformIO(または同等のもの)で使用される環境変数/ビルドフラグを介してシークレットを注入 — 実際のシークレットを含む
.envを決してコミットしない
デュアルコア FreeRTOS(ESP32)
標準的な ESP32 には2つのコアがあります:
| コア | ID | 典型的な用途 |
|---|---|---|
| PRO_CPU | 0 | Wi-Fi / BT / 無線関連の処理(ESP-NOW 送受信ループ、BLE/SPP 無線タスク) |
| APP_CPU | 1 | より重いアプリケーション処理:ディスプレイ UI、HTTP/web、パースバースト、SD、非無線ループ |
デフォルト(文書化された特別な場合のみオーバーライド):
- 無線/スタックに敏感なタスクを
xTaskCreatePinnedToCore(..., kRadioCoreId)でコア0に固定(kRadioCoreId = 0) - UI / 重い非無線タスクを
kAppCoreId = 1に固定 - コア0での長時間のブロッキング処理は避ける。無線スタックが枯渇する
- マジックナンバー
0/1ではなく名前付き定数(kRadioCoreId/kAppCoreId)を推奨
検証
- 構造変更後はプロジェクトのガードレールスクリプト(または
tools/esp_cpp_guardrails)を実行 - 新しいロジックが破られた場合に失敗する最小のホスト/ユニットチェックを追加
- インターフェース変更後はビルド
- 動作、スクリプト、ハードウェアの前提、アーキテクチャが変更されたら README を更新
- プロジェクトがそれを要求する場合、マージ前にコード品質レビューをブロッキングとして推奨
チェックリスト
- すべてに中括弧;英語の識別子/コメント
- 約400行未満 / 約30メソッド未満;ネストされたクラスなし
- 具体的なアダプターはコンポジションルートのみ;ドメインは
I*に依存 - ヘッダーに
UNIT_TEST/ テスト ifdef なし;.cppでも回避 - ハードコードされたシークレットなし
- 新しいパブリックインターフェースメソッドに
///コメント - 無線タスクはコア0へ;重いアプリケーション処理はコア1へ(文書化された例外がない限り)
- ガードレール/テストがグリーン