SOLID C++ ESP32
Limites rígidos
- Prefira arquivos com menos de 400 linhas; divida quando uma unidade de tradução acumular múltiplas responsabilidades
- Máximo de ~30 métodos por classe
- Prefira corpos de função com ~60 linhas (extraia helpers)
- Sem classes aninhadas — mova tipos internos para seu próprio cabeçalho / unidade de tradução
- Exatamente um tipo primário (
class/struct/enum/enum class) por cabeçalho público quando o projeto optar por isso (superfícies restritas / de inicialização)
Linguagem e estilo
- Código/comentários/documentos commitados em Inglês
- Sempre use chaves para
if/for/while/switch - Sem corpos de função de uma linha para lógica não trivial
- Nomes descritivos (
telemetryManager, nãomgr/tmpexceto para índices de loop triviais) - Prefira um bloco
namespacepor unidade de tradução - Cabeçalhos declaram intenção; arquivos
.cpppermaneçam simples e diretos - Métodos públicos em interfaces
I*.h(e outros cabeçalhos públicos optados) precisam de um comentário de intenção///em uma linha
Arquitetura (SOLID + DI)
- Prefira interfaces (
I*) nas fronteiras de domínio - Dependa de abstrações no código de aplicação / domínio; construa adaptadores concretos apenas em
main.cppou uma raiz de composição explícita - Hardware (BLE, Wi-Fi, display, NVS, barramentos) permanece atrás de interfaces para que testes unitários host usem fakes — não
#ifdefcirúrgico - Prefira pequenos parsers puros testados unitariamente em builds
native/ host - Prefira composição ao invés de crescer objetos Deus
- Converta
void*do FreeRTOS em um ponteiro tipado nomeado imediatamente - Prefira helpers do projeto (ex.: cópia segura de C-string) ao invés de variantes de
strncpy
Isolamento de domínio / camada
- Mantenha stacks exclusivas do hub (web, auth, OTA, API HTTP) fora dos alvos bridge / leaf
- Não faça
#includede cabeçalhos de adaptadores concretos da camada errada; se uma salvaguarda listar nomes de adaptadores, obedeça-a
Sem instrumentação de teste em APIs de produção
O código de produção não deve ser moldado por flags de build de teste.
- Proibido em cabeçalhos e
.cpp:UNIT_TEST,#ifdef UNIT_TEST,#ifndef UNIT_TEST,#if defined(UNIT_TEST), ou qualquer gate equivalente apenas para teste (esp_cpp_guardrails falha por padrão) - Prefira DI: extraia uma interface, injete um fake em testes host, ou exclua TUs de adaptadores de dispositivo do
native/ hostbuild_src_filter— nunca faça stub com ifdef em fontes de produção - Detecção de plataforma (
__has_include(<esp_random.h>),ESP_PLATFORM) é aceitável; flags de build de teste que remodelam lógica de produção não são - Mantenha tipos portáveis em cabeçalhos (
std::mutex, etc.) ou includes incondicionais de dispositivo em TUs exclusivas de dispositivo
Cheiro → correção:
| Cheiro | Correção |
|---|---|
#ifndef UNIT_TEST em torno de chamadas Wi-Fi / BLE em um serviço | Injete IWifiConnector / IBleClient; use fake em testes host |
Cabeçalho que muda de tipo quando UNIT_TEST | Tipo portável sempre, ou divida adaptador de dispositivo |
| Classe Deus precisa de ifdefs para compilar no host | Divida responsabilidades; raiz de composição conecta adaptadores |
Segredos
- Nunca codifique senhas Wi-Fi, senhas OTA / web, segredos de dispositivo, PMKs, tokens ou credenciais LAN no código-fonte
- Injete segredos via variáveis de ambiente / flags de build consumidas pelo PlatformIO (ou equivalente) — nunca faça commit de
.envcom segredos reais
FreeRTOS dual-core (ESP32)
O ESP32 clássico tem dois núcleos:
| Núcleo | ID | Uso típico |
|---|---|---|
| PRO_CPU | 0 | Trabalho adjacente a Wi-Fi / BT / rádio (loops de TX/RX ESP-NOW, tarefas de rádio BLE/SPP) |
| APP_CPU | 1 | Trabalho pesado de aplicação: UI de display, HTTP/web, rajadas de parsing, SD, loops não relacionados a rádio |
Padrões (substitua apenas com um caso especial documentado):
- Fixe tarefas sensíveis a rádio / pilha com
xTaskCreatePinnedToCore(..., kRadioCoreId)ondekRadioCoreId = 0 - Fixe tarefas de UI / não rádio pesadas para
kAppCoreId = 1 - Evite trabalho bloqueante longo no core 0; ele sufoca a pilha de rádio
- Prefira constantes nomeadas (
kRadioCoreId/kAppCoreId) ao invés de números mágicos0/1
Validação
- Execute o script de salvaguardas do projeto (ou
tools/esp_cpp_guardrails) após mudanças estruturais - Adicione a menor verificação host/unit que falhe se nova lógica quebrar
- Compile após mudanças em interfaces
- Atualize o README quando comportamento, scripts, suposições de hardware ou arquitetura mudarem
- Prefira uma revisão de qualidade de código bloqueadora antes do merge quando o projeto exigir
Lista de verificação
- Chaves em toda parte; identificadores/comentários em Inglês
- Abaixo de ~400 linhas / ~30 métodos; sem classe aninhada
- Adaptadores concretos apenas na raiz de composição; domínio depende de
I* - Sem
UNIT_TEST/ ifdefs de teste em cabeçalhos; evite-os em.cpp - Sem segredos codificados
-
///em novos métodos de interface pública - Tarefas de rádio no core 0; trabalho pesado de aplicação no core 1 (a menos que exceção documentada)
- Salvaguardas / testes verdes