SOLID C++ ESP32
Limites strictes
- Préférez des fichiers sous 400 lignes ; divisez lorsqu'une unité de compilation accumule plusieurs responsabilités
- Maximum ~30 méthodes par classe
- Préférez des corps de fonction sous ~60 lignes (extrayez des helpers)
- Pas de classes imbriquées — déplacez les types internes dans leur propre en-tête/TU
- Exactement un type principal (
class/struct/enum/enum class) par en-tête public lorsque le projet l'active (phase de mise en route / surfaces strictes)
Langue et style
- Code, commentaires et documentation livrés en anglais
- Toujours utiliser des accolades pour
if/for/while/switch - Pas de corps de fonction sur une seule ligne pour une logique non triviale
- Noms descriptifs (
telemetryManager, pasmgr/tmpsauf pour les indices de boucle triviaux) - Préférez un bloc
namespacepar unité de compilation - Les en-têtes déclarent l'intention ; les fichiers
.cpprestent sobres et directs - Les méthodes publiques sur les interfaces
I*.h(et autres en-têtes publics activés) nécessitent un commentaire d'intention///sur une ligne
Architecture (SOLID + DI)
- Préférez les interfaces (
I*) aux frontières du domaine - Dépendre d'abstractions dans le code applicatif/domaine ; construire les adaptateurs concrets uniquement dans
main.cppou une racine de composition explicite - Le matériel (BLE, Wi-Fi, affichage, NVS, bus) reste derrière des interfaces afin que les tests unitaires sur l'hôte utilisent des fakes — pas de chirurgie
#ifdef - Préférez de petits parseurs purs testés unitairement sur des builds
native/ hôte - Préférez la composition plutôt que la croissance d'objets god
- Convertissez immédiatement le
void*de FreeRTOS en un pointeur typé nommé - Préférez des helpers de projet (par exemple, copie sécurisée de chaîne C) aux variantes de
strncpy
Isolation domaine / couche
- Gardez les piles réservées au hub (web, auth, OTA, API HTTP) en dehors des cibles bridge / leaf
- N'incluez pas (
#include) d'en-têtes d'adaptateurs concrets depuis la mauvaise couche ; si une règle liste des noms d'adaptateurs, respectez-la
Pas d'instrumentation de test dans les API de production
Le code de production ne doit pas être façonné par des drapeaux de build de test.
- Interdit dans les en-têtes et les fichiers
.cpp:UNIT_TEST,#ifdef UNIT_TEST,#ifndef UNIT_TEST,#if defined(UNIT_TEST), ou tout équivalent de porte de test uniquement (esp_cpp_guardrails échoue par défaut) - Préférez l'ID : extrayez une interface, injectez un fake dans les tests sur hôte, ou excluez les TU d'adaptateurs périphériques du
build_src_filternative/ hôte — ne faites jamais de stubs ifdef dans les sources de production - La détection de plateforme (
__has_include(<esp_random.h>),ESP_PLATFORM) est acceptable ; les drapeaux de build de test qui remodèlent la logique de production ne le sont pas - Gardez les types portables dans les en-têtes (
std::mutex, etc.) ou les inclusions inconditionnelles de périphériques dans les TU propres au périphérique
Odeur → correction :
| Odeur | Correction |
|---|---|
#ifndef UNIT_TEST autour d'appels Wi-Fi / BLE dans un service | Injectez IWifiConnector / IBleClient ; fake dans les tests sur hôte |
L'en-tête définit des types différents quand UNIT_TEST | Type portable toujours, ou divisez l'adaptateur périphérique |
| Une classe god a besoin d'ifdefs pour compiler sur l'hôte | Divisez les responsabilités ; la racine de composition câble les adaptateurs |
Secrets
- Ne jamais coder en dur les mots de passe Wi-Fi, les mots de passe OTA / web, les secrets de périphérique, les PMK, les jetons ou les identifiants LAN dans le code source
- Injectez les secrets via des variables d'environnement / drapeaux de build consommés par PlatformIO (ou équivalent) — ne committez jamais
.envavec de vrais secrets
FreeRTOS double cœur (ESP32)
L'ESP32 classique a deux cœurs :
| Cœur | ID | Utilisation typique |
|---|---|---|
| PRO_CPU | 0 | Travail lié au Wi-Fi / BT / radio (boucles TX/RX ESP-NOW, tâches radio BLE/SPP) |
| APP_CPU | 1 | Travail applicatif plus lourd : IHM d'affichage, HTTP/web, rafales d'analyse, SD, boucles non radio |
Valeurs par défaut (ne modifier qu'avec un cas particulier documenté) :
- Épinglez les tâches radio / sensibles à la pile avec
xTaskCreatePinnedToCore(..., kRadioCoreId)oùkRadioCoreId = 0 - Épinglez les tâches IHM / non radio lourdes sur
kAppCoreId = 1 - Évitez les longs travaux bloquants sur le cœur 0 ; cela affame la pile radio
- Préférez des constantes nommées (
kRadioCoreId/kAppCoreId) aux valeurs magiques0/1
Validation
- Exécutez le script de garde-fou du projet (ou
tools/esp_cpp_guardrails) après des changements structurels - Ajoutez la plus petite vérification hôte/unité qui échoue si une nouvelle logique casse
- Construisez après des changements d'interface
- Mettez à jour le README lorsque le comportement, les scripts, les hypothèses matérielles ou l'architecture changent
- Préférez une revue de qualité de code bloquante avant la fusion lorsque le projet l'exige
Liste de contrôle
- Des accolades partout ; identifiants et commentaires en anglais
- Moins de ~400 lignes / ~30 méthodes ; pas de classe imbriquée
- Adaptateurs concrets uniquement à la racine de composition ; le domaine dépend de
I* - Pas de
UNIT_TEST/ ifdefs de test dans les en-têtes ; évitez-les dans les fichiers.cpp - Pas de secrets codés en dur
-
///sur les nouvelles méthodes d'interface publique - Tâches radio sur le cœur 0 ; travaux applicatifs lourds sur le cœur 1 (sauf exception documentée)
- Gardes-fous / tests au vert