OpenCyber Academy
Engenharia · Capítulo 9 · Português
Código do curso: OCA-133Capítulo 09: OCA-133-C009

Capítulo 9 — Programação II

Ensino gratuito e aberto para quem deseja proteger pessoas e tecnologias. Não é preciso criar uma conta para estudar ou consultar as respostas.

Mapa da aula

Aula 09 publicada. Mapa, exemplo, EX025.

flowchart TD
  N0["9.1 Pipelines"]
  N1["9.3 JSON seguro"]
  N2["9.4 Propriedades"]
  N3["9.5 Versionamento de parsers"]
  N4["Nota de prática — Contrapressão"]
  N5["Síntese"]
  N0 --> N1 --> N2 --> N3 --> N4 --> N5
  N5 --> EX["Exemplo resolvido"]
  EX --> Q["Exercício EX025"]

Desenho lógico

flowchart LR
  N0["9.1 Pipelines"]
  N1["9.3 JSON seguro"]
  N2["9.4 Propriedades"]
  N3["9.5 Versionamento de parsers"]
  N4["Nota de prática — Contrapressão"]
  N5["Síntese"]
  N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> Q["EX025"]
[9.1 Pipelines]
    |
    v
[9.3 JSON seguro]
    |
    v
[9.4 Propriedades]
    |
    v
[9.5 Versionamento de parsers]
    |
    v
[Nota de prática — Contrapressão]
    |
    v
[Síntese]
    |
    v
[Exemplo resolvido] --> [Exercício EX025]

Objetivos de aprendizagem

Você vai (1) estruturar um parser como um pipeline de etapas; (2) tratar erros sem perder registros em silêncio; (3) interpretar JSON com segurança usando a biblioteca padrão; (4) escrever testes de propriedades para a normalização.

9.1 Pipelines

A ingestão do Lantern é uma cadeia: obter → decodificar → validar → normalizar → deduplicar → armazenar. Cada etapa recebe registros e produz registros mais rejeições. Os geradores do Python permitem que feeds grandes fluam sem carregar tudo na memória. Cada etapa pode ser testada isoladamente com uma lista curta de registros, e uma falha em uma etapa não esconde o que as outras fizeram. Os logs de Kofi mostram quantos registros entraram e saíram de cada etapa, então uma queda repentina aponta a etapa que a causou. Quando um parceiro envia um arquivo muito grande, o fluxo contínuo faz o uso de memória ficar estável, em vez de crescer com o arquivo.

9.2 Erros como dados

Um objeto malformado não é uma exceção a engolir; é um registro de rejeição com um motivo, a fonte e o hash dos bytes originais. As contagens de rejeições por fonte viram uma métrica de qualidade de dados sobre a qual os parceiros podem agir. Os registros de rejeição de Kofi guardam o hash, e não o conteúdo, para que dados restritos de um parceiro não sejam copiados para logs que uma equipe mais ampla pode ler. Se o mesmo motivo aparece em muitos registros de uma fonte, o parceiro provavelmente mudou algo do lado dele. O relatório enviado a ele traz contagens e exemplos, o que geralmente basta para que encontre e corrija o problema.

9.3 JSON seguro

json.loads interpreta dados sem executar código, ao contrário de avaliar texto. Limite o tamanho das entradas para evitar o esgotamento da memória e valide os tipos depois do parsing; números, strings e nulos JSON chegam em lugares inesperados. Kofi define um tamanho máximo para cada objeto antes do parsing, para que uma entrada enorme seja rejeitada em vez de encher a memória. Depois do parsing, ele verifica se cada campo tem o tipo esperado: um campo de carimbo de tempo contendo um número, ou uma lista onde se esperava uma string, é uma rejeição com motivo claro. Um código antigo que avaliava texto como programa para poupar esforço foi removido em seu primeiro mês.

9.4 Propriedades

Em vez de apenas testes de exemplo, declare propriedades: normalizar duas vezes é igual a normalizar uma vez (idempotência); a saída está sempre em minúsculas; nenhuma saída tem espaço em branco em nenhuma das pontas. Gere muitas entradas aleatórias e verifique se as propriedades se mantêm. As entradas aleatórias de Kofi incluem maiúsculas e minúsculas misturadas, espaços no início e no fim, strings vazias e caracteres de outros alfabetos. Um teste de propriedade descobriu que seu normalizador de domínios mantinha um ponto final, o que fazia duas formas do mesmo nome contarem como indicadores diferentes. A correção removeu algumas centenas de duplicatas do repositório.

9.5 Versionamento de parsers

Quando um parceiro muda seu formato de exportação, uma nova versão do parser é implantada ao lado da antiga até que a troca seja verificada. Cada objeto armazenado registra a versão do parser que o produziu. Rodar as duas versões sobre a mesma entrada por alguns dias mostra se a nova produz os mesmos registros, mais rejeições ou valores diferentes. Só quando as diferenças são compreendidas o parser antigo é desligado. Registrar a versão em cada objeto significa que, se um bug for encontrado depois, os registros afetados podem ser identificados e reprocessados, em vez de adivinhados.

Nota de prática — Contrapressão

Quando uma etapa a jusante fica lenta, as etapas a montante não podem continuar empurrando até a memória acabar. Filas limitadas entre as etapas dão contrapressão (backpressure): os produtores esperam quando uma fila está cheia. O coletor do Lantern pausa as consultas quando a fila de validação está na capacidade máxima e registra a pausa, para que os operadores a vejam, em vez de descobrirem dados ausentes depois.

Exemplo resolvido

Um parceiro envia 5.000 objetos com 37 carimbos de tempo malformados. O pipeline de Kofi armazena 4.963, grava 37 rejeições com o motivo "created not RFC 3339" e envia ao contato de qualidade de dados do parceiro um e-mail com a contagem e dois hashes de exemplo — não os objetos brutos, que são TLP:AMBER.

Caso sintético. As contagens e o parceiro são inventados.

Erros e limites

Descartar registros ruins em silêncio esconde problemas dos parceiros; corrigi-los em silêncio inventa dados. Não avalie texto não confiável como código.

Exercícios

Síntese

Faça os dados fluírem por etapas, trate erros como dados, interprete com segurança, teste propriedades e registre as versões dos parsers.

Continue estudando — capítulo 09 de 50

← Capítulo 08 (rascunho) · Índice de capítulos do curso · Capítulo 10 (rascunho) →

Respostas comentadas

EX025. Quatro quaisquer entre: motivo da rejeição, fonte, hash dos bytes originais, carimbo de tempo, versão do parser.

EX026. norm(norm(x)) == norm(x): reexecutar a ingestão ou renormalizar os dados armazenados nunca muda os valores, então não surgem duplicatas nem deriva.

EX027. Os objetos são TLP:AMBER e o parceiro já os tem; hashes e contagens permitem que ele encontre os registros ruins sem que o Lantern recompartilhe conteúdo restrito.