48 · Ecossistema e design
1 exercícios: .
python3 exercicios/run_all.py 48Os exercícios#
| # | Título | Enunciado |
|---|---|---|
| 266 | o mapa que nao pode mentir, e o principio que se mede |
266 · o mapa que nao pode mentir, e o principio que se mede#
// As tres ultimas partes da referencia Deep Tech sao as de SINTESE: o
// desenho do ecossistema, os dez principios de design e a visao de
// implementacao. Sao as tres coisas que um projeto costuma escrever
// como prosa — e prosa nao roda, nao reprova e envelhece calada.
//
// Este exercicio mostra as tres feitas de outro jeito: derivadas do
// codigo e CONFERIDAS contra ele.
adopt Arcane.Ecossistema as Eco
adopt Arcane.Principios as Prin
adopt Arcane.Percurso as Perc
adopt Arcane.IO as IO
adopt Arcane.OS as OS
out "== 1. o mapa, conferido nas duas direcoes =="
// A conferencia cobra DUAS coisas, e a segunda e a que importa:
// faltando -> caminho citado no mapa que nao existe mais no disco
// orfaos -> modulo do nucleo que nao aparece em componente nenhum
//
// Sem a segunda, um modulo novo nasce FORA do mapa e o inventario fica
// incompleto em silencio. Foi ela que pegou o primeiro erro deste
// modulo: o mapa citava 'arcane_concurrent.py', e o arquivo se chama
// 'arcane_paralelo.py' — so a CLASSE se chama ArcaneConcurrent.
c := Eco.conferir()
assert c["ok"] is yes
assert len(c["faltando"]) is 0
assert len(c["orfaos"]) is 0
out $" {c['citados']} caminhos conferidos, 0 orfaos"
// As tres marcas, e a terceira e a que da valor ao mapa
assert len(Eco.ESTADOS) is 3
assert "nao-existe" in Eco.ESTADOS
n := Eco.numeros()
assert n["existem"] + n["equivalem"] + n["nao_existem"] is n["componentes"]
out $" {n['componentes']} componentes: {n['existem']} existem, " +
$"{n['equivalem']} equivalem, {n['nao_existem']} nao existem"
out ""
out "== 2. toda ausencia tem motivo escrito =="
// Um mapa que marca tudo como pronto nao e um mapa, e publicidade.
faltam := Eco.o_que_nao_existe()
assert len(faltam) bigger 0
cycle f in faltam:
assert f["porque"] is not ""
assert f["aqui"] is not ""
// A maior ausencia, e a razao dela
llvm := [f cycle f in faltam given f["no"] is "LLVM Backend"][0]
assert "fechamentos" in llvm["aqui"]
out $" {len(faltam)} ausencias nomeadas, cada uma com o porque"
out ""
out "== 3. o principio que se MEDE =="
// A prova nao repete o texto do principio: ela roda o analisador sobre
// quatro trechos com defeito conhecido e conta quantos ele pega ANTES
// de o programa rodar.
p := Prin.conferir("compile-time-first")[0]
assert p["veredito"] is "parcial"
assert "4 de 4" in p["medido"]
out $" {p['medido']}"
// E o veredito NAO e dez de dez, de proposito: um relatorio que
// aprovasse os dez seria a prova de que ninguem o leu.
v := Prin.veredito()
assert v["total"] is 10
assert v["cumprido"] + v["parcial"] + v["nao-se-aplica"] is 10
assert v["parcial"] bigger 0
out $" {v['cumprido']} cumpridos, {v['parcial']} parciais, " +
$"{v['nao-se-aplica']} nao se aplica"
out ""
out "== 4. a tensao e o conteudo =="
// Um principio isolado nao informa nada: todo mundo e a favor de
// seguranca e de velocidade. O que informa e ONDE dois se contradizem
// e qual venceu — e essa decisao esta sempre num arquivo.
ts := Prin.tensoes()
assert len(ts) bigger_eq 9
cycle t in ts:
assert len(t["entre"]) is 2
assert t["custo"] is not "" // toda escolha tem preco declarado
assert t["onde"] is not "" // e mora num arquivo
out $" {len(ts)} tensoes, todas com custo e arquivo"
out ""
out "== 5. o percurso, e a fase que NAO roda =="
pasta := $"{OS.temp_dir()}/df-266-{randint(100000, 999999)}"
IO.mkdir(pasta)
alvo := $"{pasta}/exemplo.df"
IO.write(alvo, "action fatorial(n):\n" +
" given n smaller_eq 1:\n" +
" yield 1\n" +
" yield n * fatorial(n - 1)\n" +
"out fatorial(10)\n")
r := Perc.percorrer(alvo)
assert len(r["fases"]) is 10
assert r["ms"] bigger 0
// A ultima fase e NOMEADA e nao percorrida. Executar e o que o
// programa faz: um arquivo de verdade abre soquete e escreve em disco,
// e um comando que mostra fases nao pode ter efeito no mundo.
ultima := r["fases"][9]
assert ultima["fase"] is "execucao"
assert ultima["percorrida"] is no
assert ultima["ms"] is 0.0
// Apagar a fase do mapa faria o desenho parecer completo. Ela fica.
assert "nao percorrida" in ultima["saiu"]
percorridas := [f cycle f in r["fases"] given f["percorrida"]]
assert len(percorridas) is 9
cycle f in percorridas:
assert f["ms"] bigger_eq 0.0
assert f["saiu"] is not ""
// A fase mais cara e uma MEDIDA, e nao se imprime uma medida num
// exercicio: ela muda entre execucoes, e o repositorio compara a saida
// caractere por caractere com a compilacao ligada e desligada. A
// primeira versao imprimia o nome dela e reprovava de forma
// intermitente — 'otimizar' numa execucao, 'tipos' na outra.
//
// O que se AFIRMA e estavel: ela e uma das nove percorridas.
nomes := [f["fase"] cycle f in percorridas]
assert r["mais_cara"] in nomes
out $" 9 fases percorridas, e a mais cara e uma delas"
// E as divergencias em relacao ao desenho do documento
d := Perc.divergencias()
assert len(d) bigger_eq 5
cycle x in d:
assert x["porque"] is not ""
out $" {len(d)} divergencias do desenho, com motivo"
IO.remove_tree(pasta)
out ""
out "Tudo verde: o mapa bate com o disco, e os principios foram medidos."As três últimas partes da referência Deep Tech são as de síntese: o desenho do ecossistema, os dez princípios de design e a visão de implementação.
São as três coisas que um projeto costuma escrever como prosa — e prosa não roda, não reprova e envelhece calada. Este exercício mostra as três feitas de outro jeito: derivadas do código e conferidas contra ele.
1. A conferência nas duas direções#
Arcane.Ecossistema.conferir() cobra duas coisas, e a segunda é a que importa:
| Direção | O que cobra | O que impede |
|---|---|---|
faltando | todo caminho citado existe no disco | a peça foi renomeada e o mapa aponta para o nome antigo |
orfaos | todo módulo do núcleo aparece em algum componente | um módulo novo nasce fora do mapa, e o inventário fica incompleto em silêncio |
Foi a segunda que pegou o primeiro erro deste módulo. O mapa citava dataforge/stdlib/arcane_concurrent.py em dois componentes. O arquivo se chama arcane_paralelo.py — só a classe se chama ArcaneConcurrent. conferir() acusou os dois antes de o primeiro teste existir.
Sem essa direção, o mapa teria nascido mentindo em dois pontos, e ninguém teria como saber.
2. As três marcas, e por que a terceira é a que vale#
| Marca | Estado | Quer dizer |
|---|---|---|
[+] | existe | a peça está aqui, com esse papel |
[~] | equivale | há outra peça que responde a mesma pergunta, nomeada |
[-] | nao-existe | não há, e o motivo está escrito |
A lista é fechada de propósito. Um quarto estado seria o lugar onde "mais ou menos" se esconderia — e é exatamente o que não se quer num inventário.
Sete componentes do desenho estão marcados nao-existe, e o exercício cobra que cada um tenha motivo escrito. Um mapa que marca tudo como pronto não é um mapa, é publicidade: quem o lê descobre a ausência ao tentar, no pior momento, e depois de ter escolhido a linguagem por causa dele.
3. A prova que roda#
Arcane.Principios não repete o texto do princípio. Três das dez provas executam o analisador ou o interpretador:
| Princípio | O que a prova faz | Mediu |
|---|---|---|
compile-time-first | roda o check sobre quatro trechos com defeito conhecido | 4 de 4 antes de rodar |
custo-zero | cria um blueprint sem contrato nem invariante e olha o que ele carrega | 3 de 3 sentinelas em None |
seguranca-por-padrao | roda o check num thread que escreve de fora e olha a severidade | sai como warning |
E o veredito não é dez de dez: cinco cumpridos, quatro parciais, um que não se aplica. Um relatório que aprovasse os dez seria a prova de que ninguém o leu.
custo-zero é nao-se-aplica porque a frase do documento — abstrações devem compilar para código equivalente a implementações manuais — não tem como valer sem compilação nativa. Forçá-la a valer seria redefini-la em silêncio. O que vale, e é cobrado, é outra leitura: uma abstração custa zero para quem não a usa.
4. A tensão é o conteúdo#
Um princípio isolado não informa nada. Todo mundo é a favor de segurança, e todo mundo é a favor de velocidade.
O que informa é onde dois princípios se contradizem e qual venceu — e essa decisão, nesta linguagem, está sempre num arquivo. O exercício cobra que cada uma das nove tensões tenha custo declarado e arquivo.
Exemplo: segurança por padrão × verificação antes de rodar. A escrita concorrente é aviso, não erro, porque um acumulador protegido por mutex passa pelo mesmo caminho de um sem proteção — e recusá-lo proibiria o uso correto. Custo aceito, escrito: um programa com bug de concorrência passa pelo check.
5. A fase que não roda#
Arcane.Percurso leva o arquivo por nove fases e mede cada uma. A décima — execucao — é nomeada, medida em zero e marcada como não percorrida.
Executar é o que o programa faz. Um arquivo de verdade abre soquete, escreve em disco e manda e-mail: um comando cuja função é mostrar as fases não pode ter efeito no mundo, e um que tivesse seria usado uma vez.
E ela fica no mapa. Apagá-la faria o desenho parecer completo — a mesma razão por que Machine Code continua no desenho do ecossistema, marcado como ausente.
A armadilha que inverteu a resposta#
A primeira versão do percurso apontava a fase errada, com confiança:
| Arquivo de 12 tokens | Antes | Depois |
|---|---|---|
| fase mais cara | lir, com 93,8% | tipos, com 27,2% |
| total | 7,266 ms | 0,526 ms |
trabalho real do lir | 0,05 ms | 0,064 ms |
A causa: lir importa compilador e abre um interpretador por dentro. A primeira fase que toca um módulo paga o import dele, e o cronômetro atribui esse custo a ela.
Uma ferramenta que aponta a fase errada é pior que nenhuma, porque a pessoa vai otimizar o lugar que a ferramenta indicou. Hoje os imports lentos acontecem antes de qualquer cronômetro, e há um comentário ao lado da linha que os aquece — para que ninguém os remova por parecerem inúteis.
O que levar#
- Um mapa escrito à mão mente sem avisar; um mapa conferido reprova.
- Nomear a ausência com o motivo vale mais que marcar tudo como
pronto.
- Um princípio que não se aplica é informação, não um problema a
esconder.
- A medida precisa ser honesta sobre o que ela é: uma vez, nesta máquina,
para comparar as fases entre si. Para comparar mudanças, há Arcane.Bench.
Rode um isolado com dataforge run exercicios/48-ecossistema/266_ecossistema_e_principios.df.