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
Refatoração de C++ no OpenBMC: como um agente de IA enfrentou uma função de 280 linhas
Fonte: Habr AI. Colagem: Hamidun News.
Ouvir artigo

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

ZK
Zhemal Khamidun — CPO da Alpina Digital, gerente de produto do AlpinaGPT. Cria produtos de IA desde 2019. O Hamidun News é um projeto pessoal que virou um agregador em produção com mais de 6.000 leitores.
✦ Hands-On AI Engineering · Hamidun Academy

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.

Start 72h Free Trial →Vibe-Coding Intensive
O que você acha?
Carregando comentários…