shelf

Out of the Tar Pit

source

Moseley & Marks, 2006 · 66 pages · WIP


O que é esse texto

O paper argumenta que a complexidade é a causa raiz da vasta maioria dos problemas no desenvolvimento e manutenção de software em larga escala. A maior parte dessa complexidade não é “essencial” (inerente ao problema real do usuário), mas sim “acidental” (introduzida por escolhas de arquitetura, ferramentas e linguagens).

Como solução, propõem a arquitetura de Functional Relational Programming (FRP), que combina programação funcional (para lógica pura) com o modelo relacional de Codd (para estado essencial), fatiando o sistema em camadas isoladas.


Três causadores da complexidade acidental

  1. Estado mutável (State): torna sistemas extremamente difíceis de compreender e testar, pois o comportamento muda dependendo de condições internas variáveis e muitas vezes ocultas
  2. Controle (Control): obriga o programador a definir ordem estrita de execução, misturando o que o sistema deve fazer com como isso deve acontecer
  3. Volume de código (Code Volume): código que surge apenas para lidar com manipulação de estados e controles de fluxo

A proposta FRP

A ideia fundamental é fatiar o sistema em camadas totalmente isoladas:


Padrões e ensinamentos

#PadrãoDescrição
P1Eliminar estadoO dado carrega seu próprio status. Em vez de listas paralelas, cada item tem um campo que o classifica
P2Regras como dadosCadeias de if/elif viram tabelas (tuplas, dicts, YAML)
P3Separar fetch/transformar/persistirUma função pura para cada
P4Config declarativaXPaths em YAML, scraper genérico lê config
P5Estado acidental confinadoBuffers, caches, retries escondidos atrás da interface que a lógica de negócio chama sem saber que existem
P6Avoid antes de SeparateTente eliminar complexidade antes de isolar — o paper é explícito
P7Dado derivado, não armazenadoSe pode computar a partir de algo mais primário, não guarde, derive ou materialize como cache explícito
P8Schema essencial primeiroDesenhe o modelo de dados irredutível do domínio antes de qualquer lógica
P9Pipeline como composiçãoUm pipeline idealmente é f(g(h(x))), funções puras compostas

Heurísticas práticas (teste mental)

  1. Onde mora o estado? No item, não em listas paralelas
  2. Isso é dado ou código? Regras repetitivas são tabelas
  3. Quantas coisas essa função faz? Fetch + transform + save = 3
  4. Quantas vezes essa decisão existe? Uma decisão, um lugar
  5. Isso muda com o negócio ou com a técnica? Separa config de lógica
  6. A lógica sabe da infraestrutura? Se sabe, está acoplada
  7. Esse valor é armazenado ou derivado? Se pode ser computado, precisa guardar?
  8. Rodar duas vezes dá o mesmo resultado? Idempotência. Se não, existe estado oculto
  9. Consigo testar sem mock? Se precisa mockar banco/rede/filesystem, a função está misturando essencial com acidental

Limites do paper

Heurística: quanto mais longeva e compartilhada a codebase, maior o valor de aplicar Tar Pit. Quanto mais efêmera e individual, menor.


Resumo dos capítulos 1 e 2

Cap 1 — Introdução

Contexto da “crise de software” (identificada em 1968, só agravou). Premissa central: o maior problema em software de larga escala é a complexidade, que torna grandes sistemas incrivelmente difíceis de compreender. Manuseio de estado como principal fator, seguido de volume de código e fluxo de controle. OOP acopla estado e comportamento; FP pura evita estados e efeitos colaterais. A combinação funcional + relacional é o caminho proposto.

Cap 2 — Complexidade

Análise de “No Silver Bullet” (Brooks): quatro propriedades difíceis (Complexidade, Conformidade, Mutabilidade, Invisibilidade). Moseley & Marks: só Complexidade importa de verdade. Complexidade causa: falta de confiabilidade, atrasos, falhas de segurança, desempenho ruim. Citam Dijkstra, Corbató, Backus, Hoare: “a simplicidade é difícil.” Esclarecimento: complexidade aqui = dificuldade humana de entender, não teoria da complexidade computacional (O(n), memória).


Framework de diagnóstico (5 passes)

O valor real do paper não é a arquitetura FRP (nunca existiu em produção no formato descrito, Datomic chegou mais perto). É a lente de diagnóstico.

Pass 1 — Problema essencial do usuário

Antes de olhar código: qual problema do mundo real esse artefato resolve? Sem mencionar ferramenta, linguagem ou estrutura técnica. Se não consegue escrever essa frase, o resto é especulação.

Pass 2 — Estado essencial irredutível

Quais fatos do domínio precisariam existir se reescrevesse tudo do zero em qualquer linguagem? Resistir a incluir o que está no código atual — “isso é do domínio ou da implementação?”

Pass 3 — Inventariar acidental (3 eixos)

Para cada componente, classificar:

Quantificar: linhas, variáveis mutáveis por classe, profundidade de nesting. Ratio acidental

.

Pass 4 — Árvore de decisão (Avoid > Separate)

Para cada peça de complexidade acidental, em ordem:

  1. Posso eliminar?
  2. Se não, posso derivar em vez de armazenar?
  3. Se não, posso confinar atrás de interface?
  4. Se não, aceito como dívida consciente e documento

A maioria pula direto pro passo 3. O paper insiste em começar do 1.

Pass 5 — Saída acionável

Documento curto: problema essencial (P1), schema essencial (P2), tabela de complexidade com ratio (P3), proposta de refatoração priorizada (P4). Sem isso o diagnóstico evapora em uma semana.

WIP…