Spark Static Analyzer: o guardião técnico que revisa código Spark antes do merge
← Voltar para Artigos

Spark Static Analyzer: o guardião técnico que revisa código Spark antes do merge

TL;DRSpark Static Analyzer é um agente de code review integrado ao CI/CD que analisa o diff de Pull Requests e publica um comentário técnico com score de qualidade (0–100), violações detectadas e sugestões de correção.
Ele aplica 18 regras Spark, cobrindo anti-patterns críticos de custo, estabilidade e segurança em Python, SQL, Scala, Java e R.
Regras críticas têm capacidade de bloquear merges via pipeline — a ativação por repositório é gerenciada pelo time de Plataforma.
O efeito mais importante não foi o bloqueio automático — foi o feedback contínuo no contexto do código real, que acelerou o aprendizado coletivo do time.
O agente opera 100% fora do cluster Databricks — análise estática pura, sem executar código ou acessar dados.


A CERC opera a infraestrutura do mercado financeiro brasileiro para registro de recebíveis, processando um volume expressivo de dados com exigências reais de confiabilidade, governança e rastreabilidade. Cada decisão de engenharia de dados tem impacto direto em custo, estabilidade operacional e qualidade do serviço — o que torna o controle de qualidade no código Spark uma questão operacional, não apenas de boas práticas.

O problema que motivou a construção do Spark Static Analyzer era simples de enunciar, mas difícil de resolver sem uma solução sistêmica: o custo de um erro Spark em produção era alto, e o erro quase sempre parecia pequeno no Pull Request. Uma action no lugar errado. Um join sem filtro. Um collect() sem .limit(). Nada disso chama atenção em uma leitura rápida — tudo isso pode gerar impacto real em horas.

O problema ficou mais agudo quando dois fenômenos se combinaram: times entregando mais rápido, e IA acelerando a geração de código. Quando isso acontece, revisão manual isolada não escala. O volume de mudanças cresce, a atenção disponível por PR diminui, e anti-patterns que deveriam ser bloqueados chegam silenciosamente à produção.

Foi nesse contexto que nasceu o Spark Static Analyzer — não como vitrine de IA, mas como resposta operacional a um risco concreto de engenharia de dados em escala.


Os riscos que ninguém vê no Pull Request

Para entender por que a ferramenta existe, vale ver o que acontece sem ela. A tabela abaixo não é teórica — são anti-patterns que aparecem em ambiente real quando o time cresce e a velocidade aumenta:

Anti-patternConsequência observável
.collect() em tabela de 500 GBOOM no driver, cluster reiniciado, DBU cobrado durante crash
.write dentro de loop com 30 datas30 jobs Spark sequenciais em vez de 1 — 30× o custo esperado
Cross Join acidental entre 2 tabelas de 1M linhas1 trilhão de linhas — cluster travado indefinidamente
Python UDF onde existe equivalente nativo10–100× mais lento por serialização JVM↔Python linha a linha
display(df) sem .limit() em tabela com PIICPF, CNPJ e valores financeiros vazados em logs de cluster
inferSchema=True em produçãoCNPJ inferido como LongType perde zeros à esquerda — corrupção silenciosa de dados
eval()/exec() com input externoInjeção de código via parâmetros de orquestração — OWASP A03:2021
Credencial hardcodedToken permanente no histórico Git mesmo após remoção — OWASP A02:2021

A questão não é se esses padrões aparecem no código. É quando e com que frequência — e se há um mecanismo capaz de sinalizá-los antes do merge.


O que o agente faz

O Spark Static Analyzer revisa automaticamente o diff de cada Pull Request e publica um único comentário técnico com quatro seções: score de qualidade de 0 a 100, lista de regras violadas com linha e impacto calculado, explicação objetiva do risco de cada violação e sugestão prática de correção. Para cada análise, o agente também gera um bloco de prompt pronto para usar em qualquer LLM, permitindo que o autor aplique correções assistidas no mesmo PR.

O que o agente não faz é igualmente importante para entender sua arquitetura: ele não executa código, não roda queries, não acessa dados e não modifica arquivos. Toda a análise é estática, feita sobre o texto do diff via API do Azure DevOps, e o processamento ocorre na máquina de CI/CD — completamente fora do cluster Databricks. Isso garante segurança, previsibilidade e latência baixa: menos de 5 segundos por notebook, independente do tamanho do arquivo.

O escopo é restrito ao diff. Apenas código novo ou modificado no PR recebe análise. Código legado fora do escopo do PR não é penalizado.


Como funciona no pipeline

O fluxo de execução segue cinco passos integrados ao Shift, a plataforma de agentes autônomos da CERC:

  1. O Pull Request é aberto ou atualizado no Azure DevOps.
  2. O agente coleta apenas arquivos novos ou modificados com extensões suportadas: .py, .ipynb, .scala, .java, .r, .R e .sql.
  3. O motor aplica análise estática combinando três técnicas: AST (Abstract Syntax Tree) para construtos semânticos Python, análise léxica e regex para SQL embutido e padrões de credenciais, e heurísticas para casos onde a evidência já é determinística.
  4. O score é calculado com base nas 18 regras e suas penalidades correspondentes.
  5. O comentário consolidado é publicado no PR — sempre como um novo comentário por execução, preservando o histórico completo de análises na thread.

Arquivos de configuração (.yaml, .json, .toml), Markdown e arquivos sob tests/ são ignorados automaticamente.


O modelo de score

A fórmula de cálculo é:

Score = máx(0, 100 − ΣPᵢ)

Onde Pᵢ = Wᵢ × mín(1, nᵢ × kᵢ) — Wᵢ é o peso base da regra, nᵢ é o número de ocorrências e kᵢ é o fator de agravamento por ocorrência adicional. O mín(1, ...) garante que nenhuma regra ultrapasse seu peso base.

Para tornar esse cálculo concreto: um notebook com um único .collect() sem .limit() (W=30) mais uma credencial hardcoded (W=25) mais dois filtros ausentes antes de join() (W=15, k=0,3, n=2) acumula 30 + 25 + 9 = 64 pontos de penalidade, chegando a um score de 36 — reprovado. A mesma análise que antes seria uma discussão subjetiva em comentário de PR passa a ter evidência objetiva com regra e impacto calculado.

As cinco faixas de score organizam a conversa técnica e determinam a ação recomendada:

ScoreLabelAção recomendada
95–100✅ ExcelenteAprovação automática recomendada
85–94✅ AprovadoAprovado com relatório de recomendações no PR
70–84⚠️ AtençãoAprovado, mas o autor deve confirmar explicitamente no corpo do PR
50–69🚫 Revisão obrigatóriaRequer aprovação de Staff Engineer
< 50🔴 ReprovadoTicket de tech debt recomendado

Para as sete regras classificadas como críticas, o agente vai além do comentário: ele encerra o step do pipeline com código de saída 2, tornando o step vermelho no Azure DevOps. A capacidade de bloquear efetivamente o merge — via required check no branch policy — existe na plataforma, mas a ativação por repositório é feita de forma gradual pelo time de Plataforma em conjunto com os times.


O que o agente verifica

O catálogo cobre quatro eixos: FinOps (desperdício de compute antes do merge), estabilidade (padrões que derrubam clusters compartilhados), segurança (vazamento de dados sensíveis e vetores de injeção) e governança (score auditável por notebook, PR e autor).

As 18 regras estão organizadas em três níveis de severidade. As sete críticas encerram o step do pipeline quando detectadas, independente do score total — cobrem os padrões de maior impacto imediato em custo, estabilidade e segurança. As nove de alta severidade penalizam o score e geram recomendações detalhadas com sugestão de correção. As duas de média severidade sinalizam padrões subótimos que acumulam impacto a longo prazo.

O agente analisa código em Python, SQL, Scala, Java e R, combinando AST para construtos semânticos Python, regex para SQL embutido e padrões de credenciais, e heurísticas para casos onde a evidência é determinística. Quando detecta uma violação, ele aponta a linha exata, explica o risco no contexto do código e sugere a correção — não um relatório genérico de qualidade, mas uma conversa técnica sobre o código específico do PR.


O efeito que não estava no plano

A parte mais importante da V1 do Spark Static Analyzer não foi o score, nem o bloqueio automático.

Foi o ciclo de feedback.

Antes da ferramenta, uma violação de anti-pattern chegava ao autor de duas formas: em produção, quando o custo já tinha sido pago, ou em um comentário de PR que dependia do revisor ter o contexto técnico necessário para identificá-la. Com o agente, o ciclo mudou completamente: a violação é apontada no contexto do código real, ainda no Pull Request, com explicação do risco e sugestão de correção. O autor corrige no mesmo PR, uma nova execução valida o ajuste, e o histórico da evolução fica registrado na thread.

Isso tem um efeito pedagógico que se acumula. O engenheiro que corrige um collect() sem limite no segundo PR já não vai escrever o mesmo no terceiro. O time que discute uma violação de Non-SARGable está construindo entendimento coletivo sobre partition pruning. A uniformidade cresce não porque alguém impõe um padrão de fora, mas porque o padrão passa a ser visível e compreensível no momento certo — durante o desenvolvimento, não depois do incidente.

Não é IA substituindo engenharia. É IA elevando a barra da engenharia — junto com a política que reduz a variação de julgamento entre times.


O que ele não faz sozinho

O Spark Static Analyzer não garante resultado isoladamente. Para que funcione como sistema de controle, quatro peças precisam estar juntas:

  1. Regras técnicas claras e calibradas — sem calibração contínua, as penalidades perdem relevância com a evolução do ambiente e dos workloads.
  2. Política de merge aplicada no repositório — o bloqueio efetivo de merge depende do required check ativado no branch policy do Azure DevOps; a habilitação é feita pelo time de Plataforma de forma gradual, por repositório.
  3. Correção efetiva das violações apontadas — o comentário do agente só tem valor se o autor agir sobre ele.
  4. Medição contínua de score, incidente e custo — sem essa correlação, não é possível saber se a ferramenta está cumprindo seu propósito.

Sem esse conjunto, o agente vira apenas mais um comentário no Pull Request.


Próximos passos

A evolução planejada cobre cinco frentes: melhor cobertura para notebooks .ipynb com extração estruturada de células, calibração contínua de pesos por contexto de workload, expansão de adoção com políticas de merge graduadas por maturidade de repositório, métricas de tendência de score por repositório e equipe, e correlação entre score e redução de incidentes e custo operacional.

Essa última frente é a validação definitiva de que a ferramenta está resolvendo o problema para o qual foi criada. Nossa aposta é manter essa relação mensurável — sem promessa vazia de automação mágica. IA na CERC não é um anexo de produtividade: é parte do sistema de engenharia.


Este post foi escrito por: Marcel Duarte.