Refatoração de C++ no OpenBMC: como um agente de IA enfrentou uma função de 280 linhas
A função createSensors do projeto OpenBMC (o firmware aberto para os BMCs de servidores) concentra 280 linhas de código e executa 12 tarefas diferentes: busca a configuração do entity-manager de forma assíncrona, mas em uma única thread, procura drivers I2C via sysfs, verifica a presença de dispositivos no barramento, cruza essas informações com a configuração, cria e registra objetos HwmonTempSensor no D-Bus, gerencia limiares de disparo, frequência de polling e estado de energia, trata a lógica de múltiplos sensores em um mesmo dispositivo, e ainda suporta tanto uma varredura completa na inicialização quanto uma atualização pontual de configuração. O agente de IA propôs dividir a função em 7 etapas concretas: extrair uma classe SensorScanner com os métodos buildConfigMap, findSensorPaths, ensureDevice, processPath e matchConfig; eliminar o copia-e-cola na criação de sensores (60 linhas de duplicação); mover os nomes para estruturas de correspondência; separar a lógica de varredura da de atualização; isolar os efeitos colaterais; e substituir o aninhamento profundo por continues antecipados. • **Resultado da refatoração**: o aninhamento (6 a 7 níveis de if/for) desapareceu, as funções encolheram para 20-30 linhas e surgiu uma estrutura clara. Mas o git diff revelou algo inesperado — apareceu mais código em verde (adições) do que em vermelho (remoções). As assinaturas dos 10 novos métodos, somadas a novas estruturas e classes, superaram as 60 linhas de copia-e-cola economizadas. • **O problema arquitetural**: os microsserviços do OpenBMC não leem as configurações diretamente — isso é feito por um serviço central, o entity-manager, que publica os dados no D-Bus aos poucos. O serviço de sensores não tem como saber quando a configuração está completa (não há transações), então recorre a um timeout de 1 segundo (filterTimer.expires_after(std::chrono::seconds(1))). As flags firstScan, sensorsChanged e activateOnly em createSensors existem exatamente por isso: para rastrear atualizações parciais.
Processado por IA de Habr AI; editado por Hamidun News
O que um agente de IA realmente consegue fazer numa refatoração
Um desenvolvedor analisou o microsserviço HwmonTempSensor do OpenBMC — o projeto de firmware aberto para módulos de gerenciamento de servidores baseados em Linux. Todo o serviço gira em torno de uma única função, createSensors, que coleta leituras de sensores de hardware (temperatura, pressão, umidade, corrente, tensão) e as publica no barramento D-Bus para que outros serviços, como a interface web, possam consumi-las.
Essa função de 280 linhas executa 12 tarefas isoladas: busca a configuração do entity-manager de forma assíncrona, mas em uma única thread; procura drivers I2C via sysfs; verifica a presença de dispositivos no barramento; cruza a configuração com os dispositivos encontrados; cria, ativa ou recria objetos HwmonTempSensor; os registra no D-Bus; gerencia os limiares de disparo; gerencia a frequência de polling; gerencia o estado de energia; implementa a lógica para múltiplos sensores em um mesmo dispositivo I2C; suporta uma varredura completa inicial na inicialização; e processa atualizações pontuais quando a configuração muda em tempo real.
O aninhamento de loops e condicionais chega a 6-7 níveis de profundidade (for → for/if → if → if → if). Quando o desenvolvedor pediu à IA que analisasse os problemas, o agente chegou rápido a um diagnóstico: função sobrecarregada, lógica tipo espaguete misturando operações distintas (busca, correspondência, criação, filtragem) e total impossibilidade de testar o código.
7 etapas concretas de refatoração
O agente propôs extrair uma classe SensorScanner, em que cada etapa vira um método privado de 20-30 linhas:
Etapa 1: criar um struct SensorScanner com um construtor que recebe os parâmetros io, objectServer, sensors, dbusConnection, sensorsChanged e activateOnly; expor um único método público scan como ponto de entrada para processar a configuração.
Etapa 2: dividir a lógica em métodos privados: buildConfigMap (parsing da configuração), findSensorPaths (busca de caminhos sysfs), ensureDevice (instanciação de dispositivos I2C), processPath (processamento de um caminho sysfs dentro do loop), matchConfig (correspondência entre um caminho e a configuração).
Etapa 3: eliminar a duplicação na criação de sensores. No código original, a lógica de criação de HwmonTempSensor aparece duplicada duas vezes — uma para o sensor principal e outra para os adicionais. Mover essa lógica para um método createOrActivateSensor com parâmetros como hwmonFile, i2cDev, entre outros. Isso economizou 60 linhas de copia-e-cola.
Etapas 4-7: mover os identificadores Name1..N para estruturas de correspondência separadas; separar a lógica da varredura completa da lógica de atualização de configuração; isolar todos os efeitos colaterais em métodos dedicados; substituir o aninhamento profundo de ifs por continues antecipados.
O paradoxo: a refatoração deixou o código mais bonito, mas não mais curto
Depois de implementar as sugestões do agente, createSensors encolheu para uma única linha:
```cpp void createSensors(...) { auto scanner = std::make_shared<SensorScanner>(...); scanner->run(); } ```
O aninhamento sumiu, os métodos ficaram pequenos, as estruturas ficaram explícitas. É exatamente o tipo de código cobrado em entrevistas técnicas: C++20, templates, RAII, structured bindings.
Mas o git diff mostrou algo inesperado: havia visivelmente mais código em verde (linhas novas) do que em vermelho (linhas removidas). O volume total de código cresceu, mesmo com o copia-e-cola identificado e removido. O motivo? Os 10 novos métodos exigem 10 assinaturas; foram necessárias novas estruturas e classes (para não passar uma dezena de parâmetros por referência); e definições extras foram criadas para isolar a lógica. O código assustador simplesmente ficou estruturado na moda.
A verdadeira revelação: não dá para refatorar uma função isolada
É aqui que a dor realmente começa. O horror dessa função específica não é erro de um programador cansado, nem uma falha aleatória. É consequência direta e inevitável de decisões arquiteturais ruins em todo o projeto.
O OpenBMC se orgulha de seus recursos-chave: reconfigurável em tempo de execução via D-Bus; isolado — cada tipo de sensor roda em seu próprio daemon; assíncrono e single-threaded — usa os bindings do sdbusplus/asio. Parece moderno e escalável.
A realidade é outra. Em vez de um algoritmo simples (ler o JSON de configuração → encontrar os dispositivos → executar o trabalho), os autores dividiram um processo indivisível por natureza entre microsserviços. Os serviços individuais de sensores não leem diretamente os arquivos JSON de configuração — isso é feito por um serviço central, o entity-manager. Ele analisa TODAS as configurações e publica os dados no D-Bus... aos poucos! Todos os microsserviços são forçados a esperar até que a parte da configuração de que precisam seja publicada.
O problema central: não há garantia de atomicidade. O serviço de sensores não tem como saber quando o entity-manager terminou de transmitir os dados de todos os dispositivos do sistema. Quem projetou o D-Bus e o conceito de microsserviços para esse sistema embarcado aparentemente nunca ouviu falar de transações.
A solução: um timeout no chute. Enquanto o entity-manager envia pedaços da configuração, um filtro fica reiniciando um contador. Define-se um atraso de 1 segundo (filterTimer.expires_after(std::chrono::seconds(1))). Se passar um segundo inteiro sem chegar dado novo, assume-se que a configuração está completa e createSensors é chamada.
Foi exatamente essa deficiência arquitetural que transformou createSensors em um inferno. Ela precisa lidar em tempo real com as flags firstScan, sensorsChanged e activateOnly, porque os dados chegam em pedaços e o sistema precisa lembrar corretamente seu estado e reagir às atualizações.
A conclusão: isso é um trabalho de Sísifo. Não dá para refatorar uma única função em C++, por mais assustadora que seja, e esperar que isso salve o projeto. O código aqui não é a causa raiz — é apenas a implementação de conceitos abstratos que alguém enfiou num sistema embarcado sem pensar nos detalhes.
Perguntas frequentes sobre a notícia
O que um agente de IA realmente consegue fazer numa refatoração?
Um desenvolvedor analisou o microsserviço HwmonTempSensor do OpenBMC — o projeto de firmware aberto para módulos de gerenciamento de servidores baseados em Linux. Todo o serviço gira em torno de uma única função, createSensors, que coleta leituras de sensores de hardware (temperatura, pressão, umidade, corrente, tensão) e as publica no barramento D-Bus para que outros serviços, como a interface web, possam consumi-las. Essa função de 280 linhas executa 12 tarefas isoladas: busca a configuração do entity-manager de forma assíncrona, mas em uma única thread; procura drivers I
O que se sabe sobre 7 etapas concretas de refatoração?
O agente propôs extrair uma classe SensorScanner, em que cada etapa vira um método privado de 20-30 linhas: Etapa 1: criar um struct SensorScanner com um construtor que recebe os parâmetros io, objectServer, sensors, dbusConnection, sensorsChanged e activateOnly; expor um único método público scan como ponto de entrada para processar a configuração. Etapa 2: dividir a lógica em métodos privados: buildConfigMap (parsing da configuração), findSensorPaths (busca de caminhos sysfs), ensureDevice (instanciação de dispositivos I2C), processPath (processamento de um caminho sysfs
O que se sabe sobre O paradoxo: a refatoração deixou o código mais bonito, mas não mais curto?
Depois de implementar as sugestões do agente, createSensors encolheu para uma única linha: ```cpp void createSensors(...) { auto scanner = std::make_shared<SensorScanner>(...); scanner->run(); } ``` O aninhamento sumiu, os métodos ficaram pequenos, as estruturas ficaram explícitas. É exatamente o tipo de código cobrado em entrevistas técnicas: C++20, templates, RAII, structured bindings. Mas o git diff mostrou algo inesperado: havia visivelmente mais código em verde (linhas novas) do que em vermelho (linhas removidas). O volume total de código cresceu, mesmo com o copia-e-c
Build & Ship Production AI Agents Without Boilerplate Code
Start your free 72-hour trial at Hamidun Academy (academy.hamidun.com) — interactive lessons on Claude Code & Cursor, live Tech Radar, and production agent templates.
O essencial da IA — uma vez por semana
Sete histórias que realmente importaram, escolhidas a dedo. Sem ruído nem releases.
Pronto! Verifique seu e-mail para a confirmação.