Pular para o conteúdo

Contratos de dados

O acordo entre quem produz e quem consome — escrito, versionado e cobrado.

Um contrato de dados é a mesma ideia do Arcane.Abi aplicada a uma tabela: o que este conjunto promete, e o que conta como quebra. Sem ele, quem produz não sabe o que pode mudar, e quem consome descobre no incidente.

dataforge
adopt Arcane.Qualidade as Qual

// O contrato é DADO: dá para versioná-lo, difundi-lo e testá-lo.
CONTRATO := {
    "esquema": {
        "id": {"tipo": "inteiro", "nulavel": no},
        "cliente": {"tipo": "texto", "nulavel": no},
        "valor": {"tipo": "numero", "nulavel": no},
    },
    // As regras são um vault POR CAMPO — a mesma forma do 'perfil'.
    "regras": {
        "valor": {"minimo": 0},
        "id": {"unico": yes},
    },
    "frescor_dias": 1,
}

lote := [{"id": 1, "cliente": "Ana", "valor": 10.0},
         {"id": 2, "cliente": "Bia", "valor": 20.0}]

// 1. o esquema
assert Qual.exigir_esquema(lote, CONTRATO["esquema"])["ok"] is yes

// 2. as regras
r := Qual.conferir(lote, CONTRATO["regras"])
assert r["ok"] is yes
assert r["taxa_boa"] is 1.0
out Qual.relatorio(r)

O que um contrato precisa dizer#

PartePergunta que ela responde
esquemaquais campos, de que tipo, e quais podem faltar
chaveo que identifica uma linha — e se ela é única
regras de valorfaixa, formato, lista fechada
frescorquão velho o dado pode estar
volume esperadoquantas linhas por dia são normais
quem respondea pessoa ou o time — sem isso, o contrato não tem dono

Volume também é contrato#

Um lote que chega com 3 linhas onde chegam 30 mil não quebra nenhuma regra de esquema: cada linha está perfeita. E é uma das falhas mais comuns — a origem filtrou errado, e o relatório do dia sai com um centésimo do faturamento.

dataforge
adopt Arcane.Qualidade as Qual

action conferir_volume(lote, esperado, tolerancia):
    quantas := len(lote)
    piso := esperado * (1 - tolerancia)
    teto := esperado * (1 + tolerancia)
    given quantas < piso or quantas > teto:
        trigger $"o lote tem {quantas} linha(s), e o esperado é ~{esperado}{round(tolerancia * 100)}%)"
    yield quantas

assert conferir_volume([1, 2, 3, 4, 5], 5, 0.5) is 5

monitor:
    conferir_volume([1], 100, 0.2)
    assert no
handle Error as e:
    out e.message

E frescor#

dataforge
adopt Arcane.Qualidade as Qual
adopt Arcane.Time as T

agora := T.now()
lote := [{"id": 1, "quando": agora}]

// 'atualidade' conta quantas linhas são mais velhas que o limite.
velhas := Qual.atualidade(lote, "quando", 1)
out velhas
assert velhas["velhas"] is 0
assert velhas["proporcao"] is 0.0