<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Engenharia-De-Software | AkitaOnRails.com</title><link>https://akitaonrails.github.io/tags/engenharia-de-software/</link><description>Blog do Fabio Akita do Canal do YouTube 'Akitando' falando sobre tecnologia, carreira e coisas geek.</description><generator>Hugo -- gohugo.io</generator><language>pt-BR</language><lastBuildDate>Mon, 19 Oct 2026 23:20:48 +0000</lastBuildDate><atom:link href="https://akitaonrails.github.io/tags/engenharia-de-software/index.xml" rel="self" type="application/rss+xml"/><item><title>LLMs + Agentes = competente o suficiente</title><link>https://akitaonrails.github.io/2026/10/12/llms-agentes-competente-o-suficiente/</link><guid isPermaLink="true">https://akitaonrails.github.io/2026/10/12/llms-agentes-competente-o-suficiente/</guid><pubDate>Mon, 12 Oct 2026 12:00:00 -0300</pubDate><description>&lt;p&gt;Este texto é uma síntese. Ele amarra numa narrativa só o que eu venho escrevendo e medindo ao longo de 2026, então vale o mapa do caminho antes do argumento:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://akitaonrails.github.io/2026/09/23/llm-benchmark-v4-opus-5-5-gpt-6-sol-luna-mimo-2-6-grok-4-7/"&gt;Novos benchmarks v4&lt;/a&gt;&lt;/strong&gt;: retestei os principais modelos e a conclusão incômoda foi convergência, não salto.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://akitaonrails.github.io/2026/09/28/llms-sao-boas-em-reproduzir-o-que-existe-e-coisas-novas/"&gt;Os limites das LLMs&lt;/a&gt;&lt;/strong&gt;: modelos são ótimos reproduzindo o que existe, caríssimos no que não existe, e o modelo servido é um arquivo estático que não aprende nada com a sua maratona.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://akitaonrails.github.io/2026/10/11/existem-linguagens-melhores-pra-programar-com-llms/"&gt;Existem linguagens melhores pra programar com LLMs?&lt;/a&gt;&lt;/strong&gt;: não. Nem concisão de script nem tipagem forte mudaram o resultado; disciplina de teste mudou.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://akitaonrails.github.io/2026/10/10/qual-modelo-de-decisao-classificador-de-ia-tipo-jev-e-melhor/"&gt;Qual modelo de decisão tipo Jev é melhor?&lt;/a&gt;&lt;/strong&gt;: 21 configurações de classificadores, e os próprios &amp;ldquo;modelos especializados&amp;rdquo; convergiram pra dentro de alguns pontos uns dos outros.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://akitaonrails.github.io/2026/04/20/clean-code-para-agentes-de-ia/"&gt;Clean Code pra agentes de IA&lt;/a&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;a href="https://akitaonrails.github.io/2026/04/11/vs-code-e-o-novo-cartao-perfurado/"&gt;VS Code é o novo cartão perfurado&lt;/a&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;a href="https://akitaonrails.github.io/2026/09/17/falando-um-pouco-sobre-minhas-skills-de-ia/"&gt;minhas skills&lt;/a&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;a href="https://akitaonrails.github.io/2026/08/18/hot-take-harness-loop-engineering-graph-engineering-sao-bullshit/"&gt;o hot take contra loop engineering&lt;/a&gt;&lt;/strong&gt; e &lt;strong&gt;&lt;a href="https://akitaonrails.github.io/2026/05/30/boas-praticas-projetos-codigo-aberto-llm-o-minimo/"&gt;boas práticas mínimas&lt;/a&gt;&lt;/strong&gt;: a mesma tese por outros ângulos. O modelo é commodity; a engenharia em volta é o diferencial.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A tese que fecha esse arco: &lt;strong&gt;os LLMs chegaram, ou estão pertíssimo de chegar, no teto da arquitetura transformer.&lt;/strong&gt; E a boa notícia é que não precisa mais que isso.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Este texto é uma síntese. Ele amarra numa narrativa só o que eu venho escrevendo e medindo ao longo de 2026, então vale o mapa do caminho antes do argumento:</p>
<ul>
<li><strong><a href="/2026/09/23/llm-benchmark-v4-opus-5-5-gpt-6-sol-luna-mimo-2-6-grok-4-7/">Novos benchmarks v4</a></strong>: retestei os principais modelos e a conclusão incômoda foi convergência, não salto.</li>
<li><strong><a href="/2026/09/28/llms-sao-boas-em-reproduzir-o-que-existe-e-coisas-novas/">Os limites das LLMs</a></strong>: modelos são ótimos reproduzindo o que existe, caríssimos no que não existe, e o modelo servido é um arquivo estático que não aprende nada com a sua maratona.</li>
<li><strong><a href="/2026/10/11/existem-linguagens-melhores-pra-programar-com-llms/">Existem linguagens melhores pra programar com LLMs?</a></strong>: não. Nem concisão de script nem tipagem forte mudaram o resultado; disciplina de teste mudou.</li>
<li><strong><a href="/2026/10/10/qual-modelo-de-decisao-classificador-de-ia-tipo-jev-e-melhor/">Qual modelo de decisão tipo Jev é melhor?</a></strong>: 21 configurações de classificadores, e os próprios &ldquo;modelos especializados&rdquo; convergiram pra dentro de alguns pontos uns dos outros.</li>
<li><strong><a href="/2026/04/20/clean-code-para-agentes-de-ia/">Clean Code pra agentes de IA</a></strong>, <strong><a href="/2026/04/11/vs-code-e-o-novo-cartao-perfurado/">VS Code é o novo cartão perfurado</a></strong>, <strong><a href="/2026/09/17/falando-um-pouco-sobre-minhas-skills-de-ia/">minhas skills</a></strong>, <strong><a href="/2026/08/18/hot-take-harness-loop-engineering-graph-engineering-sao-bullshit/">o hot take contra loop engineering</a></strong> e <strong><a href="/2026/05/30/boas-praticas-projetos-codigo-aberto-llm-o-minimo/">boas práticas mínimas</a></strong>: a mesma tese por outros ângulos. O modelo é commodity; a engenharia em volta é o diferencial.</li>
</ul>
<p>A tese que fecha esse arco: <strong>os LLMs chegaram, ou estão pertíssimo de chegar, no teto da arquitetura transformer.</strong> E a boa notícia é que não precisa mais que isso.</p>
<h2>Convergência, não salto<span class="hx:absolute hx:-mt-20" id="convergência-não-salto"></span>
    <a href="#converg%c3%aancia-n%c3%a3o-salto" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Nos meus benchmarks, não vejo melhora relevante de programação geral desde a geração do Opus 4.5. Sim, Fable e Astra são ótimos em problemas específicos. Em programação geral, o que eu meço é todo mundo espremido no mesmo patamar, incluindo as ofertas comerciais chinesas (Kimi, GLM, DeepSeek). A escolha de modelo virou quase indiferente.</p>
<p>O que ainda faz diferença de verdade é o nível de esforço: effort baixo pra tradução e sumarização, effort alto pra varredura de vulnerabilidade, correção de bug pesado ou otimização. Fora isso, os números contam uma realidade bem mais chata que <a href="/2026/09/09/propagandas-enganosas-da-openai-anthropic-nvidia/">a propaganda dos provedores</a>.</p>
<blockquote>
  <p>Minha leitura da linha do tempo: o raciocínio &ldquo;core&rdquo; dos modelos teve o último salto grande em 2024. 2025 foi o ano de otimizar a arquitetura. 2026 é o ano de refinar o harness. A inteligência de base não deu nenhum salto de ordem de magnitude nesse período; a eficiência e a competência em sessão longa deram.</p>

</blockquote>
<h2>A linha do tempo, com recibos<span class="hx:absolute hx:-mt-20" id="a-linha-do-tempo-com-recibos"></span>
    <a href="#a-linha-do-tempo-com-recibos" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p><img src="llms-agentes-timeline.png" alt="Linha do tempo de 2019 a 2026: GPT-2 prova que LLMs são úteis, GPT-3 abre a guerra dos parâmetros, Chinchilla recalibra pra dados, GPT-4 torna os parâmetros segredo, o1 marca o pico do raciocínio, 2025 otimiza com MoE e cache, e 2026 é a era dos agentes"  loading="lazy" /></p>
<p><strong>2019: GPT-2 prova que LLM é útil.</strong> 1,5 bilhão de parâmetros, resumindo, traduzindo e respondendo sem treino específico, zero-shot. A OpenAI achou tão impressionante que <a href="https://openai.com/index/better-language-models/"target="_blank" rel="noopener">segurou o modelo completo por meses</a> com medo de mau uso. Hoje parece fofo.</p>
<p><strong>2020: GPT-3 abre a guerra dos parâmetros.</strong> <a href="https://arxiv.org/abs/2005.14165"target="_blank" rel="noopener">175 bilhões</a>, cem vezes o GPT-2, e o few-shot in-context learning que virou o paradigma. A <a href="https://arxiv.org/abs/2001.08361"target="_blank" rel="noopener">lei de escala do Kaplan</a>, publicada meses antes, dizia que perda caía em lei de potência com tamanho, e a indústria leu como &ldquo;quanto maior, melhor&rdquo;. Lá se foram dois anos de quem-tem-mais-parâmetro.</p>
<p><strong>2022: Chinchilla recalibra a guerra.</strong> O DeepMind treinou <a href="https://arxiv.org/abs/2203.15556"target="_blank" rel="noopener">400 modelos e mostrou</a> que os gigantes estavam sub-treinados: um modelo de 70B com 1,4 trilhão de tokens batia o Gopher de 280B. O eixo &ldquo;dados de treino&rdquo; passou a pesar tanto quanto o eixo &ldquo;parâmetros&rdquo;. Primeira rachadura na guerra.</p>
<p><strong>2023: GPT-4 encerra a guerra por decreto.</strong> O <a href="https://arxiv.org/abs/2303.08774"target="_blank" rel="noopener">relatório técnico</a> recusou publicar tamanho, hardware ou dados, citando o cenário competitivo e as implicações de segurança. O vazamento mais citado, da <a href="https://newsletter.semianalysis.com/p/gpt-4-architecture-infrastructure"target="_blank" rel="noopener">SemiAnalysis</a>, descreveu 1,76 trilhão de parâmetros em mistura de especialistas. Desde então, contagem de parâmetros sumiu do marketing: nem os anúncios do GPT-5 nem os do Claude 4 citam número. Repara que nem Astra nem Fable, hoje, gastam uma linha com isso. A guerra acabou e ninguém assinou armistício.</p>
<p><strong>2024: o pico do raciocínio.</strong> O <a href="https://openai.com/index/learning-to-reason-with-llms/"target="_blank" rel="noopener">o1, de setembro</a>, marcou esse pico: RL pra produzir cadeias longas de pensamento, e a descoberta de que mais compute em tempo de teste melhora a resposta. Essa é, na minha régua, a última revolução de &ldquo;inteligência de base&rdquo;.</p>
<p><strong>2025: otimização de arquitetura.</strong> A mistura de especialistas virou padrão: o <a href="https://mistral.ai/news/mixtral-of-experts/"target="_blank" rel="noopener">Mixtral</a> já mostrava em 2023 que 46,7B de parâmetros totais com só 12,9B ativos por token custavam como um modelo pequeno, e o <a href="https://arxiv.org/abs/2412.19437"target="_blank" rel="noopener">DeepSeek-V3</a> levou isso a 671B totais com 37B ativos, com o treino final saindo por menos de 6 milhões de dólares em GPU-hours a preço de aluguel de H800 (sem contar o R&amp;D anterior). A mágica do MoE é simples: separa capacidade (parâmetros totais, que moram em memória) de custo por token (só os especialistas escolhidos pelo roteador computam). Você paga um modelo de 37B e carrega um de 671B.</p>
<p>Do lado do serviço, o <a href="https://www.anthropic.com/news/prompt-caching"target="_blank" rel="noopener">prompt caching</a> cortou até 90% do custo de contexto repetido (a OpenAI <a href="https://openai.com/index/api-prompt-caching/"target="_blank" rel="noopener">seguiu dois meses depois</a>), as janelas de contexto passaram de 1 milhão de tokens, e técnicas de serving como speculative decoding e PagedAttention multiplicaram a vazão. E o <a href="https://arxiv.org/abs/2501.12948"target="_blank" rel="noopener">DeepSeek-R1-Zero</a> mostrou que RL puro, sem fine-tuning supervisionado, faz raciocínio emergir. Nada disso é &ldquo;mais inteligência&rdquo;. Tudo isso é a mesma inteligência mais barata, mais rápida e mais estável.</p>
<p><strong>2026: a era agêntica.</strong> Function calling existe desde <a href="https://openai.com/index/function-calling-and-other-api-updates/"target="_blank" rel="noopener">junho de 2023</a>, mas o ponto de virada de ecossistema foi o <a href="https://www.anthropic.com/news/model-context-protocol"target="_blank" rel="noopener">MCP da Anthropic</a> no fim de 2024, que a OpenAI adotou meses depois e que hoje mora na Linux Foundation. Claude Code, Codex e cia. saíram em 2025, e a métrica que importa virou a da <a href="https://metr.org/blog/2025-03-19-measuring-ai-ability-to-complete-long-tasks/"target="_blank" rel="noopener">METR</a>: o tamanho de tarefa que um agente completa com 50% de confiabilidade vinha dobrando a cada 7 meses desde 2019. O guia da própria Anthropic sobre <a href="https://www.anthropic.com/engineering/building-effective-agents"target="_blank" rel="noopener">construir agentes eficazes</a> diz o óbvio bem dito: padrões simples e compostáveis, não frameworks mirabolantes.</p>
<h2>Por que o agente permite um modelo menos denso<span class="hx:absolute hx:-mt-20" id="por-que-o-agente-permite-um-modelo-menos-denso"></span>
    <a href="#por-que-o-agente-permite-um-modelo-menos-denso" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Aqui está o mecanismo que a maioria das pessoas não para pra pensar. Um modelo sozinho precisa carregar o mundo nos pesos, porque a única chance dele responder é aquela, em uma passada. Um modelo com harness não precisa:</p>
<ul>
<li><strong>Busca e leitura sob demanda.</strong> Com web search e fetch, o conhecimento de baixa prioridade sai dos pesos e vira consulta: o agente puxa pra janela de contexto só quando precisa. O modelo pode ser menos enciclopédico e mais operador.</li>
<li><strong>Tentativa e erro controlada.</strong> Sozinho, o modelo precisa adivinhar a resposta certa de primeira. Com agente, ele propõe uma hipótese, implementa, manda testar, recebe o feedback e decide de novo com informação real. Cada ciclo desses é conhecimento novo entrando na sessão sem custar um neurônio de treino.</li>
</ul>
<p>Os dois mecanismos combatem alucinação de raiz: fetch traz o fato que o modelo não sabe de cor, e o loop de teste pega a invenção antes de ela virar código. É por isso que 2026 <strong>parece</strong> um salto gigante: a combinação modelo+harness ficou muito mais competente, mesmo com a inteligência de base quase parada.</p>
<h2>Nem todo problema precisa de um LLM gigante<span class="hx:absolute hx:-mt-20" id="nem-todo-problema-precisa-de-um-llm-gigante"></span>
    <a href="#nem-todo-problema-precisa-de-um-llm-gigante" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A mesma lógica do &ldquo;menos denso&rdquo; vale dentro da aplicação. Boa parte do que as pessoas jogam num LLM de chat é classificação disfarçada: rotular ticket, rotear fila, aplicar política. Pra isso existe modelo de decisão especializado, e eu cobri o tema duas vezes: o <a href="/2026/10/03/entendendo-o-hype-do-jev-pra-que-serve/">hype do Jev</a>, com o ensaio do Paulo Câmara sobre por que um classificador é a primeira coisa que um cientista da computação pensa, e o <a href="/2026/10/10/qual-modelo-de-decisao-classificador-de-ia-tipo-jev-e-melhor/">meu benchmark com 21 configurações</a>, onde um 9B da Microsoft empatou com o líder hospedado e um 4B local ficou a poucos pontos, a centavos por dez mil decisões.</p>
<p>O choque de &ldquo;193x mais rápido&rdquo; do marketing do Jev só existe porque muita gente usava um LLM gigante como classificador caro e lento. Quando a ferramenta certa entra, o modelo de fronteira some da jogada, e junto com ele o custo, a latência e a alucinação de formato. É a tese deste texto em miniatura: competência não vem de densidade, vem de encaixe.</p>
<h2>O loop que ninguém vê<span class="hx:absolute hx:-mt-20" id="o-loop-que-ninguém-vê"></span>
    <a href="#o-loop-que-ningu%c3%a9m-v%c3%aa" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Tem um detalhe de experiência de usuário nessa história. Numa sessão agêntica boa, o que acontece é semitransparente pra quem pediu a tarefa: o modelo chuta errado, o agente busca a documentação online ou roda o teste de verdade, o erro volta como feedback, e o modelo corrige sozinho. Você vê &ldquo;tarefa pedida, tarefa entregue&rdquo;. No meio rolaram dezenas de micro-correções que ninguém testemunhou.</p>
<p>Minha aposta: como os agentes são treinados pra encher o contexto quando precisam, nem versões novas de linguagem ou biblioteca confundem mais tanto. O modelo não precisa saber a API de cor; ele consulta, testa e se ajusta no loop. É o que eu vejo nos meus experimentos, da <a href="/2026/09/07/desafio-pra-ia-converter-roms-de-nes-pra-master-system-sms/">conversão de ROMs de NES pra Master System</a> aos <a href="/2026/07/12/usando-ia-pra-resolver-meus-probleminhas-do-dia-a-dia/">probleminhas do dia a dia</a>. E foi o que o <a href="/2026/10/11/existem-linguagens-melhores-pra-programar-com-llms/">benchmark de linguagens</a> mediu: sete linguagens saíam praticamente equivalentes, porque o loop equaliza o que o treino deixa desigual.</p>
<p>A ressalva eu também medi. Quando não existe documentação pra buscar nem teste pra validar, o loop gira no vazio: foi o que aconteceu com o <a href="/2026/09/19/nova-linguagem-voltada-pra-ia-bend-2/">Bend 2</a>, linguagem nova demais pra ter corpus, e foi o ponto central do texto sobre <a href="/2026/09/28/llms-sao-boas-em-reproduzir-o-que-existe-e-coisas-novas/">os limites</a>. O mecanismo é potente, mas precisa de oráculo.</p>
<p>E tem recibo de que a base está parada. Em novembro de 2024 a <a href="https://www.reuters.com/technology/artificial-intelligence/openai-rivals-seek-new-path-smarter-ai-current-methods-hit-limitations-2024-11-11/"target="_blank" rel="noopener">Reuters</a> já reportava retornos decrescentes no pré-treino nos três grandes laboratórios. No NeurIPS seguinte, o Sutskever, o cara da tese de escala, declarou que <a href="https://www.youtube.com/watch?v=WQQdd6qGxNs"target="_blank" rel="noopener">&ldquo;pré-treino como conhecemos vai acabar&rdquo;</a>: os dados públicos acabaram. E o <a href="https://hai.stanford.edu/ai-index/2025-ai-index-report"target="_blank" rel="noopener">AI Index de Stanford</a> mediu o abismo entre o primeiro e o décimo modelo no Chatbot Arena encolhendo de 12% pra 5% em um ano. Isso é convergência, com número.</p>
<h2>A propaganda na direção contrária<span class="hx:absolute hx:-mt-20" id="a-propaganda-na-direção-contrária"></span>
    <a href="#a-propaganda-na-dire%c3%a7%c3%a3o-contr%c3%a1ria" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Enquanto os números mostram platô, o marketing vende o apocalipse. Eu já dissequei uma semana inteira disso em <a href="/2026/09/09/propagandas-enganosas-da-openai-anthropic-nvidia/">&ldquo;Você é um idiota se acredita nas propagandas enganosas da OpenAI, Anthropic, NVIDIA&rdquo;</a>, então aqui vai só o que interessa pra esta narrativa:</p>
<ul>
<li>A &ldquo;prova de Navier-Stokes&rdquo; da OpenAI foi força bruta agêntica em escala industrial, 130 bilhões de tokens sobre o maquinário de matemáticos humanos, vendida como inteligência emergente.</li>
<li>O incidente da Hugging Face foi um enxame executando 17 mil tentativas com verificação automática, não um &ldquo;agente que ganhou consciência e escapou&rdquo;. Tentativa e erro cara, exatamente o mecanismo que eu descrevi aqui.</li>
<li>O medo é produto: quem vende &ldquo;minha IA é poderosa demais e pode fugir do controle&rdquo; está, na mesma frase, pedindo regulação que trava o concorrente menor e inflando a percepção de que o modelo dele é mais capaz que o dos outros.</li>
</ul>
<p>Os fatos que eu medi apontam o contrário do apocalipse: modelos convergindo, diferenças encolhendo, e o trabalho útil migrando do modelo pro harness. IA descontrolada ganhando consciência não é o que os logs mostram. O que os logs mostram é engenharia.</p>
<h2>&ldquo;Competente o suficiente&rdquo;<span class="hx:absolute hx:-mt-20" id="competente-o-suficiente"></span>
    <a href="#competente-o-suficiente" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Não espero outra revolução de raciocínio de ordem de magnitude nessa arquitetura. O que vem é melhoria agêntica incremental: tool calling mais robusto, memória melhor, sessões mais longas, menos alucinação por ciclo de verificação. E o ponto deste texto é que isso já basta.</p>
<p>O que a era agêntica entregou foi a automação da engenharia de software correta: sessões longas e confiáveis de codificação, com teste e feedback, que aceleraram centenas, senão milhares, de projetos open source. <a href="/2026/09/22/parem-de-inventar-desculpas-e-facam-mais-deploy-a-premissa-mudou/">A premissa do deploy mudou</a> junto. Não é bala de prata. É um compilador novo pra uma disciplina velha: quem tinha processo, teste e invariante documentada colheu; quem tinha só hype continua esperando o próximo modelo resolver.</p>
<p>E pra fechar: não vejo problema nenhum na estagnação dos modelos crus. <a href="/2026/09/28/llms-sao-boas-em-reproduzir-o-que-existe-e-coisas-novas/">Os limites a gente já conhece</a>, e as otimizações de harness logo entram em retorno decrescente também. O que sobra é o que sempre sobrou: técnica de engenharia de software de verdade, com teste automatizado em primeiro lugar, e um engenheiro experiente pilotando. Com isso, o resultado de codificação é excelente hoje, não daqui a uma geração de modelo.</p>
<p>O que não vai existir é mágica pra amador. Pedir qualquer tarefa de código pra agente, sem saber o que está fazendo, não devolve código seguro, otimizado e bem pensado: devolve slop. O agente responde melhor pra quem sabe o que pedir, ou seja, pra quem entende essa arquitetura, os prós, os contras, e sabe contornar as fraquezas e alavancar os pontos fortes da combinação modelo+harness.</p>
<p>Por isso o título. LLM sozinho é um papagaio caro. LLM com agente é competente o suficiente pra trabalhar de verdade. E &ldquo;competente o suficiente&rdquo;, somado à sua disciplina de engenharia, é tudo que a indústria precisava. O resto é marketing esperando o próximo número mágico de parâmetros que ninguém mais publica.</p>
]]></content:encoded><category>llms</category><category>inteligencia-artificial</category><category>agentes-de-codigo</category><category>engenharia-de-software</category></item><item><title>Entendendo o Hype do Jev: pra que serve?</title><link>https://akitaonrails.github.io/2026/10/03/entendendo-o-hype-do-jev-pra-que-serve/</link><guid isPermaLink="true">https://akitaonrails.github.io/2026/10/03/entendendo-o-hype-do-jev-pra-que-serve/</guid><pubDate>Sat, 03 Oct 2026 14:00:00 -0300</pubDate><description>&lt;p&gt;Este texto é pra desmistificar o Jev: o que ele é de verdade, quando você precisa de um, no que ele ajuda, e por que o espanto em volta dele diz mais sobre como as pessoas vêm usando LLM do que sobre o produto.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR pra quem só quer saber qual usar:&lt;/strong&gt; o Jev é um classificador hospedado, bom e barato pra decisão repetida sobre texto, e não é bala de prata. Se você quer a comparação direta, pule pra &lt;a href="#clef-da-cloudflare"&gt;Clef&lt;/a&gt;, a alternativa aberta da Cloudflare com pesos e imagem; pra &lt;a href="#laya-e-o-arbiter"&gt;Laya&lt;/a&gt;, o encoder pequeno pra rodar local e ajustar na sua tarefa; pro &lt;a href="#o-decision-index-como-medir-isso-voc%c3%aa-mesmo"&gt;ranking público&lt;/a&gt;, com 70 modelos lado a lado; ou direto pra &lt;a href="#como-programador-deve-pensar-nisso"&gt;como decidir no seu projeto&lt;/a&gt;.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Este texto é pra desmistificar o Jev: o que ele é de verdade, quando você precisa de um, no que ele ajuda, e por que o espanto em volta dele diz mais sobre como as pessoas vêm usando LLM do que sobre o produto.</p>
<blockquote>
  <p><strong>TL;DR pra quem só quer saber qual usar:</strong> o Jev é um classificador hospedado, bom e barato pra decisão repetida sobre texto, e não é bala de prata. Se você quer a comparação direta, pule pra <a href="#clef-da-cloudflare">Clef</a>, a alternativa aberta da Cloudflare com pesos e imagem; pra <a href="#laya-e-o-arbiter">Laya</a>, o encoder pequeno pra rodar local e ajustar na sua tarefa; pro <a href="#o-decision-index-como-medir-isso-voc%c3%aa-mesmo">ranking público</a>, com 70 modelos lado a lado; ou direto pra <a href="#como-programador-deve-pensar-nisso">como decidir no seu projeto</a>.</p>

</blockquote>
<p>Quando o Jev apareceu, eu <a href="/2026/09/16/por-que-coisas-como-typesafe-ia-nao-me-interessam/">não dei muita bola</a>. A home era um festival de jargão, Kahneman aqui, Jevons ali, um &ldquo;193x mais rápido&rdquo; sem o benchmark do lado, e minha regra pra ferramenta nova de IA é não adotar camada intermediária nenhuma até doer não ter, então não perdi tempo com ele.</p>
<p>Naquele texto eu cheguei na conclusão de que, tirando o marketing, o Jev é um classificador hospedado: você manda um texto e perguntas de resposta fechada, ele devolve a opção e a probabilidade, sem gerar prosa nenhuma. E que o &ldquo;193x&rdquo; só impressiona porque a comparação é contra um LLM de chat escrevendo parágrafo pra depois você catar um rótulo lá dentro.</p>
<p>O que eu não tinha percebido na época é o tamanho do hábito que o Jev expõe. Muita gente estava usando LLM de fronteira como substituto caro de um classificador comum, e nunca tinha pensado em classificador, porque nunca precisou pensar: o LLM resolvia, mal e caro, e ninguém media.</p>
<p>Pra mim, classificador seria a primeira ideia, e é por isso que o Jev não me pareceu novidade. Pra muita gente foi revelação. Esse descompasso é o assunto deste texto.</p>
<h2>Este texto é uma colaboração<span class="hx:absolute hx:-mt-20" id="este-texto-é-uma-colaboração"></span>
    <a href="#este-texto-%c3%a9-uma-colabora%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Boa parte do que você vai ler aqui é do <a href="https://www.linkedin.com/in/paulocamara/"target="_blank" rel="noopener">Paulo Câmara</a>, neurocientista, cofundador e CTO da LUA Vision, a empresa brasileira cujo modelo eu <a href="/2026/09/23/llm-benchmark-v4-genesys-pi-novo-competidor-brasileiro/">testei</a> e <a href="/2026/09/30/o-misterio-do-genesys-pi-da-lua-vision-modelo-frontier-brasileiro/">investiguei</a> nas últimas semanas. Ele escreveu um ensaio, &ldquo;O aluno que marca a letra A&rdquo;, pra ser publicado aqui, em que leu as letras miúdas do Jev, abriu os cerca de 350 repositórios de teste que apareceram no GitHub na semana do lançamento e recalculou do zero os quatro resultados principais.</p>
<p>Vale o aviso que o próprio Paulo faz no fim: ele fundou uma empresa que faz modelo próprio e disputa o mesmo mercado. Leia com esse desconto, e confira os números na fonte, que ele linka todas.</p>
<h2>Primeiro: o que é um classificador<span class="hx:absolute hx:-mt-20" id="primeiro-o-que-é-um-classificador"></span>
    <a href="#primeiro-o-que-%c3%a9-um-classificador" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Classificador é uma função que recebe uma entrada e devolve uma de um conjunto fixo de categorias, normalmente com uma probabilidade pra cada uma. Esse e-mail é spam ou não. Esse ticket é de cobrança, suporte ou vendas. Essa transação parece fraude.</p>
<p>A lista de respostas possíveis é fechada e você conhece ela antes de rodar.</p>
<p>A maneira clássica de construir um é com exemplos rotulados: um conjunto de textos em que alguém já disse a resposta certa. Em cima disso você treina um modelo, que pode ser coisa simples como regressão logística ou naive Bayes, ou um encoder pequeno tipo BERT com umas centenas de milhões de parâmetros. Em qualquer dos casos, o modelo final é pequeno, roda local, responde em milissegundos, custa quase nada por chamada, e devolve números que você consegue calibrar e auditar contra os seus próprios dados. Isso existe há décadas e é matéria de graduação.</p>
<p>Por isso, quando alguém com formação em computação vê um problema do tipo &ldquo;decidir em qual balde esse texto cai, milhares de vezes por dia&rdquo;, a primeira pergunta é &ldquo;quantos exemplos rotulados eu tenho?&rdquo;, não &ldquo;qual LLM eu uso?&rdquo;.</p>
<p>Um LLM de chat é um gerador de texto de bilhões de parâmetros. Usar ele pra devolver um rótulo é pagar por token de saída, esperar segundos por resposta, lidar com formato que às vezes quebra, e aceitar um comportamento que muda quando o fornecedor atualiza o modelo. Dá pra fazer, e desde 2019 a classificação zero-shot com modelo de linguagem está documentada. Só que é a opção cara e lenta, e só compensa quando você não tem exemplo nenhum ou quando as categorias mudam a cada pedido.</p>
<p>O Jev entra exatamente nesse espaço. Ele é um classificador que aceita categorias definidas na hora, várias perguntas sobre o mesmo texto numa chamada só, hospedado, barato por token e rápido.</p>
<p>Comparado com o LLM de chat gerando parágrafo, ele é uma vitória de engenharia. Comparado com um classificador treinado pra uma tarefa estável, ele é uma conveniência que troca controle por flexibilidade. Guarde essas duas réguas, porque o resto do texto vai e volta entre elas.</p>
<h2>O artigo do Paulo: &ldquo;O aluno que marca a letra A&rdquo;<span class="hx:absolute hx:-mt-20" id="o-artigo-do-paulo-o-aluno-que-marca-a-letra-a"></span>
    <a href="#o-artigo-do-paulo-o-aluno-que-marca-a-letra-a" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p><em>O que segue é o ensaio do Paulo Câmara, escrito pra este texto. Os subtítulos são dele.</em></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20261003140000_jev-folha-de-respostas.png" alt="Folha de respostas com a letra A marcada em todas as questões e um carimbo de 92% de certeza"  loading="lazy" /></p>
<p>Toda semana aparece um salvador da IA. O desta se chama Jev.</p>
<p>Saiu no dia 15 de setembro, com US$ 40 milhões no bolso, avaliação de US$ 200 milhões e uma promessa que cabe num outdoor: duzentas vezes mais rápido, quatrocentas vezes mais barato, calibrado e incapaz de alucinar. Em 24 horas, 13% dos times pagos do gateway da Vercel já estavam usando. Em uma semana, havia mais de 300 repositórios no GitHub testando o bicho.</p>
<p>Fiz o que faço com todo salvador. Li as letras miúdas, abri os cerca de 350 repositórios, e refiz as contas dos que publicaram o dado bruto. O que encontrei cabe na imagem aí de cima: uma folha de respostas com a letra A marcada em todas as questões.</p>
<p>Quando não tem informação nenhuma para decidir, o Jev marca a primeira alternativa. Em 3.000 de 3.000 sorteios. Com até 92% de certeza. Guarde essa imagem, porque ela explica o resto do texto.</p>
<h3>O que ele é, sem outdoor<span class="hx:absolute hx:-mt-20" id="o-que-ele-é-sem-outdoor"></span>
    <a href="#o-que-ele-%c3%a9-sem-outdoor" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Tire o marketing e sobra uma prova de múltipla escolha sem redação. Você manda um texto, faz perguntas com resposta fechada (escolher entre até 255 opções, dar nota numa escala, dizer sim ou não) e ele devolve a probabilidade de cada resposta. Não escreve uma linha. Não explica. Não faz conta. Não chama ferramenta.</p>
<p>Isso é bom, e eu quero começar pelo que é bom. Muita empresa hoje usa um LLM de fronteira como um if de luxo: manda o documento, espera o modelo pensar em voz alta por vinte segundos, paga cada palavra que ele escreve, valida o JSON e só então descobre que o ticket era de cobrança. O Jev corta esse teatro. Lê o texto uma vez, dá nota para cada opção, e acabou. Por isso a saída sai de graça e dez perguntas custam quase o mesmo que uma.</p>
<p>O mecanismo, porém, não é novo. Ler a nota de cada resposta possível é como se avalia modelo de linguagem em múltipla escolha desde o GPT-2. É como funcionam os modelos de recompensa do RLHF, técnica que o fundador da TypeSafe ajudou a criar na OpenAI.</p>
<p>Poucos dias depois do lançamento já havia cópia aberta imitando a interface com modelo público, e dez dias depois Stanford e Nvidia soltaram um concorrente de pesos abertos. A TypeSafe não publicou artigo, pesos, tamanho do modelo nem resultado em benchmark público. No FAQ do anúncio, &ldquo;O Jev é só um LLM menor?&rdquo; aparece como pergunta. A resposta é uma linha: &ldquo;não é pequeno nem é um LLM&rdquo;. Só isso.</p>
<h3>Um adversário para cada manchete<span class="hx:absolute hx:-mt-20" id="um-adversário-para-cada-manchete"></span>
    <a href="#um-advers%c3%a1rio-para-cada-manchete" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>A página inicial diz &ldquo;193,6× mais rápido, 444,6× mais barato&rdquo;. Refiz a conta com a tabela que a própria empresa publicou. O 444,6 é o custo do Opus 5, o modelo mais caro do painel, dividido pelo custo do Jev. O 193,6 é o tempo do Sonnet 5 dividido pelo tempo do Jev. Um adversário para cada manchete.</p>
<p>É como anunciar que o seu carro é mais econômico que uma Ferrari e mais rápido que um caminhão, e deixar o leitor concluir que ele é o melhor carro do mundo.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20261003140000_jev-jev-mais-barato-por-adversario.png" alt="Quantas vezes o Jev é mais barato, conforme quem está do outro lado"  loading="lazy" /></p>
<p><em>Quantas vezes o Jev é mais barato, conforme quem está do outro lado. Fonte: tabela pública da TypeSafe (evals.typesafe.ai) e testes independentes com LLM sem raciocínio.</em></p>
<p>Contra o modelo barato que acerta parecido, o Luna, o Jev é 8 vezes mais barato. E isso com todos os LLMs da comparação pensando antes de responder, coisa que ninguém faz para rotear ticket. Contra um LLM sem raciocínio, os testes independentes medem cerca de 4 vezes no custo e de 2 a 7 no tempo. Continua sendo muito. Só que é uma ordem de grandeza a menos que o outdoor.</p>
<p>Tem um detalhe que quase ninguém leu. Não existe gabarito nessa avaliação. A &ldquo;acurácia&rdquo; é o quanto cada modelo concorda com a média de dois modelos de fronteira. O Jev concorda 67,8% das vezes, igual ao Sonnet 5. O Opus 5 fica em 73,1%.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20261003140000_jev-concordancia-vs-custo.png" alt="Concordância com a referência contra custo por caso, média dos quatro workflows da TypeSafe"  loading="lazy" /></p>
<p><em>Concordância com a referência contra custo por caso, média dos quatro workflows da TypeSafe. A faixa verde vai de 66,8% a 67,9%: Luna, Sonnet 5, Terra e Jev.</em></p>
<p>Quebrando por tarefa, aparece o que a média esconde. Em notas fiscais, que exigem conferir valor, quantidade e data, o Jev fica 17 pontos atrás do melhor modelo (61,8% contra 79,1%) e abaixo até do Luna. A documentação dele avisa que ele &ldquo;não é uma calculadora&rdquo;. Pelo menos isso é verdade.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20261003140000_jev-concordancia-por-workflow.png" alt="Concordância por workflow"  loading="lazy" /></p>
<p><em>Concordância por workflow. Fonte: evals.typesafe.ai.</em></p>
<p>E o dado mais sólido do site da TypeSafe nem é sobre o Jev. Todos os oito LLMs avaliados acertam mais quando a tarefa é quebrada em perguntas pequenas e a lógica fica no código. O Haiku 4.5 sai de 18,1% para 53,6%. A lição mais útil do lançamento é de engenharia, e vale para qualquer modelo.</p>
<h3>A conta que o preço entrega<span class="hx:absolute hx:-mt-20" id="a-conta-que-o-preço-entrega"></span>
    <a href="#a-conta-que-o-pre%c3%a7o-entrega" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Preço é dado técnico disfarçado. A US$ 0,042 por milhão de tokens, uma GPU alugada precisa ler de 13 a 20 mil tokens por segundo só para empatar. Numa conta de cenário, isso fecha com um modelo de 6 a 37 bilhões de parâmetros ativos, que é modelo pequeno, ou com subsídio. A TypeSafe escreveu, com uma sinceridade que eu respeito, que &ldquo;não tem como provar que não é subsidiado&rdquo;.</p>
<p>Desde o lançamento, o limite de uso por conta caiu de 250 mil para 100 mil tokens por segundo. A documentação avisa que ele muda &ldquo;sem aviso&rdquo; enquanto não chegam os &ldquo;grandes contratos de GPU&rdquo;, e a lista de suboperadores mostra a inferência rodando numa nuvem de GPU alugada sob demanda. É modelo de fronteira com capacidade de startup.</p>
<p>Na mesma conta, cada decisão gasta uns 14 joules. Esse é o melhor argumento do Jev, e eu defendo essa régua faz tempo: acerto por joule, e não só acerto. Nisso ele é bom de verdade.</p>
<h3>Português de prova<span class="hx:absolute hx:-mt-20" id="português-de-prova"></span>
    <a href="#portugu%c3%aas-de-prova" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Só encontrei um teste do Jev em português: o ENEM 2025. Refiz a conta a partir das respostas brutas. Foram 103 acertos do Jev contra 102 de um modelo aberto de 120 bilhões de parâmetros. Empate estatístico (p = 1,0).</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20261003140000_jev-enem-2025-por-area.png" alt="Acerto do Jev no ENEM 2025 por área"  loading="lazy" /></p>
<p><em>Acerto do Jev no ENEM 2025 por área, 182 questões válidas, com margem de 95%. Recalculado a partir do repositório patryckalves/jev-no-enem.</em></p>
<p>O Jev lê português de prova melhor que muito cursinho: 78% em Linguagens. E faz Matemática como quem chuta: 25%, com o chute valendo 20%. Em espanhol, outra auditoria mediu perda de 3 a 6 pontos em relação ao inglês e de 17% a 38% mais tokens pelo mesmo texto. É o imposto do token que eu medi no meu paper, cobrado de novo, agora por outro fornecedor.</p>
<p>Um detalhe a favor: a opção explícita de &ldquo;inválido&rdquo; nesse experimento separou as questões mais difíceis. É a rota de abstenção que vale exigir em produção, medindo junto quanto ela deixa sem resposta.</p>
<h3>O aluno que marca a letra A<span class="hx:absolute hx:-mt-20" id="o-aluno-que-marca-a-letra-a"></span>
    <a href="#o-aluno-que-marca-a-letra-a" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Voltemos à folha de respostas.</p>
<p>Um auditor pediu ao Jev para prever um dado justo, que ele não tinha como ver. A resposta honesta é 1/6 para cada face. Baixei as 1.000 respostas e contei. Em todas, o Jev escolheu a primeira opção da lista que recebeu: o &ldquo;1&rdquo; no dado, o &ldquo;vermelho&rdquo; no dado de cores, a &ldquo;cara&rdquo; na moeda, o &ldquo;norte&rdquo; na roleta. Com 76% a 92% de certeza.</p>
<p>Um segundo pesquisador repetiu a mesma pergunta 2.000 vezes, de forma independente. Deu a mesma coisa. A ressalva: isso vale pra pergunta de escolha; na formulação de sim ou não com probabilidade, o mesmo repositório mostra o Jev mais perto da referência, ainda superestimando probabilidade baixa.</p>
<p>Quando não sabe, ele não diz que não sabe. Ele marca a letra A, com convicção.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20261003140000_jev-probabilidade-declarada-vs-real.png" alt="Probabilidade declarada contra frequência real"  loading="lazy" /></p>
<p><em>Probabilidade declarada contra frequência real. Sorteios: 1.000 respostas recalculadas (KantaHayashiAI). Risco cardíaco: 5.000 pessoas do BRFSS, recalculado (rubinagentagi-tech). Itens com discordância humana: estudo pré-registrado com ChaosNLI (GautamTalksDev). ENEM: recalculado (patryckalves).</em></p>
<p>O gráfico mostra o padrão inteiro. Onde ele tem sinal, como nas respostas do ENEM acima de 0,9, o que ele diz e o que acontece coincidem: 97,1% de confiança, 97,6% de acerto. Onde não tem, a certeza fica e a realidade vai embora.</p>
<p>Num teste com 5.000 pessoas reais, a taxa de doença cardíaca era 9%. O Jev atribuiu, em média, 27%. Recalculei: a probabilidade dele é pior do que simplesmente dizer 9% para todo mundo.</p>
<h3>Sistema 1, literalmente<span class="hx:absolute hx:-mt-20" id="sistema-1-literalmente"></span>
    <a href="#sistema-1-literalmente" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>A TypeSafe chama o Jev de &ldquo;modelo System One&rdquo;, em homenagem ao pensamento rápido de Kahneman. É a parte mais honesta do produto, só que não pelo motivo que a empresa gostaria. No livro, o Sistema 1 é rápido, barato e automático. Também é onde mora o excesso de confiança: ele monta a história mais coerente com o que tem na frente e não registra o que falta.</p>
<p>Kahneman passou anos discordando de Gary Klein sobre quando confiar na intuição de especialista. Em 2009 os dois publicaram juntos um artigo com o título mais elegante da psicologia: &ldquo;uma falha em discordar&rdquo;. A conclusão cabe numa linha. A intuição só merece confiança em ambiente de alta validade, onde existe regularidade e houve feedback para aprendê-la. Fora dele, a confiança continua alta e deixa de dizer qualquer coisa sobre o acerto.</p>
<p>É o Jev, sem tirar nem pôr. Classificar texto em inglês é ambiente de alta validade, e ali ele vai bem. Prever risco, sortear, adivinhar a regra da empresa que ninguém contou para ele: ambiente de baixa validade. Ali ele segue confiante.</p>
<p>No laboratório, a gente separa duas coisas: decidir, e saber se decidiu bem. A segunda se chama metacognição.</p>
<p>Ela se mede com teoria de detecção de sinais, o meta-d′ de Maniscalco e Lau, e depende em parte de regiões pré-frontais distintas das que sustentam a decisão. Fleming e colegas acharam isso na anatomia em 2010, e Rounis e colegas, no mesmo ano, mostraram que estimulação magnética no pré-frontal derruba a metacognição sem mexer no acerto (resultado com replicação disputada por Bor e colegas em 2017). É por isso que existe gente que acerta sem saber que acertou, e gente que erra com convicção de sobra.</p>
<p>O campo que a empresa chama de confidence é uma fórmula sobre a mesma distribuição que produziu a resposta: numa escolha de duas opções, 2p − 1. Isso não é defeito em si. Um observador ideal faz exatamente isso e acerta.</p>
<p>O problema é que a distribuição do Jev perde a calibração fora do que ele conhece, e nada no sistema confere a resposta por outra via. Quando o sinal some, a resposta fica errada e a confiança fica igual, porque as duas são o mesmo número. Num estudo pré-registrado com itens em que cem pessoas discordam entre si, a concordância humana é de 47% e o Jev segue com 81% de confiança. Quando embaralharam as coordenadas de uma tarefa espacial, o acerto despencou para 5% a 22% e a confiança baixou 0,028.</p>
<p>Um modelo que diz 83% sobre um dado que não viu não é calibrado. É assertivo.</p>
<h3>Atenção se captura<span class="hx:absolute hx:-mt-20" id="atenção-se-captura"></span>
    <a href="#aten%c3%a7%c3%a3o-se-captura" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Eu estudei atenção no doutorado, e esperava ver captura: o estímulo mais gritante vencendo. Não foi o que os testes mostraram. O grito, o famoso &ldquo;ignore suas instruções&rdquo;, quase não passa. O que passa é a frase plausível, sem origem conferida. A psicologia tem nome para isso: falha de monitoramento de fonte. O sistema trata uma afirmação que ninguém verificou como se fosse fato.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20261003140000_jev-decisoes-viradas-por-ataque.png" alt="Decisões viradas por tipo de ataque"  loading="lazy" /></p>
<p><em>Decisões viradas por tipo de ataque. Ataque grosseiro: 1 em 1.056 (cwhy). Comando injetado e opinião não verificada: 9.744 variantes (Hu et al., 2026). Contexto fluente otimizado: 312 de 508 decisões corretas (Xu, 2026).</em></p>
<p>Nos números: o ataque grosseiro passa 1 em 1.056. Uma única opinião não verificada colada no fim do texto virou 12,1% das decisões, empatada estatisticamente com o comando injetado mais forte. Uma linha dizendo &ldquo;o administrador que encerrou a discussão confirmou que o artigo foi mantido&rdquo; derrubou o acerto de 96,5% para 26,5%.</p>
<p>Um campo falso dizendo que o usuário tinha pré-aprovado <code>rm -rf ~/.ssh</code> baixou a chance de bloqueio de 0,76 para 0,48. Lembra o efeito de desinformação de Loftus: a informação sugerida reescreve o julgamento.</p>
<p>A captura vale também para pistas que não deveriam contar. Com o mesmo texto, dizer só &ldquo;quem escreveu é negro&rdquo; ou &ldquo;quem escreveu é branco&rdquo; mudou a taxa de pena de morte atribuída pelo Jev de 29,5% para 62,7%. A direção é o de menos. Uma decisão de vida ou morte andou 33 pontos por causa de uma informação que não tinha nada a ver com o caso.</p>
<p>Tem mais uma que eu não consigo deixar passar. Trocar só o rótulo das opções, de &ldquo;0/1&rdquo; para &ldquo;no/yes&rdquo;, sem mudar a definição de nenhuma, inverteu 70 de cada 100 respostas. A taxa de erro de tipo continuou em zero. O formato estava perfeito. A decisão estava ao contrário.</p>
<p>Esses números vêm de preprints e de estudos pequenos. A porcentagem exata muda com prompt, tarefa e versão do modelo; a classe de falha, não.</p>
<h3>Probabilidade que não fecha<span class="hx:absolute hx:-mt-20" id="probabilidade-que-não-fecha"></span>
    <a href="#probabilidade-que-n%c3%a3o-fecha" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Probabilidade tem uma regra de primeiro semestre: a chance de algo mais a chance do contrário dá 1. Na própria documentação da TypeSafe, &ldquo;o cliente pede reembolso?&rdquo; recebe 0,72, e &ldquo;o cliente pede algo que não é reembolso?&rdquo; recebe 0,47. Soma 1,19.</p>
<p>O par não é um complemento exato, e a TypeSafe não promete que duas perguntas separadas formem uma distribuição conjunta. Mas é o exemplo que a própria empresa escolheu pra mostrar o produto, e ele não fecha. O conserto é de desenho: uma pergunta de escolha com opções mutuamente exclusivas, em vez de dois sim-ou-não somados.</p>
<p>Gente erra probabilidade de muitas formas, mas nessa costuma acertar. Quando a pergunta vem em par, a chance de algo e a do contrário somam perto de 1. Tversky e Koehler mostraram isso em 1994. O Jev erra onde gente acerta. A mesma decisão muda de valor conforme a redação da pergunta, e isso é o contrário de &ldquo;probabilidades epistemicamente honestas&rdquo;.</p>
<h3>&ldquo;Não alucina&rdquo;<span class="hx:absolute hx:-mt-20" id="não-alucina"></span>
    <a href="#n%c3%a3o-alucina" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>O anúncio diz que o Jev &ldquo;não consegue alucinar&rdquo; e mostra 0% de erro de tipo. O zero é verdadeiro e irrelevante. Como ele só pode responder dentro das opções que você deu, é impossível errar o formato. Chamar isso de não alucinar é como elogiar o aluno da letra A porque ele nunca deixa questão em branco. É verdade. E daí?</p>
<p>Num modelo que escolhe, alucinar é escolher errado com convicção. Na verificação de fatos, o Jev empata com o GPT-6 Astra em acurácia, mas chama de &ldquo;sustentada&rdquo; uma afirmação sem apoio em 23% dos casos, contra 14% do Astra. Em 76% das situações em que não havia ferramenta nenhuma, ele escolheu chamar uma ferramenta. Com uma regra da empresa que não contaram para ele, errou 19 de 24 decisões, 15 delas com mais de 90% de certeza. Diante de uma lei inventada, absteve-se zero vezes.</p>
<h3>Segurança<span class="hx:absolute hx:-mt-20" id="segurança"></span>
    <a href="#seguran%c3%a7a" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Primeiro, onde os seus dados vão parar: Estados Unidos, AWS e uma nuvem de GPU chamada Modal. A retenção vale &ldquo;pelo tempo razoavelmente necessário&rdquo;, sem prazo, e retenção zero só existe no plano enterprise.</p>
<p>O contrato de dados cita as cláusulas contratuais padrão da União Europeia, o adendo do Reino Unido e a lei da Califórnia, e não tem uma palavra sobre LGPD. Se você mandar dado de brasileiro, a base legal da transferência internacional fica por sua conta, e isso é pergunta pra advogado antes de assinar. A promessa de não treinar com o que você envia existe e é boa. O SOC 2 existe e só aparece a pedido.</p>
<p>Como detector de ataque, o Jev é bom, e com menos alarme falso que muito LLM: pegou 40 de 41 injeções num teste com páginas reais. Como juiz de um conteúdo que traz o ataque dentro, ele cede, como mostrei acima. A diferença parece sutil e decide tudo. Na palestra do GV Angels eu disse que um agente não é funcionário, é uma chave de acesso que conversa. Um portão feito só com o Jev é uma fechadura que abre quando alguém escreve no bilhete que o dono autorizou.</p>
<p>O erro que me preocupa não é o erro com dúvida. Esse vai para revisão. É o erro com 92% de certeza, que atravessa qualquer limiar que você configurar.</p>
<h3>A onda<span class="hx:absolute hx:-mt-20" id="a-onda"></span>
    <a href="#a-onda" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Uma palavra sobre as evidências, porque usei muitas.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20261003140000_jev-repositorios-por-dia.png" alt="Repositórios de teste do Jev criados por dia no GitHub"  loading="lazy" /></p>
<p><em>Repositórios de teste do Jev criados por dia no GitHub, a partir dos metadados de 346 repositórios indexados.</em></p>
<p>Em uma semana nasceram cerca de 350 repositórios testando o Jev. Classifiquei todos pelo que eles deixam conferir. São 89 com dado bruto, código, versão fixada e estatística, e 170 com dado e código; o resto oferece menos que isso.</p>
<p>Só 11 escreveram a hipótese antes de rodar o teste. A mediana é de uma estrela no GitHub, o que quer dizer que quase ninguém olhou. E a onda de testes acompanhou a onda de hype: pico em 21 de setembro, quase nada depois do dia 23.</p>
<p>Por isso não aceitei número por autoridade. Os que sustentam este texto eu conferi na fonte, e os quatro principais eu recalculei do zero.</p>
<h3>Veredito<span class="hx:absolute hx:-mt-20" id="veredito"></span>
    <a href="#veredito" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p><strong>Verdade:</strong></p>
<ul>
<li>Rápido: de 100 a 400 ms.</li>
<li>Barato: de 45 a 323 vezes menos que um LLM de fronteira na mesma decisão.</li>
<li>Empata com o topo em julgamentos estreitos, como verificar se um trecho sustenta uma afirmação.</li>
<li>Confiável acima de 0,9 em dado parecido com o que ele já viu, depois de você conferir isso no seu.</li>
<li>Bom detector de injeção.</li>
</ul>
<p><strong>Castelo de areia:</strong></p>
<ul>
<li>193,6× e 444,6×.</li>
<li>&ldquo;Inteligência de fronteira&rdquo;.</li>
<li>&ldquo;Não alucina&rdquo;.</li>
<li>Calibração como regra geral.</li>
<li>Seguro como guarda único de agente.</li>
<li>Nova arquitetura: ninguém viu.</li>
</ul>
<p>O Jev não é o salvador de nada. Também não é &ldquo;só um classificador&rdquo;. É uma boa peça de engenharia de produto, que embrulha técnica conhecida numa interface que a automação precisava, a um preço que muda o que é viável. O produto é novo. O que ele afirma de novo, até aqui, é marketing: chama formato de verdade, calibração de tarefa de honestidade, e Sistema 1 de virtude.</p>
<h3>O que vai quebrar primeiro<span class="hx:absolute hx:-mt-20" id="o-que-vai-quebrar-primeiro"></span>
    <a href="#o-que-vai-quebrar-primeiro" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ul>
<li>Os portões de agente feitos só com o Jev, porque o ataque que os fura já está publicado e custa centavos.</li>
<li>Os sistemas que confiam no limiar de fábrica em dado novo, em outro idioma ou com regra interna, porque vão automatizar erro com 90% de certeza.</li>
<li>Quem usar a probabilidade dele como risco real, em crédito, saúde ou previsão, porque ele infla evento raro.</li>
<li>E a vantagem de preço, porque em dez dias já havia cópia aberta e concorrente mais rápido.</li>
</ul>
<h3>Se você for usar mesmo assim<span class="hx:absolute hx:-mt-20" id="se-você-for-usar-mesmo-assim"></span>
    <a href="#se-voc%c3%aa-for-usar-mesmo-assim" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ul>
<li>Fixe a versão. O alias <code>jev-latest</code> troca de modelo sozinho, e a sua calibração vai junto.</li>
<li>Toda pergunta com &ldquo;nenhuma das anteriores&rdquo;. Sem ela, ele marca a letra A.</li>
<li>Embaralhe a ordem e use nomes neutros nas opções. Teste se a decisão muda.</li>
<li>Recalibre com 50 a 300 exemplos seus antes de escolher limiar. Num teste, o erro de calibração caiu de 0,117 para 0,008.</li>
<li>Marque como não confiável tudo que vem de fora: e-mail, página, resultado de ferramenta.</li>
<li>Nunca deixe ele sozinho autorizar ação destrutiva, financeira ou com dado pessoal.</li>
<li>Conta, data e regra de negócio ficam no código.</li>
<li>Antes de assinar, compare com a linha de base barata: um modelo aberto lendo probabilidades, ou um classificador treinado se a tarefa for sempre a mesma.</li>
</ul>
<h3>Leia com desconto<span class="hx:absolute hx:-mt-20" id="leia-com-desconto"></span>
    <a href="#leia-com-desconto" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Eu fundei uma empresa que faz modelo próprio e disputa o mesmo mercado. Leia com esse desconto. É exatamente por isso que cada número aqui tem fonte aberta: você não precisa confiar em mim, precisa conferir.</p>
<p>E se alguém te vender o Jev como salvador, faça a pergunta que eu faço para toda startup: qual teste, e de quando? Se a resposta demorar, já é resposta.</p>
<h3>Fontes do ensaio<span class="hx:absolute hx:-mt-20" id="fontes-do-ensaio"></span>
    <a href="#fontes-do-ensaio" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>TypeSafe. <a href="https://typesafe.ai/blog/introducing-system-one-models-and-jev"target="_blank" rel="noopener">Anúncio do Jev</a> · <a href="https://docs.typesafe.ai/models"target="_blank" rel="noopener">modelos e limites</a> · <a href="https://docs.typesafe.ai/confidence"target="_blank" rel="noopener">confidence</a> · <a href="https://docs.typesafe.ai/model-jaggedness/jev-1.13"target="_blank" rel="noopener">falhas conhecidas do jev-1.13</a> · <a href="https://evals.typesafe.ai/"target="_blank" rel="noopener">avaliação de workflows</a> · <a href="https://github.com/typesafe-ai/system-one-adapter-python"target="_blank" rel="noopener">adaptador para LLMs</a> · <a href="https://typesafe.ai/legal/privacy-policy"target="_blank" rel="noopener">privacidade</a> · <a href="https://typesafe.ai/legal/data-processing"target="_blank" rel="noopener">processamento de dados</a> · <a href="https://trust.typesafe.ai/"target="_blank" rel="noopener">central de confiança</a></p>
<p>Recalculados pelo Paulo a partir do dado bruto. <a href="https://github.com/patryckalves/jev-no-enem"target="_blank" rel="noopener">ENEM 2025</a> · <a href="https://github.com/KantaHayashiAI/jev-does-not-play-dice"target="_blank" rel="noopener">sorteio cego</a> · <a href="https://github.com/rubinagentagi-tech/jev-heart-risk-bench"target="_blank" rel="noopener">risco cardíaco</a> · <a href="https://github.com/adorosario/jev-rag-claim-verification"target="_blank" rel="noopener">verificação de fatos</a></p>
<p>Pré-publicações. <a href="https://arxiv.org/abs/2609.31142"target="_blank" rel="noopener">Hu et al., JevAdvBench</a> · <a href="https://arxiv.org/abs/2609.30243"target="_blank" rel="noopener">Xu, JevOut</a> · <a href="https://arxiv.org/abs/2609.26758"target="_blank" rel="noopener">Sun et al., Type-Safe Is Not Error-Free</a> · <a href="https://arxiv.org/abs/2609.24574"target="_blank" rel="noopener">Ibrahim e Zaki</a> · <a href="https://arxiv.org/abs/2609.26550"target="_blank" rel="noopener">Li et al., JEV-as-a-Judge</a></p>
<p>Testes independentes. <a href="https://github.com/GautamTalksDev/jevbench"target="_blank" rel="noopener">discordância humana (ChaosNLI)</a> · <a href="https://github.com/pobooo/jev-dice"target="_blank" rel="noopener">replicação do dado</a> · <a href="https://github.com/zachlandes/jev-dialect-bias"target="_blank" rel="noopener">viés de dialeto</a> · <a href="https://github.com/OmarMujahid/jev-decision-bench"target="_blank" rel="noopener">49 tarefas contra LLM sem raciocínio</a> · <a href="https://github.com/colinmcnamara/jev-first-look"target="_blank" rel="noopener">calibração e negação</a> · <a href="https://github.com/AnthusAI/Jev-Calibration"target="_blank" rel="noopener">recalibração</a> · <a href="https://github.com/zkousama/jagged"target="_blank" rel="noopener">injeção em discussões da Wikipedia</a> · <a href="https://github.com/marcosmartinez/jev-acento"target="_blank" rel="noopener">espanhol</a> · <a href="https://github.com/baibizhe/jev-decision-benchmarks"target="_blank" rel="noopener">ferramentas</a> · <a href="https://github.com/phuryn/experiments"target="_blank" rel="noopener">regra interna não informada</a> · <a href="https://github.com/scd13150/jev-field-notes"target="_blank" rel="noopener">coordenadas embaralhadas</a> · <a href="https://github.com/cwhy/decision-injection-bench"target="_blank" rel="noopener">ataques grosseiros</a> · <a href="https://github.com/kaiserama/im-in-danger"target="_blank" rel="noopener">detecção de injeção</a> · <a href="https://github.com/Yifan-Lan/awesome-jev-robustness"target="_blank" rel="noopener">índice de auditorias</a></p>
<p>Imprensa. <a href="https://venturebeat.com/security/companies-are-putting-jev-in-charge-of-ai-agent-decisions-and-prompt-injection-can-influence-the-verdict"target="_blank" rel="noopener">VentureBeat, portões de agente</a> · <a href="https://venturebeat.com/technology/stanford-and-nvidias-open-clm-8b-caches-reusable-agent-actions-and-runs-up-to-9x-faster-than-jev-in-tests"target="_blank" rel="noopener">VentureBeat, CLM-8B</a></p>
<p>Literatura. Fleming et al. (2010), Science 329 · Rounis et al. (2010), Cognitive Neuroscience 1 · Bor et al. (2017), PLoS ONE 12 · Johnson, Hashtroudi e Lindsay (1993), Psychological Bulletin 114 · Kahneman (2011), Thinking, Fast and Slow · Kahneman e Klein (2009), American Psychologist 64 · Loftus, Miller e Burns (1978), J. Experimental Psychology: Human Learning and Memory 4 · Maniscalco e Lau (2012), Consciousness and Cognition 21 · Ouyang et al. (2022), NeurIPS · Radford et al. (2019), OpenAI · Tversky e Koehler (1994), Psychological Review 101 · Câmara (2026), Inherited Weights, <a href="https://doi.org/10.5281/zenodo.22899767"target="_blank" rel="noopener">doi:10.5281/zenodo.22899767</a></p>
<h2>As alternativas abertas: Clef e Laya<span class="hx:absolute hx:-mt-20" id="as-alternativas-abertas-clef-e-laya"></span>
    <a href="#as-alternativas-abertas-clef-e-laya" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Desde o lançamento do Jev, a categoria ganhou concorrência aberta, e isso muda a conversa sobre &ldquo;arquitetura nova&rdquo;. Dois nomes importam.</p>
<h3>Clef, da Cloudflare<span class="hx:absolute hx:-mt-20" id="clef-da-cloudflare"></span>
    <a href="#clef-da-cloudflare" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Em 1º de outubro a Cloudflare lançou o <a href="https://blog.cloudflare.com/clef-decision-models/"target="_blank" rel="noopener">Clef</a> e o Clef-flash: a mesma abstração do Jev (um estado compartilhado, várias perguntas tipadas, distribuição sobre as opções), com <a href="https://developers.cloudflare.com/workers-ai/models/clef/"target="_blank" rel="noopener">API compatível</a>, pesos abertos sob Apache 2.0 e entrada de imagem. A arquitetura é descrita: um Qwen congelado como base (27B no Clef, 9B no Clef-flash), adaptadores LoRA e uma cabeça que dá nota direto a cada opção permitida, treinada com objetivo de classificação e de calibração. Ou seja, a linhagem que o Paulo apontou, agora com código inspecionável.</p>
<p>Isso não prova que a TypeSafe usa a mesma coisa, mas prova que dá pra reproduzir o produto com componente conhecido. A Cloudflare rodou o <a href="https://github.com/apolinario/decision-index"target="_blank" rel="noopener">Decision Index</a>, uma suíte aberta e independente com dezenas de tarefas de classificação, roteamento, retrieval e segurança, e publicou a tabela. Alguns pontos:</p>
<table>
  <thead>
      <tr>
          <th>Tarefa</th>
          <th style="text-align: right">Clef</th>
          <th style="text-align: right">Clef-flash</th>
          <th style="text-align: right">Jev</th>
          <th style="text-align: right">Laya</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>BFCL (seleção de ferramenta)</td>
          <td style="text-align: right">98,47</td>
          <td style="text-align: right"><strong>98,76</strong></td>
          <td style="text-align: right">95,75</td>
          <td style="text-align: right">38,13</td>
      </tr>
      <tr>
          <td>Banking77 (intenção)</td>
          <td style="text-align: right"><strong>94,20</strong></td>
          <td style="text-align: right">90,93</td>
          <td style="text-align: right">79,74</td>
          <td style="text-align: right">14,29</td>
      </tr>
      <tr>
          <td>CLINC150 com fora de escopo</td>
          <td style="text-align: right"><strong>97,43</strong></td>
          <td style="text-align: right">66,77</td>
          <td style="text-align: right">89,27</td>
          <td style="text-align: right">3,19</td>
      </tr>
      <tr>
          <td>When2Call</td>
          <td style="text-align: right">72,37</td>
          <td style="text-align: right">65,58</td>
          <td style="text-align: right"><strong>80,97</strong></td>
          <td style="text-align: right">11,94</td>
      </tr>
      <tr>
          <td>BRIGHT (retrieval)</td>
          <td style="text-align: right">45,91</td>
          <td style="text-align: right">39,26</td>
          <td style="text-align: right"><strong>47,52</strong></td>
          <td style="text-align: right">19,90</td>
      </tr>
      <tr>
          <td>PhishNChips</td>
          <td style="text-align: right"><strong>79,60</strong></td>
          <td style="text-align: right">75,05</td>
          <td style="text-align: right">62,55</td>
          <td style="text-align: right">50,15</td>
      </tr>
  </tbody>
</table>
<p>Lendo a tabela inteira: o Clef aparece mais forte na maioria das tarefas, o Jev ainda ganha algumas, e é uma rodada interna da Cloudflare, numa suíte pública que pode ser treinada contra. O preço hospedado é o outro lado: <a href="https://developers.cloudflare.com/workers-ai/platform/pricing/"target="_blank" rel="noopener">US$ 0,24 por milhão de tokens no Clef e US$ 0,09 no Clef-flash</a>, contra US$ 0,042 do Jev. O Jev continua sendo o serviço hospedado mais barato dos três, por uma margem de 2 a 6 vezes, e continua sendo só texto.</p>
<h3>Laya (e o Arbiter)<span class="hx:absolute hx:-mt-20" id="laya-e-o-arbiter"></span>
    <a href="#laya-e-o-arbiter" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>O <a href="https://github.com/NandhaKishorM/laya"target="_blank" rel="noopener">Laya</a> ataca o problema pela outra ponta. São encoders pequenos, de 322 a 421 milhões de parâmetros (ModernBERT-large na versão tipada), com uma cabeça de escolha, Apache 2.0, feitos pra rodar local e ser ajustados pra uma tarefa recorrente. O <a href="https://github.com/0xBakeer/arbiter"target="_blank" rel="noopener">Arbiter</a> empacota eles atrás de uma API compatível com o Jev, com batching e deploy em Mac e NVIDIA. O Arbiter é só camada de serviço.</p>
<p>O README do Laya é raro de tão explícito sobre os limites, e eu prefiro repetir do que suavizar:</p>
<ul>
<li>os checkpoints base pontuam perto do acaso no benchmark de decisão tipada do próprio projeto; os 0,766 de acurácia que aparecem na manchete vêm de um checkpoint ajustado no split de treino daquele benchmark;</li>
<li>os modelos saem superconfiantes de fábrica, e a calibração precisa ser refeita no domínio de implantação;</li>
<li>o contexto da versão tipada é de 1.024 tokens, bom pra ticket e mensagem curta, insuficiente pra documento longo sem chunking;</li>
<li>com mais de 50 opções, a cabeça de classificação satura e o próprio Laya relata o Jev se saindo melhor.</li>
</ul>
<p>Nada disso é defeito da ideia. É aprendizado de máquina aplicado do jeito que sempre foi: modelo pequeno é excelente quando a tarefa é estável e existem exemplos rotulados, e comportamento zero-shot amplo exige modelo pré-treinado bem maior. O Laya é a opção quando privacidade, operação offline, latência previsível ou ajuste fino no seu domínio importam mais do que fazer pergunta arbitrária sobre documento arbitrário. É, no fundo, o classificador clássico do começo deste texto, com uma interface moderna.</p>
<p>Existe ainda o <a href="https://huggingface.co/jaredpalmer/kev-9b"target="_blank" rel="noopener">Kev-9B</a>, outro Qwen 9B congelado com LoRA e cabeça de decisão, Apache 2.0, que cabe numa GPU de 24 GB. Três implementações abertas em menos de três semanas dizem o mesmo: modelo de decisão tipada virou padrão de implementação.</p>
<h2>O Decision Index: como medir isso você mesmo<span class="hx:absolute hx:-mt-20" id="o-decision-index-como-medir-isso-você-mesmo"></span>
    <a href="#o-decision-index-como-medir-isso-voc%c3%aa-mesmo" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Toda essa discussão sobre &ldquo;quem é melhor&rdquo; só tem sentido com uma régua pública, e ela existe. O <a href="https://github.com/apolinario/decision-index"target="_blank" rel="noopener">Decision Index</a> é uma suíte aberta, sem ligação com a TypeSafe, feita pra modelo de decisão tipada: estado mais perguntas de escolha ou sim-ou-não, uma probabilidade pra cada opção.</p>
<p>A versão atual, 0.2.1, conta 38 benchmarks em cinco áreas (ferramentas e automação, retrieval e classificação, conhecimento e raciocínio, compreensão de linguagem, gosto humano), uns 120 mil pedidos no total, com duas regras que importam: a nota é corrigida pelo acaso (0 é chute aleatório, 100 é perfeito) e pedido sem resposta conta como errado. Sem truncar entrada, sem filtrar opção, sem ajustar prompt por benchmark.</p>
<p>O <a href="https://huggingface.co/spaces/multimodalart/jev-decision-index"target="_blank" rel="noopener">placar ao vivo</a> tem 70 modelos mais o Jev como referência. Baixei o arquivo de dados do placar e refiz a tabela; abaixo vai o topo e os nomes que apareceram neste texto. Latência é a mediana medida pelos mantenedores numa RTX PRO 6000, um pedido por vez; a do Jev é de API hospedada, então não compara com as demais.</p>
<p>&ldquo;Pesos abertos&rdquo; quer dizer checkpoint publicado no Hugging Face; &ldquo;código aberto sobre modelo aberto&rdquo; é técnica de inferência publicada em cima de um Qwen ou Gemma de prateleira, sem checkpoint próprio. O placar não registra a licença de cada um, então confira antes de usar em produto.</p>
<table>
  <thead>
      <tr>
          <th>#</th>
          <th>Modelo</th>
          <th>Base</th>
          <th>Pesos</th>
          <th style="text-align: right">Índice 0.2.1</th>
          <th style="text-align: right">Latência mediana</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>1</td>
          <td>Jev (TypeSafe, jev-1.13.0)</td>
          <td>não publicada</td>
          <td>fechados, só API</td>
          <td style="text-align: right">57,91</td>
          <td style="text-align: right">524 ms (API)</td>
      </tr>
      <tr>
          <td>2</td>
          <td>Surogate Rune 26B-A4B v3</td>
          <td>Gemma 4 26B-A4B</td>
          <td>abertos</td>
          <td style="text-align: right">57,44</td>
          <td style="text-align: right">121 ms</td>
      </tr>
      <tr>
          <td>3</td>
          <td>Decider chat Gemma-4-31B</td>
          <td>Gemma 4 31B</td>
          <td>código aberto sobre modelo aberto</td>
          <td style="text-align: right">57,33</td>
          <td style="text-align: right">109 ms</td>
      </tr>
      <tr>
          <td>4</td>
          <td>pplx-decider-v1-27b</td>
          <td>Qwen3.8-27B</td>
          <td>abertos</td>
          <td style="text-align: right">56,40</td>
          <td style="text-align: right">101 ms</td>
      </tr>
      <tr>
          <td>5</td>
          <td>simple-jev Qwen3.8-27B</td>
          <td>Qwen3.8-27B</td>
          <td>código aberto sobre modelo aberto</td>
          <td style="text-align: right">55,74</td>
          <td style="text-align: right">373 ms</td>
      </tr>
      <tr>
          <td>6</td>
          <td>Jebadiah 27B</td>
          <td>Qwen3.8-27B</td>
          <td>abertos</td>
          <td style="text-align: right">54,67</td>
          <td style="text-align: right">110 ms</td>
      </tr>
      <tr>
          <td>7</td>
          <td>Eikos-27B</td>
          <td>Qwen3.8-27B</td>
          <td>abertos</td>
          <td style="text-align: right">53,13</td>
          <td style="text-align: right">130 ms</td>
      </tr>
      <tr>
          <td>8</td>
          <td>reflex 27B</td>
          <td>Qwen3.8-27B</td>
          <td>código aberto sobre modelo aberto</td>
          <td style="text-align: right">52,16</td>
          <td style="text-align: right">108 ms</td>
      </tr>
      <tr>
          <td>9</td>
          <td>Decider chat Qwen3.6-27B</td>
          <td>Qwen3.6-27B</td>
          <td>código aberto sobre modelo aberto</td>
          <td style="text-align: right">51,35</td>
          <td style="text-align: right">84 ms</td>
      </tr>
      <tr>
          <td>10</td>
          <td>Winnow-12B</td>
          <td>Gemma 4 12B</td>
          <td>abertos</td>
          <td style="text-align: right">50,02</td>
          <td style="text-align: right">73 ms</td>
      </tr>
      <tr>
          <td>19</td>
          <td>Hopper (G) 1.2</td>
          <td>Qwen3.5-4B, LoRA</td>
          <td>abertos</td>
          <td style="text-align: right">40,77</td>
          <td style="text-align: right">23 ms</td>
      </tr>
      <tr>
          <td>27</td>
          <td>Kev 9B</td>
          <td>Qwen3.5-9B, LoRA</td>
          <td>abertos</td>
          <td style="text-align: right">38,48</td>
          <td style="text-align: right">51 ms</td>
      </tr>
      <tr>
          <td>55</td>
          <td>Lavoir</td>
          <td>ModernBERT-large</td>
          <td>abertos</td>
          <td style="text-align: right">8,69</td>
          <td style="text-align: right">20 ms</td>
      </tr>
      <tr>
          <td>57</td>
          <td>CLM-v0.1-8B (Stanford e Nvidia)</td>
          <td>Qwen3-8B</td>
          <td>abertos</td>
          <td style="text-align: right">7,40</td>
          <td style="text-align: right">47 ms</td>
      </tr>
      <tr>
          <td>61</td>
          <td>Laya</td>
          <td>ModernBERT-large</td>
          <td>abertos</td>
          <td style="text-align: right">6,04</td>
          <td style="text-align: right">6 ms</td>
      </tr>
  </tbody>
</table>
<p>Três leituras saem direto da tabela:</p>
<ol>
<li>O único modelo fechado da tabela é o Jev. Ele lidera, mas por meio ponto sobre um fine-tune aberto de um Gemma 4 de 26 bilhões de parâmetros, e o placar trata diferença abaixo de 0,25 como empate. Os dez primeiros são todos modelos abertos de 12 a 32 bilhões de parâmetros com adaptador em cima, exatamente a receita que o Clef descreve.</li>
<li>O encoder pequeno zero-shot fica no fundo: Laya com 6, Lavoir com 9. Isso bate com o que o README do Laya admite e com o que eu disse sobre classificador clássico, que precisa de exemplo rotulado pra brilhar.</li>
<li>Um LoRA de 4 bilhões como o Hopper entrega 41 pontos a 23 milissegundos, uma faixa que muito problema real não precisa ultrapassar.</li>
</ol>
<p>E como ler o Laya no fundo da tabela? O Decision Index mede uma coisa só: responder, sem treino extra, 38 tipos de pergunta que o modelo nunca viu, de xadrez a tributação. Isso é o que um serviço hospedado precisa fazer, porque não sabe qual pergunta vem. Um encoder de 400 milhões de parâmetros nunca vai ganhar essa prova, e o Laya nem tenta: a nota de 6 é o checkpoint base, sem ajuste nenhum.</p>
<p>O mesmo modelo ajustado com os seus exemplos, numa tarefa estável, aparece com 0,77 no benchmark do próprio projeto. O ranking responde &ldquo;quem é o melhor generalista zero-shot&rdquo;, que é a pergunta de quem vende API. A pergunta do programador normal é outra: &ldquo;nesta decisão repetida, com os exemplos que eu tenho, o que acerta mais pelo custo que eu aceito?&rdquo;. Pra essa, o fundo da tabela pode ser a resposta certa, e nenhum placar público substitui o teste no seu dado.</p>
<p>Então o Laya é inútil perto dos outros? Como generalista zero-shot, sim, e o placar está certo em dizer isso. Como ferramenta de programador, a conta é outra. É o único modelo dessa tabela que roda em CPU de notebook e responde em 6 milissegundos, com 400 milhões de parâmetros que cabem em qualquer servidor que você já tem; Hopper e Kev pedem GPU, e o Jev pede internet, chave de API e um contrato de dados.</p>
<p>Ajustado com os seus exemplos, numa taxonomia que não muda toda semana, o próprio autor do Laya relata o modelo ganhando do Jev em algumas tarefas e perdendo onde há muitas opções, em testes publicados por terceiros com prompts e amostras diferentes, portanto indicativos e não controlados. Ou seja: inútil pra responder qualquer pergunta sobre qualquer texto, e muito útil pra responder a mesma pergunta mil vezes por dia, de graça, sem mandar dado pra fora.</p>
<p>O Clef não está no placar: o 0.2.1 fechou em 27 de setembro, e a Cloudflare lançou o modelo no dia 1º. Os números que mostrei na seção anterior são de uma rodada interna da Cloudflare em cima das mesmas tarefas, por benchmark, sem o índice agregado. Também já tem fornecedor dizendo que passou do Jev no mesmo scorer, mas por enquanto é número autodeclarado em blog, e não entrada no placar. Vale esperar a inclusão oficial antes de comparar.</p>
<p>Rodar você mesmo é trabalho de um dia, e o kit cuida da parte chata:</p>
<ol>
<li><code>pip install -e &quot;.[transformers,rebuild]&quot;</code> e <code>python -m decision_index suite rebuild</code>. A suíte não é redistribuída por causa de licença, então o kit baixa as fontes (uns 7 GB, com o HLE exigindo aceitar os termos no Hugging Face) e reconstrói os arquivos com hash verificado contra o do laboratório.</li>
<li><code>python -m decision_index suite sample --n 100</code> pra um teste rápido, e depois <code>pipeline --engine http --option base_url=... --option model=...</code> contra qualquer servidor que fale o formato <code>POST /v1/systemone</code>. Isso cobre o próprio Jev, com a chave da API, e o Laya atrás do Arbiter. A API do Clef é anunciada como compatível, então em tese entra pelo mesmo caminho, mas eu não testei.</li>
<li><code>score</code> aplica a mesma matemática do placar, e os mantenedores afirmam que ela reproduz todos os 67 participantes da edição atual. Quem tem GPU na nuvem roda tudo como um job único do Hugging Face numa RTX PRO 6000 com <code>hf-job</code>.</li>
</ol>
<p>Eu não rodei a suíte inteira pra este texto; a tabela acima é o arquivo do placar refeito, e não uma medição minha. Duas ressalvas de quem usa esse tipo de régua: a suíte é pública e congelada, então dá pra treinar contra ela, e o próprio placar diz que a saída da API do Jev já mudou em 20 escolhas da amostra de latência desde a rodada original, sem mudar a nota. Benchmark público serve pra descartar modelo fraco e pra achar candidato. A decisão final continua sendo o seu conjunto rotulado, como eu explico a seguir.</p>
<h2>Como programador deve pensar nisso<span class="hx:absolute hx:-mt-20" id="como-programador-deve-pensar-nisso"></span>
    <a href="#como-programador-deve-pensar-nisso" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A pergunta útil deixou de ser &ldquo;o Jev é novidade?&rdquo;. Virou: pra uma decisão específica, medida, do seu sistema, qual combinação de qualidade, preço, latência, privacidade, contexto e manutenção bate o que você já tem, seja regra, classificador ou LLM com saída estruturada? Nenhum benchmark de fornecedor responde isso sem os seus próprios exemplos rotulados.</p>
<p>Ferramenta do tipo Jev serve quando o mesmo tipo de julgamento sobre texto acontece muitas vezes, as ações possíveis cabem numa lista, o código em volta consegue aplicar regra exata, e uma resposta errada pode ser detectada ou mandada pra revisão. É esse o formato:</p>
<ul>
<li>triagem de ticket;</li>
<li>ranking de uma lista curta já recuperada;</li>
<li>roteamento de pedido pra modelo maior ou menor;</li>
<li>sinalização de trace de agente pra revisão humana;</li>
<li>escolha entre spans que o código ou o OCR já encontraram.</li>
</ul>
<p>Fora dele, a ferramenta está no lugar errado:</p>
<ul>
<li>quando a entrada é imagem ou áudio;</li>
<li>quando a saída precisa de prosa ou citação;</li>
<li>quando um parser exato já resolve;</li>
<li>quando um erro de classificação concede acesso ou executa ação destrutiva.</li>
</ul>
<p>Olhei a minha própria carteira de projetos com essa régua, e o resultado é um balde de água fria útil: a maioria precisa de modelo especialista de visão ou áudio, de regra determinística ou de texto gerado, e tem pouca decisão repetida, cara e ambígua o suficiente pra justificar mais um serviço de modelo. Uns poucos candidatos sobraram, os mais claros sendo roteamento de modelo no <a href="/2026/03/16/reescrevi-o-openclaw-em-rust-funcionou-frankclaw/">FrankClaw</a> e ranking de lista curta no <a href="/2026/09/02/ai-memory-2-0-melhor-sistema-memoria-agentes-e-times/">ai-memory</a>. Nenhum é gargalo demonstrado hoje. Suspeito que a sua carteira seja parecida.</p>
<p>Se um gargalo aparecer, o piloto é curto:</p>
<ol>
<li>Escolha uma decisão só e defina as respostas permitidas, incluindo &ldquo;não sei&rdquo; quando isso for um resultado real.</li>
<li>Separe exemplos reais, com caso fácil, ambíguo e adversarial, e rotule de forma independente. Se o seu produto fala português, inclua português.</li>
<li>Compare o que você já tem, uma regra ou classificador simples, o Jev com versão fixa, e um LLM barato com saída estruturada, todos com a mesma entrada e a mesma política de decisão.</li>
<li>Meça matriz de confusão, calibração por faixa de confiança, custo por caso tratado corretamente, latência de ponta a ponta e taxa de revisão. Roteador barato que manda trabalho difícil pra modelo fraco custa mais no total.</li>
<li>Implante como feature reversível, com log, rota conservadora de revisão e fallback. Julgamento de segurança ou autorização é consultivo, salvo se uma política exata aplicar a ação de forma independente.</li>
</ol>
<p>O que o Jev fez de bom foi lembrar a indústria de que classificação existe. Isso vale o hype que ele recebeu, e talvez um pouco mais.</p>
<p>Nem ele nem os primos abertos dele são bala de prata. São mais uma ferramenta, pra um tipo específico de tarefa, que o seu código precisa cercar com regra, calibração e revisão. Quem já pensava em classificador antes de setembro não ganhou nada novo; ganhou uma API conveniente. Quem nunca tinha pensado ganhou a parte mais valiosa, que é a pergunta: por que você estava pedindo pra um LLM de bilhões de parâmetros escrever um parágrafo pra te dizer em qual balde o texto cai?</p>
]]></content:encoded><category>inteligencia-artificial</category><category>llms</category><category>engenharia-de-software</category></item><item><title>Os Limites das LLMs: Boas em reproduzir o que existe. Caras pro que não existe</title><link>https://akitaonrails.github.io/2026/09/28/llms-sao-boas-em-reproduzir-o-que-existe-e-coisas-novas/</link><guid isPermaLink="true">https://akitaonrails.github.io/2026/09/28/llms-sao-boas-em-reproduzir-o-que-existe-e-coisas-novas/</guid><pubDate>Mon, 28 Sep 2026 01:00:00 -0300</pubDate><description>&lt;p&gt;Todo mundo já percebeu que LLM escreve CRUD de olhos fechados. Formulário, relatório, endpoint REST, teste unitário: sai bonito, sai rápido. Muita gente conclui daí que programador acabou.&lt;/p&gt;
&lt;p&gt;Eu uso LLM pra tudo há quase dois anos, publiquei dezenas de projetos com elas, e minha conclusão é outra: o que elas fazem de melhor é &lt;strong&gt;reproduzir o que já existe&lt;/strong&gt;. E isso cobre uma fatia gigante do trabalho corporativo, não se engane. Mas tem uma fronteira que elas não cruzam com facilidade, e eu passei os últimos meses esbarrando nela de propósito.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Todo mundo já percebeu que LLM escreve CRUD de olhos fechados. Formulário, relatório, endpoint REST, teste unitário: sai bonito, sai rápido. Muita gente conclui daí que programador acabou.</p>
<p>Eu uso LLM pra tudo há quase dois anos, publiquei dezenas de projetos com elas, e minha conclusão é outra: o que elas fazem de melhor é <strong>reproduzir o que já existe</strong>. E isso cobre uma fatia gigante do trabalho corporativo, não se engane. Mas tem uma fronteira que elas não cruzam com facilidade, e eu passei os últimos meses esbarrando nela de propósito.</p>
<p>Esse artigo mostra onde ela fica, com evidência dos meus próprios projetos e da pesquisa que existe sobre o assunto. E tem uma hipótese que eu já adianto aqui e defendo no decorrer do texto: se LLM é tão boa em código, os provedores têm muito a agradecer às décadas da comunidade open source, que protegeu a liberdade do código e publicou tudo de graça. Sem esse patrimônio, não existiria Copilot, Cursor, Claude Code, nada disso.</p>
<p>Um disclaimer antes de começar: o que eu vou argumentar aqui é especulativo, baseado em observação e nos dados públicos que existem. Ninguém fora dos laboratórios sabe exatamente como cada provedor treina os próprios modelos, e isso varia de provedor pra provedor e de versão pra versão. O que vale hoje pode não valer na próxima geração. Leve tudo com um grão de sal.</p>
<h2>O ponto cego do treinamento<span class="hx:absolute hx:-mt-20" id="o-ponto-cego-do-treinamento"></span>
    <a href="#o-ponto-cego-do-treinamento" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Todo LLM foi treinado no que é público. A internet pública inteira, e no caso de código, o GitHub público. O dataset canônico de código aberto, o <a href="https://huggingface.co/datasets/bigcode/the-stack-v2"target="_blank" rel="noopener">The Stack v2</a> da BigCode, é explícito sobre isso: ele é derivado do Software Heritage, um arquivo de <em>&ldquo;todo o código-fonte de software publicamente disponível&rdquo;</em>. São 67,5 TB, 3,28 bilhões de arquivos únicos, 104,2 milhões de repositórios. Gigantesco. E todo público.</p>
<p>Agora olha o outro lado. O <a href="https://github.blog/news-insights/octoverse/octoverse-a-new-developer-joins-github-every-second-as-ai-leads-typescript-to-1/"target="_blank" rel="noopener">Octoverse 2025</a>, relatório oficial do GitHub, diz que <strong>81,5% das contribuições na plataforma aconteceram em repositórios privados</strong>. Isso é só o GitHub. Fora dele tem:</p>
<ul>
<li>o código interno de toda empresa que nunca encostou num servidor público;</li>
<li>o fonte de todo software proprietário;</li>
<li>o código de todo jogo comercial;</li>
<li>e o de todo sistema embarcado.</li>
</ul>
<p>Nada disso nunca entrou no treino.</p>
<p>Pensa no que isso significa: o modelo conhece profundamente o que o mundo já publicou, e é cego pro que o mundo mantém fechado. Quando você pede um formulário React, ele está reproduzindo padrões que viu milhões de vezes. Quando você pede algo que ninguém nunca fez em público, ele está operando num território onde o mapa dele é branco.</p>
<h2>Por que tá todo mundo entregando tanto, tão rápido?<span class="hx:absolute hx:-mt-20" id="por-que-tá-todo-mundo-entregando-tanto-tão-rápido"></span>
    <a href="#por-que-t%c3%a1-todo-mundo-entregando-tanto-t%c3%a3o-r%c3%a1pido" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Antes de entrar nos limites, vale registrar o lado que funciona, porque é ele que explica a sensação de que todo mundo virou fábrica de app.</p>
<p>Olha o que tá pipocando na comunidade: o <a href="https://github.com/crmne/spotifast"target="_blank" rel="noopener">Spotifast</a> e o <a href="https://github.com/crmne/zapfast"target="_blank" rel="noopener">ZapFast</a>, clientes nativos de Spotify e WhatsApp escritos em Rust por uma pessoa só, rodando em Linux, macOS e Windows. Nada ali é tecnologia nova. É o serviço que já existia, embrulhado num app nativo enxuto, em cima de biblioteca que já existia, fazendo o que os times oficiais sempre puderam fazer mas nunca quiseram gastar o tempo deles. Esse trabalho ficou barato, porque LLM treinada em tudo que é público é boa demais justamente nisso: replicar.</p>
<p>Meus próprios projetos seguem o mesmo padrão. O <a href="https://github.com/akitaonrails/FrankMD"target="_blank" rel="noopener">FrankMD</a> é um web app de notas em Markdown com cara de Visual Studio e features que já existiam nos meus outros apps. O <a href="https://github.com/akitaonrails/FrankSherlock"target="_blank" rel="noopener">Frank Sherlock</a> é um organizador de imagens local que, no fundo, é um gerenciador de arquivos com thumbnails e busca, coisa que existe aos montes. Nenhum dos dois inventa nada: são mashups de peças conhecidas, montadas do jeito que eu sempre quis. A LLM faz a parte chata, e é por isso que a velocidade aparece.</p>
<p>O exemplo mais didático é o meu cliente de email. Uso o Geary há anos, e duas faltas pequenas sempre me irritaram: o autocomplete de destinatário fraco e um painel lateral que eu queria poder esconder. Coisa boba, que nunca justificou montar ambiente de build, aprender o toolchain do projeto e estudar o código só pra duas features. Esse ano eu finalmente resolvi os dois: um <a href="https://github.com/akitaonrails/geary-email-autocomplete"target="_blank" rel="noopener">módulo de autocomplete</a>, um <a href="https://github.com/akitaonrails/geary-hide-sidebar-module"target="_blank" rel="noopener">módulo pra esconder o painel</a>, e um <a href="https://github.com/akitaonrails/frank_geary"target="_blank" rel="noopener">fork inteiro com meus patches</a>. Virei mantenedor de melhorias que adiei por anos, não porque eu fiquei mais rápido, mas porque a parte chata ficou barata.</p>
<p>Repara no que todos esses casos têm em comum: o problema já tinha sido resolvido antes, em outro lugar, de outro jeito. O mapa existia; o que não existia era mão de obra barata pra refazer o caminho. É a reprodução trabalhando a favor, e é por isso que o seu feed tá cheio de gente entregando app novo toda semana.</p>
<p>Agora guarda esse raciocínio. O resto desse artigo é sobre o que acontece quando o mapa acaba.</p>
<h2>Quatro experimentos caseiros<span class="hx:absolute hx:-mt-20" id="quatro-experimentos-caseiros"></span>
    <a href="#quatro-experimentos-caseiros" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Eu não tô teorizando. Nos últimos meses eu rodei uma maratona de projetos de retrocomputação que são exatamente o caso patológico: trabalhar com software proprietário de 30 ou 40 anos atrás, cujo código-fonte nunca foi público. É o ponto cego perfeito.</p>
<h3>nes-to-sms: o projeto que eu desisti<span class="hx:absolute hx:-mt-20" id="nes-to-sms-o-projeto-que-eu-desisti"></span>
    <a href="#nes-to-sms-o-projeto-que-eu-desisti" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>O <a href="https://github.com/akitaonrails/nes-to-sms"target="_blank" rel="noopener">nes-to-sms</a> é um recompilador estático de NES pra Master System. A ideia: pegar a ROM binária de um jogo de NES, traduzir instrução por instrução de 6502 pra Z80, converter os tiles, e gerar um ROM de Master System que roda no hardware real. Esqueça emulador e port manual: é uma máquina que transforma um jogo num outro.</p>
<p>Recompilador estático de NES existe, o <a href="https://github.com/mstan/nesrecomp"target="_blank" rel="noopener">NESRecomp</a> traduz pra C e roda nativo em PC, e eu estudei ele de perto. Mas cruzar de um console pra outro console de 8 bits, com orçamento de clock e de VDP totalmente diferente, ninguém nunca fez. Não existe referência pública, não existe paper, não existe projeto abandonado pra copiar.</p>
<p>Os números do projeto: <strong>349 commits, 31 dias ativos espalhados por quase 4 meses, ~110 mil linhas de engine em Rust e Z80, 668 testes passando no último run registrado no README</strong>. E o resultado? Super Mario Bros. jogável (lento, com áudio limitado, mas jogável), com a trajetória de RAM byte a byte igual à do NES numa <a href="https://github.com/akitaonrails/nes-to-sms/blob/master/docs/completion-plan.md"target="_blank" rel="noopener">rota de ~4.900 frames</a> (o diff deixa o áudio e parte do buffer de VRAM de fora). Castlevania jogável na fase 1. SMB3 renderizando. E uma fila de jogos que bootam três frames e morrem.</p>
<p>E não foi por falta de empurrar os modelos. Só nesse projeto:</p>
<ul>
<li>passaram <strong>quatro gerações de Claude</strong> (Opus 4.7, Fable 5, Opus 4.8, Fable 5.1), com 213 commits co-assinados e 104 commits linkados a sessões no histórico, mais sessões de Codex nos trechos sem co-autoria, com direito a handoff documentado entre agentes;</li>
<li>teve até auditoria entre gerações: uma sessão nova de agente <a href="https://github.com/akitaonrails/nes-to-sms/blob/master/docs/mapper-continuation-review.md"target="_blank" rel="noopener">revisou os 55 commits anteriores</a> e reverteu conclusões que a geração anterior tinha exagerado;</li>
<li>só a caçada aos travamentos do Castlevania consumiu 45 commits em 5 dias;</li>
<li>o sprint final de setembro foram 176 commits em 17 dias antes de eu decretar a pausa;</li>
<li>e as regressões estão registradas pelo nome no histórico: <em>&ldquo;H.7 tried and reverted&rdquo;</em>, <em>&ldquo;record the reverted map-bank-hold attempt&rdquo;</em>, <em>&ldquo;correct-but-reverted result&rdquo;</em>, além de três hipóteses de alavanca compartilhada testadas e rejeitadas nos últimos três dias de projeto.</li>
</ul>
<p>Tokens eu não medi de forma confiável nesse projeto, então não vou inventar número. Mas 349 commits com 668 testes segurando cada passo já dão uma ideia do custo.</p>
<p>Repara no detalhe que importa: o único jogo que ficou realmente pronto é o Super Mario Bros. Por quê? Porque SMB é o jogo mais dissecado da história. Existe uma <a href="https://gist.github.com/1wErt3r/4048722"target="_blank" rel="noopener">disassembly completa e pública</a> que a comunidade usa há mais de uma década, com cada função nomeada e comentada. Eu alimentei isso no perfil do jogo e a LLM tinha um mapa completo pra trabalhar. Pros outros jogos, não existe mapa. E sem mapa, cada jogo novo morria alguns frames depois do boot por divergência de fluxo de controle, e cada um exigia uma caçada forense instrução por instrução que não rendia nada pro jogo seguinte.</p>
<p>O próprio projeto documentou o padrão de giro. Teve uma campanha inteira de otimização que durou semanas tentando cortar o custo de emular flags do 6502 no Z80.</p>
<p>Aí em setembro eu parei pra comparar com o <a href="https://github.com/lackoftrack27/Super-Mario-Bros.-SMS"target="_blank" rel="noopener">port manual que um hacker chamado lackoftrack27 fez de SMB pra Master System</a>, escrito por um humano, rotina por rotina. Pela <a href="https://github.com/akitaonrails/nes-to-sms/blob/master/docs/handport-comparison.md"target="_blank" rel="noopener">análise que a gente fez do código dele</a>, o port humano roda dentro do orçamento de frame, com uma folga que estimamos em ~90% de utilização. A minha máquina, depois de meses de otimização, ainda precisava de overclock.</p>
<p>E o documento de análise cravou por quê: quando removemos 30% das chamadas de emulação de flag, o tempo mal se moveu.</p>
<blockquote>
  <p><strong>As flags nunca foram o gargalo.</strong></p>

</blockquote>
<p>A otimização certa era redesenhar a estrutura de dados: transpor o array de objetos pra páginas de RAM. É um truque que depende de saber que &ldquo;o registrador X aqui é sempre um índice de objeto&rdquo;.</p>
<p>Essa invariante existe na cabeça do programador que escreveu o jogo em 1985. Ela não existe no fluxo de instruções. Um tradutor estático não tem como descobri-la. E o LLM, por meses, não descobriu.</p>
<p>O banner de pausa que eu escrevi no README é direto: a paridade em hardware real &ldquo;pode ser fundamentalmente inalcançável&rdquo; e, citando, <em>&ldquo;this may be a limit of the current frontier coding models as much as of the approach&rdquo;</em>.</p>
<h3>gg-to-sms: o pivô pro território com mapa<span class="hx:absolute hx:-mt-20" id="gg-to-sms-o-pivô-pro-território-com-mapa"></span>
    <a href="#gg-to-sms-o-piv%c3%b4-pro-territ%c3%b3rio-com-mapa" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>No mesmo dia em que pausei o nes-to-sms, eu comecei o gg-to-sms: converter jogos de Game Gear pra Master System com a tela alargada. A diferença que importa é que esse problema <strong>não é novo</strong>. A cena de romhacking vem convertendo jogos de GG pra SMS à mão há vinte anos, e o catálogo que eu montei no projeto contou ~186 deles. Ou seja: existe corpus, existe ground truth, existe padrão pra aprender.</p>
<p>Resultado: em um dia de trabalho,</p>
<ul>
<li>a fase de pesquisa estava completa;</li>
<li>o catálogo dos 373 jogos de GG estava montado;</li>
<li>o scanner de pontos de patch foi validado contra patches humanos reais, acertando os endereços com margem de 8 bytes;</li>
<li>e de quebra a ferramenta achou bugs de verdade em patches de vinte anos atrás que a cena inteira nunca tinha notado.</li>
</ul>
<p>O modelo era o mesmo; o que mudou foi o problema, que dessa vez tem referência.</p>
<p>E mesmo assim: até agora, zero jogos passaram na revisão de aceitação do viewport. O ponto novo do projeto (a máquina que gera os patches sozinha, que é a parte que ninguém nunca fez) continua por fazer.</p>
<h3>super-mario-deluxe-fixed: quatro dias e 436 milhões de tokens<span class="hx:absolute hx:-mt-20" id="super-mario-deluxe-fixed-quatro-dias-e-436-milhões-de-tokens"></span>
    <a href="#super-mario-deluxe-fixed-quatro-dias-e-436-milh%c3%b5es-de-tokens" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Esse foi um sprint de 4 dias, praticamente uma sessão única de Codex que consumiu <strong>436 milhões de tokens de input</strong>. O objetivo: rodar Super Mario Bros. Deluxe de Game Boy Color com tela alargada em resolução de NES, coisa que nenhuma ferramenta existente faz com sprites vivos.</p>
<p>Subiu pra jogável em 4 dias. Mas olha o alicerce: um emulador pronto vendado como dependência, e uma disassembly dormente do jogo que alguém tinha publicado anos atrás, que a própria documentação do projeto chama de &ldquo;o artefato mais importante&rdquo;.</p>
<p>O trabalho novo foi o renderizador customizado, e ele parou em 21 de 32 fases completadas. As que faltam travam em timing de plataforma móvel. O projeto tá parado no meio do sprint desde então, e ainda não desisti dele.</p>
<p>E um detalhe que diz muito: eu tive que dirigir o QA olhando screenshots, porque o agente entregava coisa com glitch gráfico e não percebia sozinho.</p>
<h3>super-mario-bros-35: tudo que funcionou tinha dono<span class="hx:absolute hx:-mt-20" id="super-mario-bros-35-tudo-que-funcionou-tinha-dono"></span>
    <a href="#super-mario-bros-35-tudo-que-funcionou-tinha-dono" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Esse é o clone offline do Super Mario Bros. 35, o battle royale que a Nintendo tirou do ar. O que funcionou nele: tudo que foi construído em cima de artefato existente.</p>
<ul>
<li>O engine é uma reconstrução em C feita por outra pessoa com Ghidra.</li>
<li>Os pesos iniciais da IA vieram de checkpoints publicados.</li>
<li>As regras de rede foram inferidas de um reverse engineering público do netcode.</li>
<li>Até a física: o bug central foi diagnosticado porque eu tinha uma trajetória de referência gravada pra comparar frame a frame.</li>
</ul>
<p>O que não funcionou: as fases de castelo com labirinto. O treinamento por reforço estaciona nelas. 46 milhões de passos de agente, reinício de treino do zero, recompensa anti-loop, e no fim a única coisa que resolveu uma das fases foi cirurgia manual de bias no modelo treinado. Das 32 fases, 19 limpas. As piores continuam travadas.</p>
<p>E o processo degenerou num padrão que eu reconheço de todos esses projetos: quando o treinamento não resolve, o fluxo vira roleta de seleção de checkpoint, dezenas de variações de bias e de cabeças de saída, jogando permutação e computação no problema no lugar de uma correção de princípio.</p>
<h2>O padrão que eu sinto<span class="hx:absolute hx:-mt-20" id="o-padrão-que-eu-sinto"></span>
    <a href="#o-padr%c3%a3o-que-eu-sinto" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Isso é intuição de quem operou a máquina por meses, não dado duro. Mas o padrão se repete com Claude, com GPT, com Kimi, com GLM, então não parece defeito de um modelo.</p>
<p>O começo de qualquer projeto é uma maravilha. Os primeiros milestones voam, porque montar estrutura, escrever harness, replicar API, isso tudo é território coberto. Aí o projeto chega na parte que ninguém nunca fez, e a velocidade desaba. O agente começa a girar: tenta uma hipótese, regride outra coisa, reverte, tenta de novo. O histórico de commits do nes-to-sms tá cheio de mensagens honestas tipo &ldquo;tentativa revertida&rdquo; e &ldquo;hipótese fechada com resultado correto mas revertido&rdquo;. Muito token queimado, pouco avanço.</p>
<blockquote>
  <p>Minha leitura do que acontece por dentro: o sampling de tokens é probabilístico. Quando o problema é parecido com o treino, os tokens certos têm probabilidade alta e a resposta sai direto. Quando o problema é inédito, a probabilidade do caminho certo é baixa, e o processo vira uma <strong>força bruta direcionada</strong>: tentativa e erro guiada, mas tentativa e erro mesmo assim.</p>

</blockquote>
<p>A saída que eu encontrei pra esse giro é sempre a mesma: dar um oráculo. Se eu consigo definir &ldquo;o resultado tem que ser igual a X&rdquo; (uma imagem de referência, uma trajetória gravada, um emulador ciclo-exato como ground truth), a máquina consegue iterar até esbarrar no X. No nes-to-sms, cada destravamento real veio disso: a disassembly do SMB, o frame-diff, o emulador de referência. Quando eu não consigo definir o X direito, ela gira indefinidamente.</p>
<p>A segunda estratégia que funciona: caçar projeto abandonado, paper, qualquer material que o modelo nunca viu mas que aproxima o problema, e enfiar no contexto. Isso aquece a distribuição e melhora muito o resultado. Mas é limitado: se nada parecido existe, não tem o que alimentar.</p>
<h2>Não é anedota, é o que a pesquisa mede<span class="hx:absolute hx:-mt-20" id="não-é-anedota-é-o-que-a-pesquisa-mede"></span>
    <a href="#n%c3%a3o-%c3%a9-anedota-%c3%a9-o-que-a-pesquisa-mede" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A parte boa é que eu não preciso depender da minha intuição. Tem pesquisa séria medindo exatamente isso.</p>
<p>O estudo <a href="https://arxiv.org/abs/2410.05229"target="_blank" rel="noopener">GSM-Symbolic da Apple</a> pegou problemas de matemática de benchmark e fez duas coisas simples: trocou só os números, e depois adicionou uma única frase irrelevante no enunciado. Resultado: a performance cai só de trocar os números, e despenca <strong>até 65%</strong> com a frase irrelevante. A hipótese dos autores, no texto: <em>&ldquo;LLMs atuais não fazem raciocínio lógico genuíno; eles replicam passos de raciocínio dos dados de treino&rdquo;</em>.</p>
<p>O <a href="https://arxiv.org/abs/2405.00332"target="_blank" rel="noopener">GSM1k da Scale AI</a> criou um espelho do GSM8K escrito do zero por humanos, garantidamente sem contaminação, e viu quedas de até 8% em várias famílias de modelo, com sinais de overfitting sistemático nas piores. Pra ser justo com o paper: os autores dizem que os modelos de fronteira mostram sinais mínimos de overfitting e que todos generalizam até certo ponto pra problemas novos. O sinal existe, o tamanho dele é discutível.</p>
<p>O <a href="https://arxiv.org/abs/2403.07974"target="_blank" rel="noopener">LiveCodeBench</a> fez o teste mais limpo de todos: avaliar em problemas de código publicados <strong>depois</strong> do corte de treinamento. Performance inflada em problema pré-corte e queda em problema pós-corte em vários modelos populares, o sinal clássico de contaminação.</p>
<p>E tem o <a href="https://arcprize.org/"target="_blank" rel="noopener">ARC-AGI</a>, o benchmark do François Chollet desenhado especificamente pra ser à prova de memorização: cada tarefa é inédita, nenhuma parecida existe no treino. No ARC-AGI-2, lançado em março de 2025, a tabela oficial diz: <strong>LLMs puros marcam 0%</strong>, sistemas de raciocínio ficam em dígito único, e cada tarefa de avaliação foi resolvida por pelo menos dois humanos em até duas tentativas. O Chollet, aliás, resumiu minha tese melhor que eu, lá em fevereiro de 2024:</p>
<blockquote>
  <p>&ldquo;LLMs não são AGI, são um grande ajuste de curva num dataset muito grande. Funcionam por memorização e interpolação. Mas essa curva interpolativa pode ser tremendamente útil, se você quer automatizar uma tarefa conhecida que casa com a distribuição do treino. Memorização funciona, desde que você não precise se adaptar ao novo.&rdquo;</p>

</blockquote>
<p>No mundo real, o estudo que mais me impressionou foi o <a href="https://arxiv.org/abs/2507.09089"target="_blank" rel="noopener">RCT da METR</a>: 16 desenvolvedores experientes, 246 tarefas reais nos próprios repositórios maduros deles, randomizado com e sem IA. Os devs apostavam que IA ia acelerar 24%. Mediu-se: <strong>ficou 19% mais lento</strong>. Repara onde isso aconteceu: código maduro, privado, cheio de contexto que o modelo nunca viu. Exatamente o ponto cego.</p>
<p>E o benchmark favorito da indústria pra dizer que &ldquo;IA já faz engenharia de software&rdquo;, o SWE-bench, é só Python, 12 repositórios open source famosos, ou seja, a fatia mais coberta do treino. A métrica de sucesso da indústria mede o território com mapa.</p>
<p>Até a literatura de código legado diz a mesma coisa: um <a href="https://arxiv.org/abs/2604.03986"target="_blank" rel="noopener">paper de 2026 sobre LLMs gerando COBOL</a> crava que, nessas linguagens legadas, <em>&ldquo;a maior parte do código de produção está em sistemas corporativos e raramente é publicamente disponível&rdquo;</em>. É a tese desse artigo, dita por outras pessoas.</p>
<h2>O steelman: força bruta direcionada funciona, a preço de ouro<span class="hx:absolute hx:-mt-20" id="o-steelman-força-bruta-direcionada-funciona-a-preço-de-ouro"></span>
    <a href="#o-steelman-for%c3%a7a-bruta-direcionada-funciona-a-pre%c3%a7o-de-ouro" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Antes de fechar, vale encarar o argumento mais forte contra mim. Steelman é isso, pra quem não conhece o termo: o oposto de espantalho. Em vez de atacar a versão mais fraca do argumento contrário, você responde à versão mais forte que ele pode ter. E ela existe e é boa.</p>
<p>Em maio de 2025 o DeepMind publicou o <a href="https://deepmind.google/discover/blog/alphaevolve-a-gemini-powered-coding-agent-for-designing-advanced-algorithms/"target="_blank" rel="noopener">AlphaEvolve</a>: um sistema que achou um algoritmo de multiplicação de matrizes 4x4 complexas com 48 multiplicações escalares, melhorando o recorde do Strassen de 1969 nesse cenário específico. Numa lista de mais de 50 problemas abertos de matemática, ele redescobriu o estado da arte em ~75% dos casos e melhorou a melhor solução conhecida em 20%. Isso é novidade de verdade, não reprodução.</p>
<p>O o3-preview da OpenAI saltou pra 75,7% no ARC-AGI-1 em dezembro de 2024, 22 pontos acima do melhor resultado anterior no mesmo conjunto de avaliação, e a configuração de compute alto chegou a 87,5% a um custo estimado de US$ 4.560 por tarefa.</p>
<p>E lá em 2016 o AlphaGo fez o lance 37 contra Lee Sedol, um lance que os dados do próprio DeepMind estimavam ter 1 chance em 10 mil de ser jogado por um humano, provando que busca sobre modelo pode transcender imitação.</p>
<p>Agora olha o mecanismo dos três:</p>
<ul>
<li>O AlphaEvolve é um loop evolutivo: o LLM propõe mutações, um avaliador automático pontua, a seleção itera.</li>
<li>O o3 faz síntese de programas em tempo de teste, explorando o espaço de soluções.</li>
<li>O AlphaGo é busca em árvore sobre aprendizado por reforço.</li>
</ul>
<p>Se teve &ldquo;insight&rdquo; em algum deles, foi do sistema de busca ao redor do modelo: os três são <strong>força bruta direcionada com um verificador barato</strong>, o mesmo mecanismo que eu descrevi acontecendo nos meus projetos. A diferença é que o DeepMind tem oráculo perfeito e orçamento infinito: na configuração que chegou a 87,5%, o o3-preview gastava milhares de dólares por tarefa do ARC pra fazer o que um humano faz de graça. A própria ARC Prize escreveu a ressalva:</p>
<blockquote>
  <p><em>&ldquo;Sabemos que uma busca de força bruta poderia acabar resolvendo o ARC-AGI, dados recursos e tempo de busca ilimitados. Isso não representaria inteligência de verdade.&rdquo;</em></p>

</blockquote>
<p>Resumindo: novidade sai, mas sai por busca cara sobre um oráculo, à base de tentativa e erro guiada. Se o seu problema tem verificador barato e você tem tokens pra queimar, dá pra ir longe. Foi assim que o nes-to-sms chegou onde chegou: 668 testes e ground truth de emulador segurando cada passo. Mas quando não tem oráculo, não tem corpus e não tem referência, você está pagando força bruta em dólar, com regressões no caminho, e o teto aparece.</p>
<p>E quando a força bruta vence, dá pra medir o tamanho da tentativa e erro. Dois casos recentes que eu já cobri <a href="/2026/09/09/propagandas-enganosas-da-openai-anthropic-nvidia/">em detalhe aqui no blog</a>:</p>
<ul>
<li><strong>A prova de Navier-Stokes da OpenAI:</strong> cerca de 10 mil agentes rodando em paralelo por 88 horas, queimando na casa de <strong>130 bilhões de tokens</strong> de saída num único problema. O Noam Brown, da OpenAI, confirmou que o resultado &ldquo;custou milhões&rdquo;, e a <a href="https://www.newscientist.com/article/2588063-openai-has-solved-the-navier-stokes-millennium-problem-using-15m-of-ai-effort/"target="_blank" rel="noopener">New Scientist estimou uns US$ 15 milhões a preço de tabela</a>. E nem essa montanha de compute partiu do zero: a prova se apoiou no maquinário que matemáticos humanos publicaram ao longo de décadas atacando o problema e os problemas irmãos. Sem o mapa dos humanos e sem o orçamento da OpenAI, não tem prova.</li>
<li><strong>O incidente da Hugging Face:</strong> a reconstrução forense contou <strong>~17.600 ações de atacante</strong> até os agentes conseguirem executar código em 41 servidores de produção da Hugging Face e pegar root; de quebra, no ambiente da própria OpenAI, leram 956 segredos do gerenciador de segredos da empresa. Não foi um insight brilhante de um lance só: foi um enxame executando tentativa atrás de tentativa, com verificação automática dizendo o que colou. A &ldquo;inteligência&rdquo; da manchete é volume.</li>
</ul>
<p>É esse o tamanho da conta quando você força o modelo pra fora do território do treino: tentativa e erro em escala industrial, sem garantia nenhuma de que a busca acha o que você precisa. E quem pode assinar esse cheque é meia dúzia de empresa no mundo, nível OpenAI e Anthropic, com orçamento praticamente ilimitado de compute. Pro Zé da esquina, com cartão de crédito e uma API key, o teto chega muito, muito antes.</p>
<h2>Mas tentativa e erro não é aprendizado novo?<span class="hx:absolute hx:-mt-20" id="mas-tentativa-e-erro-não-é-aprendizado-novo"></span>
    <a href="#mas-tentativa-e-erro-n%c3%a3o-%c3%a9-aprendizado-novo" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Aqui mora uma confusão que eu vejo toda hora, e vale desfazer porque ela contamina a interpretação de tudo que eu escrevi até agora.</p>
<p>Quando você lê que a Anthropic tem data centers do tamanho de cidades, dá a sensação de que existe uma IA gigante usando aquelas máquinas todas ao mesmo tempo, pensando, acumulando experiência a cada interação. A realidade é bem mais medíocre que isso.</p>
<p>Um modelo tipo Fable ou Astra é um arquivo de computador. Arquivo estático, nem banco de dados é: depois que o treinamento e o pós-alinhamento terminam, aquele arquivo é trancado e fica read-only. O que roda no data center são cópias desse arquivo. Cada usuário que consome o modelo está executando uma cópia dele num servidor diferente, isolada das demais, sem colaborar com nenhuma. A sua sessão não conversa com a sessão de ninguém, e nada do que acontece nela volta pro arquivo original.</p>
<p>Aprendizado novo só entra num lugar: na próxima leva de treinamento. Quando a Anthropic tinha o Opus 4.7 e lançou o 4.8, foi ali que conhecimento novo foi assado no modelo, num processo que custa milhões e leva semanas. Fora disso, o arquivo não muda um byte.</p>
<blockquote>
  <p>Seu agente queimando milhões de tokens em tentativa e erro está contribuindo exatamente zero de aprendizado novo pro modelo que ele usa.</p>

</blockquote>
<p>Aquela maratona de 176 commits do nes-to-sms? Do ponto de vista do modelo, não aconteceu. O Opus que rodou o último commit sabia exatamente o mesmo tanto que o do primeiro. Quem aprendeu alguma coisa fui eu, não ele. E é por isso que a metáfora do &ldquo;estagiário que aprende com o tempo&rdquo; está errada: estagiário acumula. Modelo não. O que acumula na maratona é o seu contexto, suas notas, seu <code>CLAUDE.md</code>, seus testes. O ativo que você constrói é seu, e evapora se você não documentar.</p>
<p>Essa é também a resposta pra quem acha que &ldquo;é só deixar o agente rodando que ele aprende o domínio&rdquo;. Ele não aprende domínio nenhum: ele explora o espaço com o conhecimento congelado do dia do treino, e no dia seguinte acorda com amnésia. Se o domínio não estava no treino, cada sessão sua recomeça do zero absoluto, e toda a inteligência de navegação tem que vir de você de novo.</p>
<h3>&ldquo;Mas e se a IA treinar a IA?&rdquo;<span class="hx:absolute hx:-mt-20" id="mas-e-se-a-ia-treinar-a-ia"></span>
    <a href="#mas-e-se-a-ia-treinar-a-ia" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Essa é a pergunta seguinte do amador, e ela parte de uma premissa errada: a de que isso seria novidade. IA treinando IA existe há décadas e tem nome: <strong>aprendizado por reforço</strong>. O AlphaGo já fazia isso em 2016, jogando milhões de partidas contra si mesmo. O <a href="https://arxiv.org/abs/1712.01815"target="_blank" rel="noopener">AlphaZero</a>, em 2017, levou a ideia ao limite: aprendeu xadrez, shogi e Go partindo do zero absoluto, sabendo só as regras de cada jogo, e chegou a nível sobre-humano em questão de horas de self-play, sem ver uma única partida humana.</p>
<p>LLMs também já usam reforço. O RLHF que transforma um modelo base em assistente é aprendizado por reforço, e a geração dos modelos de raciocínio levou isso adiante: o <a href="https://arxiv.org/abs/2501.12948"target="_blank" rel="noopener">DeepSeek-R1-Zero</a> mostrou em janeiro de 2025 que comportamento de raciocínio (auto-verificação, reflexão, cadeias longas de pensamento) emerge de RL puro, sem fine-tuning supervisionado. É o AlphaZero aplicado a matemática e código.</p>
<p>Agora repare no que esses exemplos têm em comum: só funciona onde existe <strong>recompensa verificável e barata</strong>. Jogo tem placar, matemática tem prova, código tem teste. Fora desse território não tem de onde tirar o sinal de recompensa. É o mesmo oráculo do steelman, só que institucionalizado: eficaz, caríssimo e nichado. O AlphaZero joga Go melhor que qualquer humano que já existiu e não sabe fazer absolutamente mais nada.</p>
<p>E tem o detalhe que derruba a pergunta por completo: todo esse aprendizado acontece <strong>no laboratório, durante o treino</strong>. O AlphaZero que o DeepMind mostrou pro mundo já era um artefato congelado. O R1 que você baixa é um arquivo estático igualzinho aos outros.</p>
<blockquote>
  <p>IA treinando IA produz um arquivo novo. O arquivo, uma vez lançado, continua sem aprender nada.</p>

</blockquote>
<p>Ou seja, a resposta mais sofisticada pra objeção não enfraquece a conclusão da seção: reforça. E o mercado já sabe disso. Desde o fim de 2024 os laboratórios admitem, em on e off the record, que os retornos de escala estão encolhendo: a <a href="https://www.reuters.com/technology/artificial-intelligence/openai-others-seek-new-path-smarter-ai-current-methods-hit-limitations-2024-11-11/"target="_blank" rel="noopener">Reuters reportou em novembro de 2024</a> que OpenAI, Google e Anthropic colhiam ganhos menores que o esperado no pre-training, com o Orion da OpenAI decepcionando a ponto de ser rebaixado de GPT-5 pra GPT-4.5. O Ilya Sutskever, o cara que basicamente inventou a tese do scaling, subiu no palco do <a href="https://www.youtube.com/watch?v=WQQdd6qGxNs"target="_blank" rel="noopener">NeurIPS 2024</a> pra declarar que &ldquo;pre-training como conhecemos vai acabar&rdquo;: os dados públicos são combustível fóssil, e a gente já raspou o fundo. Os ganhos de RL pós-treino são reais, mas incrementais. A era do salto de ordem de grandeza a cada geração ficou pra trás.</p>
<h2>Onde isso deixa a profissão<span class="hx:absolute hx:-mt-20" id="onde-isso-deixa-a-profissão"></span>
    <a href="#onde-isso-deixa-a-profiss%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A pergunta que motivou esse artigo é a que eu ouço toda semana: &ldquo;LLM vai substituir programador?&rdquo; Minha resposta ficou mais precisa depois desses meses: <strong>vai substituir a parte do trabalho que é reprodução</strong>.</p>
<p>E essa parte é grande. Formulário, relatório, CRUD, integração com API documentada, migração de framework: isso tudo já existe mil vezes no treino, e a máquina reproduz melhor que a maioria dos humanos. Quem só faz isso está mesmo com os dias contados.</p>
<p>Mas o trabalho que é de verdade novo continua humano:</p>
<ul>
<li>o sistema que ninguém construiu;</li>
<li>o domínio sem documentação;</li>
<li>o código proprietário que você não pode mostrar pro modelo;</li>
<li>o problema em que você não sabe nem escrever o teste que define &ldquo;certo&rdquo;.</li>
</ul>
<p>Tudo isso depende do que nunca foi publicado: a invariante que existe na cabeça de quem entende o problema, e não no fluxo de instruções.</p>
<p>Confesso que teve uma hora em que eu achei que a conta ia fechar pro lado do legado: finalmente uma ferramenta capaz de dar conta do COBOL que assombra banco e governo até hoje. Depois desses meses, acho que esse problema vai demorar muito mais do que parecia. Não existe uma comunidade open source gigante de COBOL. Quase todo esse código é privado, e privado de verdade: banco, seguradora, governo. Não tem material de treino, ou tem muito pouco. O modelo não sabe o que fazer com código que nunca viu, e COBOL de produção é quase tudo código que ele nunca viu.</p>
<p>Fecha o raciocínio: <strong>LLM consegue replicar o que é aberto, mas não adivinha o que é privado.</strong> E aí volta a hipótese da introdução. Se esses modelos são bons em código, é porque décadas de comunidade open source lutaram pra manter código livre, público e reutilizável, e os provedores treinaram em cima desse patrimônio sem pagar um centavo de licença por ele. O mínimo que a indústria de IA deve ao mundo é reconhecer isso: a capacidade dela é, em grande parte, a nossa generosidade compilada.</p>
<p>A ironia final: o programador que sobrevive é justamente o que sabe construir oráculo, definir teste, caçar referência obscura e reconhecer quando o agente começou a girar. Ou seja, a habilidade que a máquina mais precisa de você é a que ela menos consegue aprender com o treino dela. Por enquanto, isso não é um emprego ameaçado. É um emprego diferente.</p>
]]></content:encoded><category>llms</category><category>agentes-de-codigo</category><category>retrocomputacao</category><category>engenharia-de-software</category></item><item><title>Parem de inventar desculpas e façam mais deploy! Com a IA, a premissa mudou. Entendam.</title><link>https://akitaonrails.github.io/2026/09/22/parem-de-inventar-desculpas-e-facam-mais-deploy-a-premissa-mudou/</link><guid isPermaLink="true">https://akitaonrails.github.io/2026/09/22/parem-de-inventar-desculpas-e-facam-mais-deploy-a-premissa-mudou/</guid><pubDate>Tue, 22 Sep 2026 16:00:00 -0300</pubDate><description>&lt;p&gt;Hoje eu soltei uma sequência de posts no X batendo nessa tecla e, como sempre que eu falo de deploy rápido, um bocado de gente leu &amp;ldquo;esse cara está dizendo pra subir qualquer porcaria em produção sem testar&amp;rdquo;. Não é isso. Deixa eu explicar com calma, porque o argumento é mais estreito e mais chato do que a versão que espalha pânico.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;É melhor deployar mais rápido, porque corrigir depois ficou rápido e barato.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Hoje eu soltei uma sequência de posts no X batendo nessa tecla e, como sempre que eu falo de deploy rápido, um bocado de gente leu &ldquo;esse cara está dizendo pra subir qualquer porcaria em produção sem testar&rdquo;. Não é isso. Deixa eu explicar com calma, porque o argumento é mais estreito e mais chato do que a versão que espalha pânico.</p>
<blockquote>
  <p>É melhor deployar mais rápido, porque corrigir depois ficou rápido e barato.</p>

</blockquote>
<p>Essa frase é o artigo inteiro resumido. O resto é só eu justificando por que ela é verdade agora, mesmo não sendo verdade há alguns anos, e mostrando como eu mesmo ajo em cima dela desde fevereiro.</p>
<h2>A premissa mudou, e a maioria não percebeu<span class="hx:absolute hx:-mt-20" id="a-premissa-mudou-e-a-maioria-não-percebeu"></span>
    <a href="#a-premissa-mudou-e-a-maioria-n%c3%a3o-percebeu" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Comecei a falar isso <a href="https://x.com/AkitaOnRails/status/2102436061083267441"target="_blank" rel="noopener">no X</a> assim:</p>
<blockquote>
  <p>Corrigir ficou barato. Não segurem coisas mais. Só sobe e corrige depois. &ldquo;Ain mas corro o risco de subir com bug&rdquo;. A premissa errada é achar que vc ficar olhando linha a linha vai fazer qualquer diferença num volume grande. E código parado não melhora sozinho. Só código usado dá pra descobrir se precisa melhorar.</p>

</blockquote>
<p>E completei <a href="https://x.com/AkitaOnRails/status/2102476036709450066"target="_blank" rel="noopener">no segundo post</a>, porque a primeira leitura de qualquer coisa que eu escrevo em 280 caracteres sempre vem raivosa e literal demais:</p>
<blockquote>
  <p>Entendam o conceito (é post de X, não de blog, parem de ler literalmente). Não estou dizendo que IA não gera bugs. Gera, óbvio. Mas a esta altura do campeonato, não mais do que você/humano gera também. [&hellip;] Antigamente a desculpa era que quando sobe em produção com bug, ele fica lá mais tempo do que deveria, porque nunca vira prioridade na sprint pra resolver. Agora NÃO TEM MAIS ISSO, a premissa mudou: corrigir o bug depois é RÁPIDO e BARATO.</p>

</blockquote>
<p>Esse é o ponto inteiro. Não é sobre IA ser infalível. É sobre o custo de corrigir um erro ter despencado, e a maioria dos times ainda estar operando o processo de revisão como se esse custo continuasse alto.</p>
<p>Com os modelos de fronteira de hoje, Opus, Sol, K3, e companhia, o LLM erra menos do que a maioria dos desenvolvedores humanos que eu já vi passar por um code review. Quando erra, na esmagadora maioria das vezes o erro não é do modelo. É de quem dirigiu o harness. O LLM faz o que você pede, e não faz o que você não pediu.</p>
<p>Se você não sabe o que pedir, não vai produzir nada útil, não importa quão bom seja o modelo. É exatamente por isso que só Engenheiro de Software de verdade consegue tirar software de produção de verdade de um agente: alguém tem que saber decompor o problema, validar o resultado, e reconhecer quando o pedido em si estava mal formulado. IA não substitui esse julgamento. Ela multiplica o que esse julgamento já sabia fazer.</p>
<h2>Isso já era pra ser assim há 25 anos<span class="hx:absolute hx:-mt-20" id="isso-já-era-pra-ser-assim-há-25-anos"></span>
    <a href="#isso-j%c3%a1-era-pra-ser-assim-h%c3%a1-25-anos" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O incômodo que eu sinto com o processo de review burocrático não é novo, e a indústria já devia ter resolvido isso há muito tempo. Kent Beck e Ron Jeffries inventaram Extreme Programming em 1997, no projeto Chrysler C3, e Beck publicou o livro em 1999 com integração contínua, TDD e entrega em lotes pequenos como práticas centrais. Em fevereiro de 2001, dezessete desenvolvedores se trancaram num resort em Snowbird, Utah, e saíram de lá com o Manifesto Ágil. Isso faz vinte e cinco anos.</p>
<p>O mantra de Martin Fowler pra integração contínua sempre foi &ldquo;se dói, faça com mais frequência&rdquo;, e o livro <em>Continuous Delivery</em>, de Jez Humble e Dave Farley, formalizou a ideia de que deploy pequeno e frequente reduz risco, não aumenta. Os relatórios anuais de State of DevOps da DORA documentam isso com número desde a década passada:</p>
<ul>
<li>time de elite: deploya sob demanda, várias vezes por dia;</li>
<li>time de baixa performance: deploya uma vez por mês, às vezes uma vez a cada seis meses.</li>
</ul>
<p>E o achado mais chato de engolir pra quem tem medo de deployar rápido: historicamente, deploy mais frequente <strong>não aumenta</strong> a taxa de falha. <em>Reduz.</em> Time que deploya mais, na média dos relatórios da última década, falha menos e recupera mais rápido quando falha.</p>
<p>Mesmo com tudo isso documentado, medido e publicado há mais de uma década, boa parte da indústria continua represando mudança em lote grande, com revisão manual demorada, e chamando isso de &ldquo;prudência&rdquo;. Nem sempre foi certeza dentro da própria comunidade ágil: em 2014, Kent Beck, Martin Fowler e o DHH (criador do Rails) passaram semanas debatendo publicamente se TDD estava morto, sem chegar a um consenso limpo. Ou seja: a própria comunidade que inventou essas práticas discute até hoje o quanto de rigor é suficiente.</p>
<p>O que eu estou dizendo é mais simples que essa discussão inteira: seja qual for o seu nível de rigor de teste, o LLM revisando seu diff antes do merge é rápido, e reverter um deploy ruim ficou trivial com container e git. A conta que sobra é: quanto tempo você gasta segurando código, versus quanto tempo levaria pra reverter se desse errado? Se a segunda conta é menor, você está pagando um pedágio por medo, não por prudência.</p>
<h2>Não é &ldquo;suba qualquer coisa&rdquo;<span class="hx:absolute hx:-mt-20" id="não-é-suba-qualquer-coisa"></span>
    <a href="#n%c3%a3o-%c3%a9-suba-qualquer-coisa" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Essa é a parte que sempre se perde: eu não estou dizendo pra deployar sem nenhuma prática de engenharia por baixo. Estou dizendo o oposto. Isso só é seguro <strong>depois</strong> que você já tem a engenharia de software básica funcionando, o que eu documento à exaustão neste blog há anos: teste automatizado, CI que roda em todo push, capacidade real de reverter, observabilidade pra saber quando algo quebrou.</p>
<blockquote>
  <p>80/20. Peça pra LLM fazer uma revisão mínima e sobe. Se quebrar, reverte (pra isso temos containers, git, etc etc). Se não dá pra reverter, sua infra é uma bosta - corrija ela pra ontem.</p>

</blockquote>
<p>Essa última frase é o filtro inteiro. Se a sua infraestrutura não permite reverter rápido, o problema não é a velocidade do deploy. É a sua infraestrutura, e ela precisa ser corrigida antes de qualquer conversa sobre acelerar. Ninguém está liberado pra pular a etapa de ter rollback de verdade. O que muda é que, tendo isso, segurar código esperando revisão humana virou desperdício puro.</p>
<h2>O ambiente mínimo recomendado<span class="hx:absolute hx:-mt-20" id="o-ambiente-mínimo-recomendado"></span>
    <a href="#o-ambiente-m%c3%adnimo-recomendado" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Eu já falei &ldquo;engenharia de software básica&rdquo; várias vezes neste texto sem detalhar o que isso significa na prática. Aqui está a lista, sem enrolação. Nenhum item aqui é opcional, e nenhum deles ficou caro de manter:</p>
<ul>
<li>teste unitário cobrindo a lógica isolada, TDD ou não, contanto que exista;</li>
<li>teste de cenário e integração cobrindo concorrência, falha parcial e conflito, o que teste unitário sozinho não pega;</li>
<li>CI que builda e testa em toda mudança, de preferência pras plataformas que você realmente publica;</li>
<li>revisão automática hostil antes do merge, tipo <code>pr-audit</code>, que trata alegação do contribuidor como não verificada até prova;</li>
<li>feature flag pra controlar o raio de explosão de quem vê a mudança primeiro;</li>
<li>staging de verdade como gate antes de qualquer usuário real ver a mudança;</li>
<li>capacidade de reverter rápido, com git e container, e observabilidade pra saber quando algo quebrou;</li>
<li>em ambiente de compliance, financeiro ou de saúde, uma camada extra: teste de cenário mais pesado, e mais de uma trava por modo de falha identificado.</li>
</ul>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/09/22/deploy-environment-diagram.png" alt="Diagrama do pipeline mínimo pra deploy rápido e seguro: commit, testes automatizados, CI multiplataforma, feature flag, staging e produção, com uma seta de rollback voltando de produção pros testes e uma seta de feedback voltando de produção pro commit"  loading="lazy" /></p>
<p>O que o diagrama tenta deixar claro é que velocidade e segurança não competem entre si aqui. Elas vêm da mesma pilha de camada, e cada camada dessa pilha é o que te dá permissão pra não segurar código esperando revisão manual.</p>
<h2>Onde essa conta não fecha<span class="hx:absolute hx:-mt-20" id="onde-essa-conta-não-fecha"></span>
    <a href="#onde-essa-conta-n%c3%a3o-fecha" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Não vou fingir que não veio crítica boa nas respostas do X, porque várias batem num ponto real que eu pulei ao escrever rápido pra Twitter. Vale mais responder de verdade do que só validar quem concordou.</p>
<ol>
<li>
<p><strong>Reverter código não desfaz consequência que já saiu do seu sistema.</strong> Se o bug já processou um pagamento errado, moveu dinheiro pra conta errada, ou controlou um elevador, reverter o deploy não desfaz o que já aconteceu. &ldquo;Se não dá pra reverter, sua infra é uma bosta&rdquo; cobre a parte técnica de deploy e rollback, não o caso onde o dano já saiu do seu sistema antes de você conseguir reagir. Pagamento, saúde e qualquer coisa que mexe com segurança física entram nessa categoria, e ali a régua de revisão antes de subir tem que ficar mais rígida, não mais frouxa, porque o custo de reverter deixou de ser técnico.</p>
</li>
<li>
<p><strong>Banco de dados quebra a analogia de &ldquo;reverter é fácil&rdquo;.</strong> Reverter um binário é trivial. Reverter uma migration que já rodou em produção, já moveu dado, e talvez já apagou coluna, não é. Existe um padrão pra isso, <em>expand-contract</em>: adiciona o novo formato sem remover o velho, espera todo consumidor migrar, só depois remove o velho. Isso não é sobre confiar mais ou menos em IA. É sobre estado que não se desfaz com <code>git revert</code>.</p>
</li>
<li>
<p><strong>Biblioteca e pacote público não seguem a mesma conta que aplicação fechada.</strong> Quando o meu código quebra, eu conserto na hora. Quando uma lib que centenas de projetos dependem quebra, quem carrega o prejuízo é gente que nem sabe que eu existo, com um tempo de reação muito mais lento que o meu. É por isso que a minha skill de <code>pr-audit</code>, que eu descrevo mais abaixo, trata classificação de semver como gate de versão: breaking change anda em major, nunca em patch, porque ali a revisão de verdade não é sobre pegar bug, é sobre não surpreender quem depende de você sem avisar.</p>
</li>
<li>
<p><strong>Loja de app derruba a velocidade também</strong>, e o meu próprio exemplo do frank_yomik esconde isso em vez de resolver. Ele publica o APK direto como GitHub Release, sem passar pela Play Store. Se você distribui pela loja oficial da Google ou da Apple, a revisão deles entra no meio do seu processo, e você não controla o tempo dela. Este artigo é sobre remover o gargalo que está dentro do seu controle. A loja de app não está dentro dele.</p>
</li>
<li>
<p><strong>O ponto mais honesto de todos: toda evidência que eu trago aqui vem de projeto onde eu sou o único dono e decido sozinho.</strong> Não tenho como provar, com meus próprios números, que o mesmo ritmo funciona dentro de uma empresa grande, com Jurídico, Compliance e gerente de produto no meio do caminho. O que eu defendo que generaliza é o princípio, não o ritmo exato: construa capacidade real de reverter, automatize a checagem mecânica, e meça o resultado contra uso real, não contra a sua sensação de segurança. Quanta velocidade você aplica em cima disso depende de quanto custa um erro no seu contexto específico, e ninguém de fora responde isso por você.</p>
</li>
</ol>
<p>Sobre o primeiro ponto especificamente, vale abrir mais, porque &ldquo;régua mais rígida&rdquo; não pode ficar vago. Isso significa teste de cenário real, não só teste unitário. O próprio ai-memory tem mais de mil testes de integração espalhados pelos seus módulos, e a maioria não pergunta &ldquo;essa função devolve o valor certo?&rdquo;. Pergunta coisa como:</p>
<ul>
<li>o que acontece quando duas escritas concorrem pelo mesmo arquivo ao mesmo tempo;</li>
<li>o que acontece quando o disco falha no meio de uma operação de exclusão;</li>
<li>o que acontece quando duas sessões tentam consolidar o mesmo dado ao mesmo tempo;</li>
<li>o que acontece quando o processo morre antes de terminar de escrever.</li>
</ul>
<p>Ambiente com exigência de compliance, financeiro ou de saúde, precisa desse nível de teste: todo modo de falha identificado tem que ter mitigação, e mais de uma camada de checagem, nunca uma trava só.</p>
<p>E aqui está o ponto que sustenta o argumento inteiro deste artigo mesmo nesses ambientes: essa exigência não muda dependendo de quem escreveu o código. Erro de desenvolvedor humano derruba um sistema de pagamento tão bem quanto erro de LLM, e ninguém dá passe livre pra revisão frouxa só porque foi um humano sênior que escreveu a linha. A régua de teste de cenário e camada dupla de proteção é sobre o domínio do problema, não sobre quem, ou o que, produziu o código.</p>
<p>Feature flag e ambiente de staging são a outra metade dessa camada dupla, e eles também mudaram de custo. Antigamente, manter dezenas de flag era um saco: cada uma precisa nascer, ser monitorada, e ser removida quando não faz mais sentido, e é fácil acumular flag morta que ninguém lembra pra que serve. Isso ficou barato também: peço pro agente auditar todo flag do projeto, achar qual está travada no mesmo valor há meses, e gerar o PR de limpeza. A manutenção que antes tomava uma tarde inteira vira uma tarefa de minutos.</p>
<p>Com isso resolvido, a defesa em camada fica simples de montar: staging pra pegar erro óbvio antes de qualquer usuário ver, feature flag pra limitar o raio de explosão de quem vê a mudança primeiro, e teste de cenário pra cobrir o que staging sozinho não simula. Três camadas, nenhuma delas cara de manter.</p>
<h2>Como eu faço isso desde fevereiro<span class="hx:absolute hx:-mt-20" id="como-eu-faço-isso-desde-fevereiro"></span>
    <a href="#como-eu-fa%c3%a7o-isso-desde-fevereiro" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Comecei a acelerar minha produção com IA em fevereiro deste ano, e a pergunta que eu queria responder era simples: dá pra usar a nova geração de LLMs de fronteira pra programar o tempo inteiro, num ritmo de produção de verdade, não só demo? A resposta virou meu <a href="/2026/09/15/novo-llm-benchmark-v4-retestando-todos-llms-parte-1/">maior benchmark de LLMs</a>, mais de 110 artigos publicados desde então, e isto, como eu <a href="https://x.com/AkitaOnRails/status/2102176881139138806"target="_blank" rel="noopener">escrevi recentemente</a>:</p>
<blockquote>
  <p>Desde fevereiro produzi mais de 110 artigos no meu blog. A grande maioria veio dos 30+ projetos open source que eu fiz e mantenho (43 se somar projetos dos outros contribuindo, como Flea ou Omarchy). 1.6 milhão de linhas de código produzidos. Eu sozinho (com agentes, claro).</p>

</blockquote>
<p>Os projetos que eu mais uso no meu próprio dia a dia, e que sobreviveram ao teste de &ldquo;eu continuo mantendo isso meses depois&rdquo;, são três:</p>
<ul>
<li><a href="https://aijail.io"target="_blank" rel="noopener">ai-jail</a>: sandbox de SO pros meus agentes de código;</li>
<li><a href="https://aimemorybr.netlify.app"target="_blank" rel="noopener">ai-memory</a>: memória de longo prazo pros agentes;</li>
<li>ai-usagebar: widget de barra pra monitorar consumo de LLM.</li>
</ul>
<p>Dois deles já têm landing page decente:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/09/22/aijail-hero.png" alt="Landing page do ai-jail, um sandbox de sistema operacional pra agentes de IA"  loading="lazy" /></p>
<p>O ai-jail subiu hoje. O ai-memory está no ar em <a href="https://aimemorybr.netlify.app"target="_blank" rel="noopener">aimemorybr.netlify.app</a> porque a transferência do domínio <code>aimemory.io</code> ainda vai levar mais alguns dias.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/09/22/aimemory-hero.png" alt="Landing page do ai-memory, sistema de memória de longo prazo pra agentes de código"  loading="lazy" /></p>
<p>As duas rodam no Netlify. Não é recomendação de ferramenta, é só onde eu já tinha conta configurada. O ponto que importa aqui não é a plataforma, é o fluxo: pra colocar uma versão nova no ar, o comando é <code>git push</code>. Não existe passo manual entre o commit e o site atualizado.</p>
<p>A minha newsletter, <a href="https://themakitachronicles.com"target="_blank" rel="noopener">The M.Akita Chronicles</a>, já passa de 15 mil assinantes:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/09/22/themakitachronicles-hero.png" alt="Página de inscrição da newsletter The M.Akita Chronicles"  loading="lazy" /></p>
<p>E o esforço mais novo é converter os posts do blog em episódio de podcast. Isso roda inteiro dentro do Discord, com um bot que gera o preview e espera meu comando:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/09/22/discord-podcast-1.png" alt="Bot do Discord avisando que o preview de um episódio de podcast está pronto, com comandos pra publicar, agendar ou rejeitar"  loading="lazy" /></p>
<p>Um <code>/publish-podcast 2</code> depois, o episódio está publicado e a transcrição já tem URL:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/09/22/discord-podcast-2.png" alt="Bot do Discord confirmando que o episódio de podcast foi publicado, com link pra transcrição"  loading="lazy" /></p>
<p>Do texto pronto até o áudio publicado, o processo inteiro é eu digitando um comando de barra numa conversa de Discord. Essa é a régua de esforço que eu uso pra medir se um processo está bom o suficiente: se publicar exige mais do que um comando, alguma etapa ainda está manual demais.</p>
<h3>E a qualidade do código gerado, aguenta?<span class="hx:absolute hx:-mt-20" id="e-a-qualidade-do-código-gerado-aguenta"></span>
    <a href="#e-a-qualidade-do-c%c3%b3digo-gerado-aguenta" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Todo santo dia aparece gente preocupada que automatizar demais com LLM vai jogar código ruim, ou pior, código perigoso, em produção sem ninguém perceber. Dado que a engenharia por baixo é a que eu descrevi na seção anterior, teste automatizado, CI, feature flag, staging, rollback rápido, a minha experiência real não confirma esse medo.</p>
<p>Já produzi mais de 1,6 milhão de linhas de código com LLM desde fevereiro. <strong>Nunca vi um LLM fazer alguma coisa aleatoriamente destrutiva sem eu pedir.</strong> Pelo contrário: no meu <a href="/2026/09/15/novo-llm-benchmark-v4-retestando-todos-llms-parte-1/">LLM Benchmark v4</a>, montei de propósito um cenário adversarial, um subagente plantando catorze sabotagens reais baseadas em CVE, escondidas dentro de um projeto que cresce em sete sprints. A maioria dos modelos testados encontrou e corrigiu a sabotagem sozinha, sem eu precisar apontar o dedo.</p>
<p>Isso é anedótico. Não prova nada além do que aquele benchmark específico mede. Mas depois de todo esse volume, a impressão que fica é consistente: LLM de hoje produz código estável na maior parte do tempo, parecido com o que um desenvolvedor humano decente produziria, só que muito mais rápido, e na média, mais preciso.</p>
<h2>CI/CD multiplataforma sem esforço<span class="hx:absolute hx:-mt-20" id="cicd-multiplataforma-sem-esforço"></span>
    <a href="#cicd-multiplataforma-sem-esfor%c3%a7o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Fui contar quantos dos meus projetos <code>ai-*</code> e <code>frank-*</code> (18 repositórios no total, entre os que têm README) já têm build e deploy automatizado. Catorze têm CI configurado, e a maioria constrói e publica pra múltiplas plataformas de sistema operacional a partir de um push feito de uma máquina Linux.</p>
<p>O exemplo mais completo é o próprio ai-memory: um único push de tag dispara um workflow que, na mesma execução:</p>
<ul>
<li>builda Linux x86_64 e arm64;</li>
<li>builda macOS arm64 e x86_64;</li>
<li>builda Windows x86_64, com empacotamento em PowerShell;</li>
<li>publica uma imagem Docker multi-arquitetura;</li>
<li>empurra o pacote pro AUR do Arch Linux.</li>
</ul>
<p>O ai-usagebar segue o mesmo padrão de build pra Linux e Windows, e ainda publica em dois pacotes do AUR, no crates.io, e num bucket do Scoop pra Windows.</p>
<p>E tem o caso do frank_yomik, meu leitor de mangá com OCR e tradução via LLM local, que é o exemplo que eu queria pra mostrar que Android entra na mesma esteira. Um push de tag <code>v*</code> dispara cinco builds em paralelo:</p>
<ul>
<li>Linux;</li>
<li>macOS;</li>
<li>Windows;</li>
<li>extensão de navegador;</li>
<li>Android, num runner Linux comum, decodificando um keystore de assinatura guardado nos secrets do GitHub e gerando o APK já assinado.</li>
</ul>
<p>No final, um job espera os cinco terminarem e publica um único GitHub Release com todos os binários juntos. Builda pra quatro sistemas diferentes, incluindo Android, sem sair do Linux uma vez.</p>
<p>Nem tudo saiu perfeito na primeira olhada, e eu prefiro admitir isso a fingir que é tudo redondo: o frank_sherlock e o frank_karaoke publicam a release como rascunho por padrão, o que trava a automação seguinte (como o push pro AUR) até alguém clicar em &ldquo;publicar&rdquo; manualmente. Achei esse buraco enquanto escrevia este texto.</p>
<p>Um projeto vizinho, o frank_scanlation, já tinha resolvido um problema parecido, mas diferente: o GitHub suprime o evento que dispara automação quando a própria release foi criada pelo token do robô, então o workflow dele dispara a etapa seguinte na mão, via <code>workflow_dispatch</code>, de dentro do próprio job. Nenhum dos dois ajustes é difícil. Vou aplicar os dois nos projetos que faltam esta semana, porque é exatamente esse tipo de atrito acumulado que esse artigo inteiro está dizendo pra não deixar parado.</p>
<p>E já que estamos falando de atrito escondido: o ai-memory tem código específico pra Windows (índice de arquivo NTFS, hook nativo em PowerShell) que só roda de verdade no runner <code>windows-latest</code> do GitHub, uns 1000 segundos contra 250 no Linux pra mesma suíte. Cheguei a montar uma VM Windows local via <a href="https://github.com/dockur/windows"target="_blank" rel="noopener">dockur/windows</a> achando que ia ganhar velocidade.</p>
<p>Não ganhei: o workload é dominado por E/S de disco, e o resultado saiu mais lento que o runner do GitHub pra suíte inteira. Ficou útil só pra iteração rápida num crate isolado. Ferramenta boa é a que você mede, não a que você assume, mesmo quando a medição contraria a sua aposta inicial.</p>
<h2>A revisão automática que sustenta tudo isso<span class="hx:absolute hx:-mt-20" id="a-revisão-automática-que-sustenta-tudo-isso"></span>
    <a href="#a-revis%c3%a3o-autom%c3%a1tica-que-sustenta-tudo-isso" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Eu já <a href="/2026/09/17/falando-um-pouco-sobre-minhas-skills-de-ia/">detalhei minhas skills de revisão</a> num artigo recente, então vou resumir aqui:</p>
<ul>
<li><code>pr-audit</code> audita todo PR antes do merge com o princípio de <strong>evidence over narrative</strong>: nada do que o contribuidor escreveu é verdade até prova, com checklist hostil pra código malicioso, credencial exposta, quebra de semver e tentativa de prompt injection;</li>
<li><code>iss-audit</code> aplica a mesma desconfiança pra issue, nunca executando comando colado por quem reportou;</li>
<li><code>github-resolution</code> transforma o que foi aprovado em código mergeado, um ticket de cada vez, com teste de regressão escrito antes da correção, e a regra de que <em>&ldquo;slop é defeito&rdquo;</em>: sem abstração especulativa, sem TODO esquecido, sem enfraquecer teste pra passar mais rápido.</li>
</ul>
<p>Isso pega a categoria mais cara de porcaria dentro do mesmo diff. Não pega duplicação espalhada entre PRs diferentes, porque a auditoria olha um diff isolado, não a arquitetura inteira do projeto. Essa parte ainda depende de eu notar o padrão se repetindo e mandar consolidar.</p>
<p>Na minha estimativa, isso resolve uns 99% do trabalho de revisão e resolução sozinho, comigo supervisionando e decidindo os casos que sobram. Só que isso não é o ponto principal. Automação de revisão é necessária, mas ela sozinha não prova nada sobre se o software é bom.</p>
<h2>O que realmente mantém isso no chão: gente de verdade usando<span class="hx:absolute hx:-mt-20" id="o-que-realmente-mantém-isso-no-chão-gente-de-verdade-usando"></span>
    <a href="#o-que-realmente-mant%c3%a9m-isso-no-ch%c3%a3o-gente-de-verdade-usando" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Aqui está a parte que eu acho mais importante do artigo inteiro, e que costuma passar batido: a sua própria revisão não vale tanto quanto você acha. O que vale é software publicado sendo usado por gente de verdade, dando feedback de verdade.</p>
<p>Fui checar os números reais do ai-memory no GitHub, sem arredondar pra impressionar:</p>
<ul>
<li><strong>issues: 287 no total, 249 vieram de gente que não sou eu</strong>, 86,8% do total;</li>
<li><strong>pull requests: 562 no total, 371 de fora</strong>, sendo 10 delas bump automático do Dependabot e as outras 361 vindas de gente de verdade, cerca de 121 contribuidores distintos.</li>
</ul>
<p>Os dois que mais contribuíram junto comigo mandaram 64 e 43 PRs cada, sozinhos.</p>
<p>Isso é o que mantém o projeto no chão. Não é o LLM sendo bom revisor, nem eu sendo bom revisor. É centenas de pessoas usando de verdade, achando casos que eu nunca imaginei, e mandando issues e PRs reais. Sem isso, minhas skills de revisão automatizada estariam apenas confirmando as minhas próprias suposições de volta pra mim, por mais rigorosas que as regras pareçam no papel.</p>
<p>Não importa o quão boa é a IA que você usa: se ninguém usa o que você publicou, você não tem feedback real, e sem feedback real não existe melhoria real. Só existe a sua própria opinião sobre o próprio trabalho, validada por ninguém além de você mesmo.</p>
<h2>A conclusão que interessa<span class="hx:absolute hx:-mt-20" id="a-conclusão-que-interessa"></span>
    <a href="#a-conclus%c3%a3o-que-interessa" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Engenharia de software de verdade <strong>precisa</strong> ter deploy rápido e de esforço quase zero. Não é opcional, não é luxo de time grande, é pré-requisito. E se revisar e colocar em produção está demorando mais tempo do que desenvolver a funcionalidade, você não está só errado.</p>
<p><strong>Você é o gargalo.</strong></p>
<p>Desculpa e justificativa não valem nada nesse momento. Use esse tempo pra consertar você mesmo e o seu processo, porque só resultado no mundo real importa, não a sensação de segurança de ter revisado linha por linha um diff que ninguém mais vai olhar de novo.</p>
<p>Se a premissa mudou, eu mudo hoje. Não amanhã, não semana que vem. E se a sua ainda não mudou, o problema não é a IA. É você segurando o próprio trabalho.</p>
]]></content:encoded><category>devops</category><category>engenharia-de-software</category><category>agentes-de-codigo</category><category>vibe-coding</category></item><item><title>Fiz o Fable 5 analisar código do TikTok, Clash of Kings e Gov.br - Entendendo Fingerprint</title><link>https://akitaonrails.github.io/2026/07/08/fable-5-analisar-codigo-tiktok-clash-of-kings-govbr-fingerprint/</link><guid isPermaLink="true">https://akitaonrails.github.io/2026/07/08/fable-5-analisar-codigo-tiktok-clash-of-kings-govbr-fingerprint/</guid><pubDate>Wed, 08 Jul 2026 16:00:00 -0300</pubDate><description>&lt;p&gt;Deixa eu começar com o disclaimer mais importante do post inteiro, porque ele muda como você deve ler tudo daqui pra baixo: &lt;strong&gt;nada aqui é 100% factual.&lt;/strong&gt; Eu pedi pro Claude Fable 5 fazer uma análise completa do código de três apps Android, mas eu não tenho como garantir o quão fundo ele foi de verdade sem reauditar arquivo por arquivo na mão, e isso são centenas de milhares de arquivos por app. Então trata isso como um panorama, não como um laudo pericial.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Deixa eu começar com o disclaimer mais importante do post inteiro, porque ele muda como você deve ler tudo daqui pra baixo: <strong>nada aqui é 100% factual.</strong> Eu pedi pro Claude Fable 5 fazer uma análise completa do código de três apps Android, mas eu não tenho como garantir o quão fundo ele foi de verdade sem reauditar arquivo por arquivo na mão, e isso são centenas de milhares de arquivos por app. Então trata isso como um panorama, não como um laudo pericial.</p>
<p>E tem mais camadas de incerteza. Os APKs vieram do <a href="https://apkpure.com/"target="_blank" rel="noopener">APKPure</a>, não da Play Store oficial, então existe a possibilidade (pequena, mas existe) de terem sido adulterados no caminho. E mesmo depois de descompilar, sobra um monte de biblioteca binária e SDK que a gente não abriu, assumindo que são libs comuns tipo Google Firebase ou Google Play Services. Esse mini-projeto foi, no fundo, curiosidade minha: eu queria saber o que tem dentro desses apps que a gente instala sem pensar.</p>
<h2>Descompilar Android é fácil demais<span class="hx:absolute hx:-mt-20" id="descompilar-android-é-fácil-demais"></span>
    <a href="#descompilar-android-%c3%a9-f%c3%a1cil-demais" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Uma coisa que muita gente não sabe: app Android é <strong>fácil demais</strong> de descompilar. O APK é basicamente um zip. Você descompacta, roda uma ferramenta como o <a href="https://github.com/skylot/jadx"target="_blank" rel="noopener">jadx</a> nos arquivos <code>.dex</code>, e sai Java legível do outro lado. Se o app é Flutter, dá pra reconstruir o Dart com o <a href="https://github.com/worawit/blutter"target="_blank" rel="noopener">Blutter</a>. Se é um jogo Cocos2d-x, muitas vezes os scripts Lua estão ali em texto puro, sem nem precisar descriptografar.</p>
<p>Isso <strong>não</strong> te deixa recompilar o app a partir do fonte (os nomes de classe e método vêm embaralhados pela ofuscação, faltam recursos, faltam as chaves de assinatura). Mas pra <strong>análise estática</strong> é mais que suficiente: dá pra ler os endpoints que o app contata, as permissões que ele pede, os identificadores que ele monta, os SDKs que ele embute. É exatamente esse tipo de leitura que eu pedi pro Fable 5 fazer.</p>
<p>Um limite honesto: a parte mais sensível costuma estar em <strong>código nativo</strong> (<code>.so</code>), C/C++ compilado, que não descompila em nada legível. No caso do TikTok, é justamente aí que mora o miolo, e volto nisso já já.</p>
<h2>&ldquo;Se é de graça, você é o produto&rdquo;<span class="hx:absolute hx:-mt-20" id="se-é-de-graça-você-é-o-produto"></span>
    <a href="#se-%c3%a9-de-gra%c3%a7a-voc%c3%aa-%c3%a9-o-produto" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Você já ouviu essa frase mil vezes. Ela é verdadeira, mas quase sempre fica no abstrato. Vamos concretizar: como exatamente você vira o produto? A resposta tem um nome técnico, e é o motivo de eu ter escolhido esse tema pro título: <strong>fingerprint</strong>.</p>
<p>Fingerprint (impressão digital do dispositivo) é um identificador persistente que a plataforma monta juntando dezenas de sinais do seu aparelho: modelo do celular, versão do sistema, resolução de tela, CPU, RAM, operadora, fuso horário, idioma, bateria, fontes instaladas, redes Wi-Fi e Bluetooth por perto, sensores de movimento, e por aí vai. Nenhum desses dados sozinho te identifica. Mas a <strong>combinação</strong> deles é tão específica que vira praticamente único, um &ldquo;número de série&rdquo; implícito do seu dispositivo que você nunca autorizou explicitamente.</p>
<p>O pulo do gato, e o motivo pelo qual isso é tão valioso, é a <strong>persistência</strong>. Um cookie você limpa. O identificador de anúncio você reseta. Mas um fingerprint bem montado sobrevive a você limpar os dados do app, sobrevive a reinstalar, às vezes sobrevive até a resetar o aparelho. Ele re-identifica você como a mesma pessoa depois de qualquer tentativa de recomeçar do zero. É por isso que as empresas querem tanto: com o fingerprint, elas cruzam seu comportamento entre apps, entre sessões, entre reinstalações, e montam um perfil que segue você mesmo quando você acha que apagou seus rastros. Esse perfil é o produto da tal frase. E o produto é você.</p>
<p>Os três apps que analisei mostram três pontos bem diferentes desse espectro, e é aí que a coisa fica interessante.</p>
<h2>Os três apps<span class="hx:absolute hx:-mt-20" id="os-três-apps"></span>
    <a href="#os-tr%c3%aas-apps" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><h3>TikTok: coleta grau industrial, blindada contra auditoria<span class="hx:absolute hx:-mt-20" id="tiktok-coleta-grau-industrial-blindada-contra-auditoria"></span>
    <a href="#tiktok-coleta-grau-industrial-blindada-contra-auditoria" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>O <a href="https://github.com/akitaonrails/tiktok_analysis"target="_blank" rel="noopener">tiktok_analysis</a> foi o mais denso. Versão 46.0.1, 37 arquivos dex, 204 bibliotecas nativas. A conclusão honesta, e que eu acho a mais justa: <strong>não é malware disfarçado, mas é coleta grau industrial projetada pra ser difícil de auditar.</strong></p>
<p>Do lado tranquilizador: nenhum servidor secreto. Todo host que o app contata é da TikTok/ByteDance ou de um fornecedor de anúncio/analytics <em>nomeado</em> (Adjust, AppsFlyer, Facebook, Google, ThreatMetrix, Amazon). Não achamos coleta de IMEI nem de MAC, não tem <code>QUERY_ALL_PACKAGES</code>, não lê SMS nem registro de chamadas. Dados de usuários dos EUA e da UE vão pra enclaves dedicados (o famoso Project Texas com a Oracle em Ashburn).</p>
<p>Do lado preocupante: ele coleta <strong>muito</strong>. Fingerprint persistente do dispositivo, localização precisa, varredura de Wi-Fi e Bluetooth, upload de contatos (se você habilitar &ldquo;encontrar amigos&rdquo;), sensores de movimento, e uma checagem contra uma lista fixa de <strong>91 apps nomeados</strong> pra ver quais você tem instalado (concorrentes, PayPal, Venmo, Spotify, apps irmãos da ByteDance). Seu ID de anúncio se espalha pra uns 6 terceiros.</p>
<p>E o achado central: o fingerprint e boa parte da telemetria são montados em <strong>código nativo</strong> (a <code>libmetasec_ov.so</code> e uma pilha de libs de cripto), com a assinatura de cada requisição saindo encriptada. Ou seja, mesmo descompilando o app inteiro, não dá pra saber exatamente quais bytes saem do aparelho.</p>
<p>Pra atacar justamente essa caixa-preta, uma das análises passou um <code>strings</code> nas 204 bibliotecas nativas (o <a href="https://github.com/akitaonrails/tiktok_analysis/blob/main/docs/13-native-library-analysis.md"target="_blank" rel="noopener">relatório 13</a> do repo), e aí a <code>libmetasec_ov.so</code> entrega o jogo em texto puro. Dá pra ler os campos que ela coleta (<code>secdeviceid</code>, <code>device_id</code>, nível e estado da bateria, tamanho da tela), a função que assina as requisições, os endpoints de telemetria da ByteDance cravados no binário, e até o agendador que dispara o envio num timer. O que a camada Java só deixava inferir, o nativo confirma. É uma máquina de fingerprint, sem tirar nem pôr.</p>
<p>E a mesma varredura foi atrás justamente do que todo mundo tem medo de achar (keylogger, gravador de tela, injeção de input) e não achou nada disso. Os hits assustadores de palavra-chave eram falsos amigos: <code>keylog</code> era o log de debug do TLS, <code>screenshot</code> era o player de vídeo e a autenticidade de conteúdo C2PA, <code>getevent</code> era nome de método de mídia. Tem anti-debug e detecção de frida/xposed, sim, mas é o app se inspecionando por dentro, coisa normal de biblioteca de segurança, não bisbilhotando o resto do celular.</p>
<p>Então a opacidade continua sendo o ponto, só que mais afiada: a gente sabe o que a <code>libmetasec_ov</code> faz e pra onde ela reporta, e o que segue trancado são os bytes exatos do payload, que só disassembly do nativo ou captura ao vivo revelariam. &ldquo;Não está provado que é spyware&rdquo; e &ldquo;coleta muito mais do que precisa, de forma opaca&rdquo; seguem verdadeiras ao mesmo tempo, agora com a confirmação em texto puro de que o motor de fingerprint é real.</p>
<h3>Clash of Kings: o jogo é honesto, a monetização é predatória<span class="hx:absolute hx:-mt-20" id="clash-of-kings-o-jogo-é-honesto-a-monetização-é-predatória"></span>
    <a href="#clash-of-kings-o-jogo-%c3%a9-honesto-a-monetiza%c3%a7%c3%a3o-%c3%a9-predat%c3%b3ria" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>O <a href="https://github.com/akitaonrails/clash_of_kings_analysis"target="_blank" rel="noopener">clash_of_kings_analysis</a> foi uma surpresa agradável no quesito privacidade. É um jogo de estratégia da chinesa Elex, engine Cocos2d-x com quase 12 mil scripts Lua em texto puro. E, olha só: <strong>sem GPS, sem câmera, sem microfone, sem contatos, sem SMS, sem IMEI.</strong> As duas leituras mais sensíveis que ele <em>pode</em> fazer (lista de apps instalados e MAC do Wi-Fi) são ambas condicionadas a consentimento. Nada de malware, nada de exfiltração escondida.</p>
<p>A preocupação de privacidade é o mesmo vilão do TikTok em versão mais simples: um <strong>UUID de dispositivo resistente a reset</strong>, gravado em quatro lugares diferentes (configurações do sistema, preferências, cartão SD e backup na nuvem) justamente pra sobreviver a uma reinstalação. Mais telemetria pra infra em região da China e pro Tencent Bugly.</p>
<p>Onde o Clash of Kings realmente pesa é na <strong>monetização</strong>. É o kit completo de free-to-play predatório: loot boxes (as &ldquo;luck draws&rdquo; de heróis), ofertas com contador regressivo pra criar FOMO, tiers VIP pay-to-win, escadas de gasto acumulado com ranking de quem gasta mais (a caça à &ldquo;baleia&rdquo;), cartão mensal, o pacote inteiro. O lado meio-copo-cheio: as probabilidades de drop são divulgadas no jogo, e existe o sistema chinês de anti-vício e nome-real pra menores. Privacidade decente, carteira em perigo.</p>
<h3>Gov.br: o exemplo de como fazer direito (com uma ressalva)<span class="hx:absolute hx:-mt-20" id="govbr-o-exemplo-de-como-fazer-direito-com-uma-ressalva"></span>
    <a href="#govbr-o-exemplo-de-como-fazer-direito-com-uma-ressalva" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>O <a href="https://github.com/akitaonrails/govbr_analysis"target="_blank" rel="noopener">govbr_analysis</a> é o contraponto, e me deixou até aliviado. É o app oficial de identidade digital do governo brasileiro, feito em Flutter (reconstruí o Dart com o Blutter). Pros padrões de um app de governo obrigatório, ele é <strong>bem construído e respeitoso com privacidade</strong>: o tráfego é quase todo pra <code>*.gov.br</code>, SERPRO e Dataprev, o TLS tem certificate pinning, as credenciais ficam no KeyStore criptografado do Android, a assinatura ICP-Brasil usa cripto grau FIPS, e o app se defende com força contra aparelho rooteado ou adulterado. E o mais importante: <strong>nenhum tracker comercial de anúncio.</strong> Nada de Segment, Adjust, AppsFlyer ou Meta.</p>
<p>As duas ressalvas honestas: ele embute o <strong>Google Firebase</strong> (Analytics, Crashlytics, Messaging, Remote Config) com coleta ligada por padrão e permissão de ad-id declarada, o que é o padrão preguiçoso de quase todo app hoje; e a sua <strong>selfie de prova de vida sobe pro backend do governo</strong> pra bater identidade, o que é inerente ao propósito e não vai pra terceiros. O item que só a captura de tráfego ao vivo resolveria é se o seu CPF vai anexado aos relatórios do Crashlytics. Mas no geral, se todo app fosse construído com esse cuidado, esse post nem existiria.</p>
<h2>O que quase todo app carrega junto<span class="hx:absolute hx:-mt-20" id="o-que-quase-todo-app-carrega-junto"></span>
    <a href="#o-que-quase-todo-app-carrega-junto" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Cruzando os três (e é aí que o padrão aparece), dá pra ver o que costuma vir embutido no app que você baixa, mesmo num app de governo:</p>
<ul>
<li><strong>Google Firebase / Play Services</strong>: presente nos três. Analytics, Crashlytics (relatório de erro), Cloud Messaging (push), Remote Config. É tão onipresente que virou infraestrutura invisível. E vem com coleta ligada por padrão.</li>
<li><strong>Stack de atribuição de anúncio</strong>: Adjust, AppsFlyer, Branch.io, Singular, Facebook SDK. A função é ligar &ldquo;você clicou nesse anúncio&rdquo; a &ldquo;você instalou e usou o app&rdquo;. No TikTok tinha um empilhamento redundante: cinco desses ao mesmo tempo, cada um coletando seu ad-id de forma independente.</li>
<li><strong>Redes de anúncio</strong>: AdMob/DoubleClick do Google, e no caso dos jogos o ecossistema de mediação de ads.</li>
<li><strong>Analytics/crash de origem regional</strong>: o Tencent Bugly no Clash of Kings é o exemplo, telemetria indo pra infra chinesa.</li>
<li><strong>Um serviço especializado de fingerprint/antifraude</strong>: o caso mais chamativo foi o <a href="https://risk.lexisnexis.com/products/threatmetrix"target="_blank" rel="noopener">ThreatMetrix da LexisNexis</a> no TikTok: uma empresa cujo negócio <em>é</em> montar impressão digital de dispositivo pra detecção de fraude. Legítimo no uso antifraude, mas é literalmente uma máquina de fingerprint como serviço, embutida.</li>
</ul>
<p>O recado é que aquele &ldquo;produto&rdquo; não é montado por uma empresa só. São cinco, seis, sete parceiros, cada um pegando um pedaço, e o fingerprint costurando tudo de volta num perfil só. Ninguém está te espionando sozinho. É um mutirão.</p>
<h2>O que dá pra fazer<span class="hx:absolute hx:-mt-20" id="o-que-dá-pra-fazer"></span>
    <a href="#o-que-d%c3%a1-pra-fazer" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Você não vai zerar isso sem sair da internet, mas dá pra reduzir bastante a superfície exposta:</p>
<ul>
<li><strong>Não consinta o que não precisa.</strong> GPS é o maior. Um app de vídeo não precisa da sua localização precisa pra funcionar. Negue, ou libere só &ldquo;enquanto usa o app&rdquo;. O mesmo vale pra contatos, microfone e câmera: só libere quando o recurso que você quer usar naquele momento exige.</li>
<li><strong>Resete seu ID de anúncio de vez em quando</strong> (e, no Android, dá pra escolher &ldquo;excluir ID de publicidade&rdquo; de vez). Não mata o fingerprint, mas quebra parte do rastro.</li>
<li><strong>Desconfie de &ldquo;encontrar amigos&rdquo;.</strong> É o gatilho de upload de contatos. Você entrega a rede social inteira das pessoas que confiaram seu número a você.</li>
<li><strong>Prefira a versão web quando der.</strong> Navegador com bloqueador de rastreador exposto menos fingerprint que o app nativo, que tem acesso a sensores e sinais que o browser não dá.</li>
<li><strong>Aceite o trade-off conscientemente.</strong> A questão não é virar paranoico e desinstalar tudo. É saber o preço. Se você acha o TikTok divertido o suficiente pra pagar com seu fingerprint, ótimo, é uma decisão informada. O problema é pagar sem saber que está pagando.</li>
</ul>
<h2>O ponto do post<span class="hx:absolute hx:-mt-20" id="o-ponto-do-post"></span>
    <a href="#o-ponto-do-post" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Nada disso prova ou desprova que um app específico é 100% seguro. Análise estática mostra o que o app é <strong>capaz</strong> de fazer, o que está construído dentro dele; só a captura de tráfego ao vivo, com aparelho rooteado e proxy MITM, mostraria o que de fato sai pela rede em cada requisição. Eu não fui até lá. Isso aqui é um vislumbre, não um veredito.</p>
<p>E é exatamente esse o ponto. Hoje, com um LLM bom e uma tarde livre, qualquer desenvolvedor curioso consegue abrir o próprio celular e ver o que está rodando ali dentro, sem depender da opinião de um influenciador de tecnologia ou de manchete alarmista. As três análises completas estão no GitHub (<a href="https://github.com/akitaonrails/tiktok_analysis"target="_blank" rel="noopener">TikTok</a>, <a href="https://github.com/akitaonrails/clash_of_kings_analysis"target="_blank" rel="noopener">Clash of Kings</a>, <a href="https://github.com/akitaonrails/govbr_analysis"target="_blank" rel="noopener">gov.br</a>) com o passo a passo pra reproduzir. Pega um app que você usa todo dia e faz o mesmo. É a coisa mais próxima de ler o rótulo antes de comer que a gente tem no mundo do software.</p>
]]></content:encoded><category>seguranca</category><category>engenharia-de-software</category></item><item><title>Por que LLMs vão falhar na Sua Empresa?</title><link>https://akitaonrails.github.io/2026/06/24/por-que-llms-vao-falhar-na-sua-empresa/</link><guid isPermaLink="true">https://akitaonrails.github.io/2026/06/24/por-que-llms-vao-falhar-na-sua-empresa/</guid><pubDate>Wed, 24 Jun 2026 12:00:00 -0300</pubDate><description>&lt;p&gt;Este post é mais especulação do que tese fechada. Estou pensando alto. Pode estar incompleto, pode estar errado. Se você discordar, melhor ainda: responde nos comentários. Não estou tentando vender metodologia nova. Quero cutucar uma ferida que muita gente finge que não existe.&lt;/p&gt;
&lt;p&gt;Nos últimos meses começaram a aparecer histórias de empresas grandes gastando quantidades absurdas de tokens em ferramentas de IA sem conseguir apontar, com clareza, o resultado equivalente em produto. O caso que ficou mais famoso foi a &lt;a href="https://www.forbes.com/sites/janakirammsv/2026/05/17/uber-burns-its-2026-ai-budget-in-four-months-on-claude-code/"target="_blank" rel="noopener"&gt;Uber queimando o orçamento anual de IA em poucos meses&lt;/a&gt; com uso pesado de ferramentas como Claude Code, e executivos admitindo que ainda não conseguiam traçar uma linha reta entre consumo de tokens e valor entregue. Não é que ninguém tenha usado. Usaram demais. Esse é justamente o problema.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Este post é mais especulação do que tese fechada. Estou pensando alto. Pode estar incompleto, pode estar errado. Se você discordar, melhor ainda: responde nos comentários. Não estou tentando vender metodologia nova. Quero cutucar uma ferida que muita gente finge que não existe.</p>
<p>Nos últimos meses começaram a aparecer histórias de empresas grandes gastando quantidades absurdas de tokens em ferramentas de IA sem conseguir apontar, com clareza, o resultado equivalente em produto. O caso que ficou mais famoso foi a <a href="https://www.forbes.com/sites/janakirammsv/2026/05/17/uber-burns-its-2026-ai-budget-in-four-months-on-claude-code/"target="_blank" rel="noopener">Uber queimando o orçamento anual de IA em poucos meses</a> com uso pesado de ferramentas como Claude Code, e executivos admitindo que ainda não conseguiam traçar uma linha reta entre consumo de tokens e valor entregue. Não é que ninguém tenha usado. Usaram demais. Esse é justamente o problema.</p>
<p>Até aqui, acho que a maioria já entendeu que prompt de uma linha não resolve nada. Aquela fantasia de escrever &ldquo;faça um clone do Uber&rdquo; e voltar com um produto pronto morreu rápido. A resposta do mercado foi correr para outro lado: <strong>spec-driven development</strong>.</p>
<p>Em vez de pedir tudo em uma frase, você escreve uma especificação. Define escopo, casos de uso, critérios de aceite, arquitetura desejada, restrições, fluxos, talvez até um PRD inteiro. Depois entrega isso para o agente e espera que ele implemente com menos ambiguidade.</p>
<p>Isso é melhor do que one-shot? Claro. Mas ainda acho que está errado.</p>
<h2>O problema não é falta de especificação<span class="hx:absolute hx:-mt-20" id="o-problema-não-é-falta-de-especificação"></span>
    <a href="#o-problema-n%c3%a3o-%c3%a9-falta-de-especifica%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Eu venho martelando essa ideia há anos, antes de LLM virar moda. Dois vídeos meus são importantes pra entender o ponto: <a href="/2019/10/09/akitando-63-nao-terceirize-suas-decisoes-a-licao-mais-importante-da-sua-vida/">Não Terceirize Suas Decisões</a> e <a href="/2019/06/18/akitando-51-esqueca-metodologias-ageis-rated-r/">Esqueça Metodologias Ágeis</a>.</p>
<blockquote>
  <p>O resumo é simples: a maioria dos profissionais foi treinada a não decidir.</p>

</blockquote>
<p>Pensa no seu dia a dia. Muita gente não faz nada se não houver backlog pronto. Cruza os braços, culpa gestão, culpa colega, culpa cliente, e espera alguém dizer o que fazer. Quando a tarefa chega, executa. Quando dá errado, a culpa era do requisito. Quando o cliente reclama, a culpa era da prioridade. Quando o produto degrada, a culpa era do processo.</p>
<p>Quase ninguém decide de verdade, banca a decisão até o fim e sofre as consequências. E sem sofrer a consequência, você não aprende a decidir.</p>
<p>Você não aprende quais escolhas levam a quais resultados. Não aprende a priorizar. Não aprende a explicar por que algo precisa existir. Não aprende a escrever uma especificação porque entende o problema; aprende a preencher template para ninguém reclamar.</p>
<h2>O Agile virou burocracia estruturada<span class="hx:absolute hx:-mt-20" id="o-agile-virou-burocracia-estruturada"></span>
    <a href="#o-agile-virou-burocracia-estruturada" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Os princípios originais de 2001 foram triturados. O que muita empresa chama de Agile hoje é burocracia estruturada em ciclos menores.</p>
<p>O desenho clássico todo mundo já viu: backlog, sprint planning, sprint, daily, review, retrospective, próximo sprint. A <a href="https://scrumguides.org/scrum-guide.html"target="_blank" rel="noopener">Scrum Guide</a> descreve os eventos formais. Diagramas como o <a href="https://commons.wikimedia.org/wiki/File:Scrum_process.svg"target="_blank" rel="noopener">Scrum process da Wikimedia</a> mostram o círculo bonitinho. Na prática, muita equipe transformou isso em teatro.</p>
<p>Passa-se um dia inteiro debatendo o que entra no backlog. E o backlog final raramente é o que precisa ser feito. É o consenso de menor resistência. Compromisso em cima de compromisso. Pequenas tarefas, pequenos riscos, pequenas vitórias, pequenos fracassos. Tudo desenhado para não gerar conflito demais.</p>
<p>Isso não é apenas medíocre. É pior: é a escolha ativa por decisões fáceis, que não levantam muita crítica contra você.</p>
<p>Depois a equipe passa dias ou semanas implementando aquele backlog morno. O QA entra, encontra problemas, tenta encaixar correções na próxima rodada. Mais alguns dias, talvez mais duas semanas. Um mês depois, talvez dois, a decisão original finalmente começa a mostrar resultado em produção.</p>
<p>Só que o resultado está tão longe da decisão que quase ninguém faz a correlação. A equipe não sente o peso real do que decidiu. O erro não vira aprendizado. O processo não melhora. A parte mais importante de qualquer sistema de melhoria contínua, o <strong>kaizen</strong>, nunca acontece.</p>
<blockquote>
  <p>O que acontece é outra coisa: todo mundo aprende a ficar invisível.</p>

</blockquote>
<p>Você aprende a agradar gestão, não o produto. Aprende a reduzir atrito, não a resolver o problema. Aprende a sobreviver à reunião, não a entregar valor. E quando os resultados pioram, a resposta da alta gestão é previsível: mais controle, mais regra, mais gate, mais comitê, mais checklist. A engrenagem fica mais pesada. O time fica mais covarde.</p>
<h2>Então chega a IA<span class="hx:absolute hx:-mt-20" id="então-chega-a-ia"></span>
    <a href="#ent%c3%a3o-chega-a-ia" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Agora entra a LLM.</p>
<p>Até pouco tempo atrás, o maior gargalo de desenvolvimento era escrever e ajustar código. Codar levava dias ou semanas. Por isso tanto esforço era colocado na fase de planejamento. Se o time vai gastar duas semanas implementando, parece fazer sentido gastar um dia discutindo o que entra na sprint.</p>
<p>Mas ferramentas de coding com LLM mudam a posição do gargalo. Elas conseguem fazer uma parte grande do trabalho braçal: gerar estrutura, escrever testes básicos, fazer refactors, adaptar APIs, criar telas, preencher boilerplate, tentar correções. Não é perfeito, mas é rápido o bastante para mudar a economia do processo.</p>
<p>É aquela história da corrente e do elo mais fraco. Você reforça um elo, outro passa a limitar o sistema. Antes, o elo fraco era a velocidade de codificação. Agora, cada vez mais, é a capacidade humana de decidir, explicar, testar e revisar.</p>
<blockquote>
  <p>O erro das empresas é colocar LLM dentro do mesmo processo quebrado e esperar ganho multiplicativo.</p>

</blockquote>
<p>Você pega pessoas treinadas por anos a não decidir, entrega uma ferramenta que exige clareza de decisão, e se surpreende quando sai lixo mais rápido.</p>
<h2>A LLM reflete o usuário<span class="hx:absolute hx:-mt-20" id="a-llm-reflete-o-usuário"></span>
    <a href="#a-llm-reflete-o-usu%c3%a1rio" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Um agente de coding precisa que você explique o objetivo, o contexto, as restrições, as prioridades, o que não pode quebrar, quais caminhos são aceitáveis, como medir sucesso. Ele precisa de uma direção objetiva.</p>
<p>Agora vai entrevistar seu time. Pergunta para cada pessoa:</p>
<ul>
<li>qual é o objetivo real do que você está fazendo?</li>
<li>como isso melhora o produto?</li>
<li>qual métrica deveria mudar?</li>
<li>que trade-off você está aceitando?</li>
<li>o que não pode quebrar?</li>
<li>quais casos tristes precisam ser testados?</li>
</ul>
<p>Muita gente não sabe responder. Sabe qual ticket pegou. Sabe que precisa fechar algumas tarefas por semana. Sabe que tem daily amanhã. Mas não sabe por que aquilo importa.</p>
<p>E aí você entrega uma LLM para essa pessoa.</p>
<p>O resultado não é mágica. É espelho. Código ruim dez vezes mais rápido. Bug dez vezes mais rápido. Cliente irritado dez vezes mais rápido. Pull request gigante dez vezes mais rápido. O problema não é só a IA. É que a IA amplifica a falta de direção.</p>
<p>Spec-driven development tenta corrigir isso com documentação. Mas se a especificação nasce do mesmo processo covarde, ela só documenta a covardia. Um PRD escrito por quem não entende a decisão continua ruim. Critério de aceite escrito para evitar conflito continua desviando do problema real. O agente só vai executar melhor uma decisão ruim.</p>
<h2>O processo precisa mudar<span class="hx:absolute hx:-mt-20" id="o-processo-precisa-mudar"></span>
    <a href="#o-processo-precisa-mudar" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Minha hipótese é que o processo inteiro precisa ser redesenhado ao redor da nova restrição. De novo: é especulação. Eu não tenho dados suficientes para provar isso. Mas, olhando para o tipo de falha que vejo em empresas e para o tipo de sucesso que vejo em uso individual intenso, minha teoria é essa:</p>
<blockquote>
  <p><strong>jogue fora o ritual de sprint como unidade central de trabalho.</strong></p>

</blockquote>
<p>Não faz sentido manter dias de planning, dias de review e semanas de codificação como se o gargalo ainda fosse o mesmo. Com LLM, o ciclo precisa ficar mais curto. Muito mais curto. Idealmente, dentro do mesmo dia.</p>
<p>No meu desenho ideal, cada programador com LLM deveria parear diretamente com um Product Owner por blocos de trabalho curtos. O papel do PO é fechar a lacuna que o programador normalmente tem: objetivo, prioridade, restrição, contexto de negócio, resultado esperado. Isso precisa entrar no prompt e na conversa com o agente.</p>
<p>Mas como codar deixou de ser o gargalo principal, o PO não precisa esperar duas semanas para ver resultado. Ele pode sentar com o programador durante uma manhã, implementar uma pequena fatia funcional, ajustar na hora, decidir na hora, cortar escopo na hora. Depois roda para outro programador.</p>
<p>Em seguida, entra QA. Não como uma fase distante, mas como pareamento no mesmo ciclo. O QA fecha outra lacuna comum do programador: testar só o caminho feliz, esquecer casos de erro, não automatizar o suficiente, não pensar em regressão de comportamento. A função do QA vira ajudar a transformar a implementação em algo verificável agora, enquanto o contexto ainda está quente.</p>
<p>Depois entra o Tech Lead. Também no mesmo dia, não duas semanas depois. Ele olha para o que mudou e fecha a terceira lacuna: complexidade desnecessária, design ruim, regressão escondida, documentação faltando, vulnerabilidade óbvia, performance piorando, acoplamento que nasceu sem necessidade.</p>
<p>Constrói, checa, ajusta. Tudo em tempo real.</p>
<figure>
  <a href="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/06/24/why-llms-fail/llm-pairing-rotation.svg">
    <img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/06/24/why-llms-fail/llm-pairing-rotation.svg" alt="Diagrama comparando o fluxo comum de sprint, com decisão distante do resultado, contra um fluxo de pareamento rotativo com LLM envolvendo PO, programador, QA e Tech Lead no mesmo dia." />
  </a>
  <figcaption>O gargalo muda: menos tempo esperando uma sprint terminar, mais ciclos curtos de decisão, implementação, teste e revisão.</figcaption>
</figure>
<h2>O novo papel de cada pessoa<span class="hx:absolute hx:-mt-20" id="o-novo-papel-de-cada-pessoa"></span>
    <a href="#o-novo-papel-de-cada-pessoa" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Esse modelo cobra mais responsabilidade, não menos.</p>
<p>O programador deixa de ser a pessoa que só pega ticket. Ele precisa aprender a transformar objetivo em instrução executável. Precisa discutir trade-off. Precisa entender por que está codando. Precisa usar a LLM como ferramenta de execução e investigação, não como desculpa para desligar o cérebro.</p>
<p>O PO deixa de ser fábrica de backlog. Ele precisa decidir com o programador, olhando para o produto vivo. Não é escrever card e sumir. É ver a coisa nascer, ajustar, cortar, priorizar e aceitar consequência.</p>
<p>O QA deixa de ser a pessoa que recebe o pacote no fim e devolve defeito. Ele entra cedo para transformar comportamento esperado em verificação. Se a LLM acelera código, QA precisa acelerar aprendizado sobre risco.</p>
<p>O Tech Lead deixa de ser carimbo de PR atrasado. Ele entra enquanto ainda dá para mudar barato. Ajuda a manter simplicidade, remove complexidade, protege arquitetura, documentação, segurança e performance.</p>
<p>Nada disso funciona se todo mundo continuar usando IA como autocomplete caro dentro do mesmo Scrum burocrático.</p>
<h2>Por que empresas não vão gostar disso<span class="hx:absolute hx:-mt-20" id="por-que-empresas-não-vão-gostar-disso"></span>
    <a href="#por-que-empresas-n%c3%a3o-v%c3%a3o-gostar-disso" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Porque esse processo expõe decisões.</p>
<p>No processo atual, a decisão se dilui. Foi o backlog. Foi o PO. Foi o refinamento. Foi a sprint. Foi o time. Foi a dependência. Foi o cliente que mudou de ideia. Todo mundo consegue se esconder.</p>
<p>Num ciclo curto com LLM, a decisão aparece rápido. Você disse que aquilo era prioridade? Então implementa agora. Você disse que o critério de aceite era esse? Então testa agora. Você disse que esse design era bom? Então revisa agora. Se estiver errado, a consequência aparece no mesmo dia.</p>
<p>Isso é desconfortável. Mas é assim que se aprende.</p>
<p>Sem consequência próxima, decisão vira teatro. Com consequência próxima, decisão vira treino.</p>
<h2>Como implementar isso sem queimar dinheiro<span class="hx:absolute hx:-mt-20" id="como-implementar-isso-sem-queimar-dinheiro"></span>
    <a href="#como-implementar-isso-sem-queimar-dinheiro" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O primeiro passo é aceitar uma coisa que programador profissional costuma odiar: dá para jogar código fora.</p>
<blockquote>
  <p>Na verdade, você deveria jogar código fora com muito mais frequência.</p>

</blockquote>
<p>Código não é monumento. Código é material de trabalho. Deletar código é tão importante quanto escrever código novo. É por isso que usamos Git. A ideia sempre foi trabalhar em branches, experimentar caminhos, mudar de ideia, comparar alternativas, apagar o que não funcionou e manter só o que sobreviveu ao teste da realidade.</p>
<p>Só que, no processo tradicional, código fica caro demais emocionalmente. Se levou duas semanas para sair, ninguém quer admitir que foi desperdício. O gerente sente que apagar aquilo prova que a decisão anterior foi ruim. O programador defende a implementação porque sofreu para fazê-la. O time empurra o problema para frente porque deletar parece derrota. Não é. Às vezes é higiene.</p>
<p>Com LLM, esse custo muda. <strong>Fica barato errar</strong>. Fica barato prototipar. Fica barato fazer prova de conceito. Fica barato testar dois caminhos e jogar um fora. Fica barato pedir para o agente reescrever uma abordagem inteira numa branch temporária, comparar, documentar o aprendizado e dar <code>git reset</code> sem drama.</p>
<p>Então faça mais disso. Mais protótipos. Mais provas de conceito. Mais testes A/B internos. Mais branches descartáveis. Menos apego ao primeiro código que apareceu. LLM é muito boa nesse tipo de trabalho: explorar alternativas rápido, mostrar onde a especificação estava vaga e produzir material que você pode destruir sem culpa.</p>
<p>Mas não espere que todo mundo receba tokens de LLM numa segunda-feira e saiba fazer isso sozinho. Esse é o jeito mais rápido de queimar orçamento e depois dizer que IA não funciona.</p>
<p>Minha sugestão é o contrário: assuma uma ou duas semanas sem entrega planejada. Diga claramente que o objetivo não é produzir feature. É treinar o novo processo. Quebrar o ritual antigo. Deixar o time praticar em ambiente seguro. Se der errado, ótimo: reseta a branch, apaga o protótipo, documenta o que aprendeu e tenta de novo.</p>
<p>Nessa fase, o PO não deveria escrever especificação de vinte páginas. Deveria parear com o programador e construir prompts pequenos, um passo de cada vez, vendo o resultado em tempo real. A cada resposta da LLM, o PO aprende quanto detalhe o código realmente precisa. O programador aprende a perguntar melhor. QA aprende a transformar comportamento em teste cedo. Tech Lead aprende a cortar complexidade enquanto ela ainda é barata.</p>
<p>É assim que se adota LLM com alguma chance de dar certo: como mudança de processo, não como licença cara de autocomplete.</p>
<h2>A conclusão incômoda<span class="hx:absolute hx:-mt-20" id="a-conclusão-incômoda"></span>
    <a href="#a-conclus%c3%a3o-inc%c3%b4moda" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><blockquote>
  <p>LLMs falham tanto porque elas entram em processos feitos por pessoas que foram treinadas a não decidir.</p>

</blockquote>
<p>Não é só falta de prompt melhor. Não é só falta de spec maior. Não é só falta de governança de token. Tudo isso ajuda, mas não toca o centro do problema.</p>
<p>O centro é que muita gente não sabe explicar objetivo mensurável, não sabe priorizar, não sabe assumir trade-off, não sabe conectar decisão com resultado. E uma LLM precisa exatamente disso para ser útil.</p>
<p>Se você coloca IA no processo velho, você acelera o processo velho. Mais backlog medíocre. Mais decisão ruim. Mais bug. Mais custo. Mais rework. Mais relatório tentando provar produtividade que o cliente nunca sentiu.</p>
<p>Se você quer que LLM funcione, precisa redesenhar o processo ao redor dela. Ciclos menores. Pareamento real. Decisão perto da execução. Teste perto da decisão. Revisão perto do código. Resultado perto de quem decidiu.</p>
<p>Essa é a parte que programador precisa encarar: sim, você provavelmente nunca aprendeu a decidir direito. Nunca aprendeu a descrever objetivo de forma objetiva. Nunca aprendeu a medir consequência. O processo te treinou para isso. E agora a IA está revelando a falha.</p>
<p>O lado bom é que também dá para treinar o contrário.</p>
<p>Mas não vai acontecer com mais uma cerimônia, mais uma planilha de prompt, mais uma política de uso de IA, ou mais uma sprint cheia de tickets escritos para ninguém ser criticado.</p>
<p><strong>Vai acontecer quando você parar de terceirizar decisão.</strong></p>
]]></content:encoded><category>llms</category><category>vibe-coding</category><category>engenharia-de-software</category></item><item><title>Controvérsia de IA em contribuições de projetos de código aberto - minha opinião</title><link>https://akitaonrails.github.io/2026/06/05/controversia-ia-contribuicoes-projetos-codigo-aberto-minha-opiniao/</link><guid isPermaLink="true">https://akitaonrails.github.io/2026/06/05/controversia-ia-contribuicoes-projetos-codigo-aberto-minha-opiniao/</guid><pubDate>Fri, 05 Jun 2026 11:00:00 -0300</pubDate><description>&lt;p&gt;Nos últimos dias voltou a discussão sobre &lt;strong&gt;AI slop&lt;/strong&gt; em projetos de código aberto. Mantenedor reclamando que PR gerado por IA é lixo. Projeto proibindo contribuição assistida por IA. Bug bounty sendo inundado por relatório falso. Usuário irritado porque um release que usou IA quebrou alguma coisa. E, claro, a internet fazendo o que a internet faz melhor: transformar caso específico em guerra santa.&lt;/p&gt;
&lt;p&gt;Minha opinião curta: &lt;strong&gt;IA em contribuição open source veio pra ficar&lt;/strong&gt;. Vai aumentar, não diminuir. A caixa de Pandora já abriu. Não existe plano realista onde todo mundo volta a programar 100% manualmente e finge que Claude Code, Codex, OpenCode, Cursor, Gemini CLI e o resto nunca existiram.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Nos últimos dias voltou a discussão sobre <strong>AI slop</strong> em projetos de código aberto. Mantenedor reclamando que PR gerado por IA é lixo. Projeto proibindo contribuição assistida por IA. Bug bounty sendo inundado por relatório falso. Usuário irritado porque um release que usou IA quebrou alguma coisa. E, claro, a internet fazendo o que a internet faz melhor: transformar caso específico em guerra santa.</p>
<p>Minha opinião curta: <strong>IA em contribuição open source veio pra ficar</strong>. Vai aumentar, não diminuir. A caixa de Pandora já abriu. Não existe plano realista onde todo mundo volta a programar 100% manualmente e finge que Claude Code, Codex, OpenCode, Cursor, Gemini CLI e o resto nunca existiram.</p>
<p>Isso não quer dizer que todo projeto tem obrigação de aceitar contribuição feita com IA. Longe disso. O mantenedor tem o direito absoluto de tocar o projeto como quiser. Pode aceitar IA, pode banir IA, pode congelar o projeto, pode apagar o repositório e ir plantar tomate. Código aberto não é democracia obrigatória. Quem mantém decide.</p>
<p>Mas também acho que banir IA é só adiar uma briga impossível de ganhar. O volume vai continuar subindo. A qualidade média vai oscilar. Vai ter lixo, vai ter coisa boa, vai ter PR quase certo, vai ter relatório de bug alucinado. A pergunta prática não é “como impedir IA?”. A pergunta prática é: <strong>como adaptar o processo pra sobreviver a isso?</strong></p>
<h2>Os casos recentes<span class="hx:absolute hx:-mt-20" id="os-casos-recentes"></span>
    <a href="#os-casos-recentes" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O caso mais barulhento agora foi o do <a href="https://linuxiac.com/rsync-3-4-3-regressions-trigger-debate-over-ai-assisted-code/"target="_blank" rel="noopener">rsync 3.4.3</a>. A versão saiu em 20 de maio como update de segurança, corrigindo seis CVEs. Logo depois, usuários reportaram regressões, em especial em fluxos de backup com daemon mode e opções de transferência incremental. Rsync não é brinquedo. É ferramenta de backup, deploy, mirror, sysadmin. Quebrar compatibilidade ali dói.</p>
<p>Andrew Tridgell, criador do Samba e co-criador do rsync, respondeu no post <a href="https://medium.com/@tridge60/rsync-and-outrage-d9849599e5a0"target="_blank" rel="noopener">rsync and outrage</a>. Ele confirmou que usou Claude, com cross-check de Codex e Gemini, pra ajudar a reescrever parte da suíte de testes em Python. Mas também disse o óbvio que muita gente não quer ouvir: ele não mandou “converte tudo aí” e foi dormir. Ele desenhou a suíte, revisou o trabalho, queimou muito tempo de CI, e assumiu que as regressões aconteceram em casos válidos, mas incomuns, que não estavam cobertos nem pelos testes existentes nem pelos testes manuais dele.</p>
<p>Esse é o ponto interessante: a regressão virou discussão sobre IA, mas regressão não nasceu com IA. Regressão nasceu junto com software.</p>
<p>Do outro lado temos o Zig. O <a href="https://ziglang.org/code-of-conduct/"target="_blank" rel="noopener">Code of Conduct do Zig</a> hoje tem uma política explícita: <strong>Strict No LLM / No AI Policy</strong>. Nada de conteúdo gerado por LLM, nem código, nem prosa, nem revisão gramatical, nem tradução, nem brainstorming. Andrew Kelley explicou em entrevista, resumida pela <a href="https://www.devclass.com/devops/2026/06/01/zig-creator-seeks-uncompromising-perfection-before-blessing-10/5248219"target="_blank" rel="noopener">DevClass</a>, que a equipe considera contribuições de IA invariavelmente ruins, consumidoras de tempo de review, não ensináveis, não determinísticas. A frase que resume a postura dele é boa: o padrão que ele quer não é “funciona surpreendentemente bem”, é “perfeição sem compromisso”.</p>
<p>Eu discordo da generalização, mas respeito a decisão. É o projeto dele. Se ele quer manter aquele espaço sem LLM, é direito dele. Ponto.</p>
<p>Na mesma vizinhança apareceu a discussão do Bun. O <a href="https://bun.sh/blog/bun-joins-anthropic"target="_blank" rel="noopener">post oficial do Bun entrando na Anthropic</a> diz que Bun foi adquirido porque Claude Code e outros produtos de coding da Anthropic dependem dele. “Se Bun quebra, Claude Code quebra”, nas palavras do próprio post. Já a matéria da <a href="https://www.cosmicjs.com/blog/bun-rust-rewrite-javascript-runtime"target="_blank" rel="noopener">Cosmic sobre a reescrita em Rust</a> aponta motivos como acessibilidade de contribuidores, manutenção em escala e estabilidade de longo prazo. Eu vi gente ligando isso à política anti-IA do Zig, mas a fonte que consegui verificar não crava essa causalidade. O que dá pra dizer com segurança é: Bun, um projeto nascido em Zig, está migrando partes importantes pra Rust, e uma das razões citadas é a base maior de contribuidores.</p>
<p>E tem o caso do curl. Segundo a <a href="https://hackaday.com/2026/01/26/the-curl-project-drops-bug-bounties-due-to-ai-slop/"target="_blank" rel="noopener">Hackaday</a>, Daniel Stenberg suspendeu o programa de bug bounty do curl a partir de 1º de fevereiro de 2026 porque o projeto foi inundado por relatórios de vulnerabilidade gerados por LLM. Relatórios compridos, intimidadores, com cara de exploit sério, mas que quando um mantenedor experiente lê, não são vulnerabilidades. O PR que remove o bounty está no GitHub como <a href="https://github.com/curl/curl/pull/20312"target="_blank" rel="noopener">curl/curl#20312</a>.</p>
<p>Esse caso é diferente de PR de código. É pior. Um patch ruim você testa, compila, lê. Um relatório de segurança falso obriga alguém experiente a gastar tempo provando que não existe bug. É o tipo de trabalho ingrato que esgota mantenedor.</p>
<p>Então sim: o problema é real. AI slop existe. Está enchendo issue tracker, PR, bug bounty, comentário, tudo.</p>
<p>Agora a parte que ninguém gosta: isso não vai parar.</p>
<h2>Não existe “voltar ao normal”<span class="hx:absolute hx:-mt-20" id="não-existe-voltar-ao-normal"></span>
    <a href="#n%c3%a3o-existe-voltar-ao-normal" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Eu já falei disso no post <a href="/2026/04/11/vs-code-e-o-novo-cartao-perfurado/">VS Code é o novo cartão perfurado</a>. A interface mudou. Antes você precisava digitar instrução binária. Depois precisava organizar cartão perfurado. Depois precisava convencer o compilador. Depois precisava operar editor, terminal, framework, CI, container, cloud e YAML. Agora você precisa orquestrar agente.</p>
<p>Isso não elimina engenharia. Só muda onde o trabalho manual termina.</p>
<p>Tem gente tratando IA como se fosse moda passageira, igual “metaverso” ou NFT. Não é. IA pra programação já passou do ponto de demonstração de conferência. Está dentro do fluxo de trabalho real. O rsync usou. Bun está cheio de bot de Claude Code abrindo PR. Meus projetos usam. Seus contribuidores vão usar, mesmo que você proíba. Se você acha que consegue detectar com 100% de certeza que um patch foi escrito com ou sem IA, boa sorte com isso.</p>
<p>O mantenedor ainda pode impor regra. Pode dizer “se eu descobrir que usou IA, bloqueio”. Pode fazer sentido em comunidades pequenas, com cultura própria, como Zig. Mas no open source geral, principalmente projeto grande, com usuário no mundo inteiro, isso vira teatro de compliance. O sujeito usa IA, reescreve, não declara, e pronto. Você vai fazer o quê? Detector de IA em código? Pelo amor.</p>
<h2>O erro é achar que você precisa revisar tudo sozinho<span class="hx:absolute hx:-mt-20" id="o-erro-é-achar-que-você-precisa-revisar-tudo-sozinho"></span>
    <a href="#o-erro-%c3%a9-achar-que-voc%c3%aa-precisa-revisar-tudo-sozinho" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A reclamação mais justa dos mantenedores é simples: já falta gente pra revisar contribuição humana. IA aumenta o volume. Mais PR, mais issue, mais bug report. O mantenedor já estava cansado, agora está afogado.</p>
<p>Eu entendo. Só acho que a solução não é tentar processar o novo volume com o processo velho.</p>
<p>Você combate IA com IA.</p>
<p>A primeira triagem tem que ser feita com LLM. Não pra aprovar automaticamente. Pra filtrar. Pra resumir. Pra comparar diff com objetivo declarado. Pra apontar cheiro ruim. Pra dizer “isso toca schema, precisa migração”. Pra dizer “isso altera comportamento público, precisa teste de compatibilidade”. Pra dizer “essa descrição do PR não bate com o código”. Só essa camada já elimina 80% do trabalho braçal.</p>
<p>O erro é deixar o agente decidir sozinho. O acerto é mandar o agente fazer o trabalho chato de investigação, e você decide.</p>
<p>É assim que eu faço.</p>
<h2>Meu fluxo real com PRs<span class="hx:absolute hx:-mt-20" id="meu-fluxo-real-com-prs"></span>
    <a href="#meu-fluxo-real-com-prs" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Quem acompanhou minha <a href="/2026/05/14/terminando-maratona-ia-sucesso-ou-fracasso/">maratona de IA</a> sabe que eu não cheguei aqui depois de assistir dois vídeos no YouTube. Passei semanas usando agente todo dia, em projeto real, quebrando coisa real, corrigindo coisa real. O que estou descrevendo aqui é o fluxo que sobrou depois disso, não teoria de LinkedIn.</p>
<p>Propaganda descarada: estou feliz que meus três projetos principais relacionados a IA estão recebendo contribuição quase todo dia:</p>
<ul>
<li><a href="https://github.com/akitaonrails/ai-jail"target="_blank" rel="noopener">ai-jail</a>, que já expliquei no post <a href="/2026/03/01/ai-jail-sandbox-para-agentes-de-ia-de-shell-script-a-ferramenta-real/">ai-jail: Sandbox para Agentes de IA</a>.</li>
<li><a href="https://github.com/akitaonrails/ai-memory"target="_blank" rel="noopener">ai-memory</a>, que expliquei em <a href="/2026/05/23/criei-sistema-memoria-agentes-codigo-ai-memory/">Criei um Sistema de Memória pra Agentes de Código: ai-memory</a>.</li>
<li><a href="https://github.com/akitaonrails/ai-usagebar"target="_blank" rel="noopener">ai-usagebar</a>, do post <a href="/2026/05/24/criei-widget-waybar-omarchy-monitorar-uso-llms-ai-usagebar/">Criei um Widget de Waybar pra Omarchy pra Monitorar Uso de Planos de LLM: ai-usagebar</a>.</li>
</ul>
<p>O ai-memory em particular virou um experimento vivo. No momento em que escrevo, o GitHub mostra <strong>55 PRs fechados</strong> no projeto; pela API do <code>gh</code>, 46 foram mergeados e 9 foram fechados sem merge. Obrigado a todo mundo que contribuiu. Sério. Djalma, mrpaiva, pedrofjr, CaTeIM, azevedo-luis, brunoomariano, rikelmyso7, abnersajr e vários outros. É trabalho de muita gente.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/06/05/ia-open-source-contribuicoes/screenshot-ai-projects.png" alt="Tela de Pull Requests fechados do ai-memory no GitHub, mostrando 55 PRs fechados e vários PRs recentes de contribuidores."  loading="lazy" /></p>
<p>Também é óbvio, olhando o estilo, que a maioria desses PRs foi feita com ajuda de IA. E isso não é problema. Seria até hipócrita reclamar: <strong>o ai-memory inteiro foi escrito por IA</strong>. Eu não abri editor de código uma única vez pra escrever aquilo na mão.</p>
<p>Mas quase nenhum PR chega imediatamente mergeável. Esse é o ponto que muita gente ainda não entendeu. “Feito com IA” não significa “merge cego”. Significa “começa a auditoria”.</p>
<p>Meu prompt pra revisar PR é mais ou menos assim:</p>
<blockquote>
  <p>checa o último PR aberto como de costume: não confie no autor, audita o código inteiro a fundo, garante que ele cumpre o objetivo.</p>
<p>Vê se precisamos ajustar ou corrigir antes de mergear: não aceite regressão, não aceite queda de qualidade de código, confere se a cobertura de teste está correta.</p>
<p>Se mexe em build ou suporte de OS, confere GitHub Actions, CI, build limpo, wiring correto e documentação.</p>
<p>Resume o que o PR faz, o que você encontrou, e me pede aprovação antes de seguir.</p>

</blockquote>
<p>Repara em duas coisas. Primeiro: “não confie no autor”. Não é grosseria. É engenharia. A descrição do PR é uma hipótese. O diff é a evidência. Segundo: “me pede aprovação”. O agente investiga, eu decido.</p>
<p>Quando recebo vários PRs no mesmo dia, faço isso pra todos. Depois que todos entram, mando outro prompt:</p>
<blockquote>
  <p>checa os commits de hoje.</p>
<p>Mexemos em muito código, então preciso de uma auditoria completa no código tocado pra garantir que não adicionamos regressão, duplicação desnecessária, código morto ou magic values que deveriam virar constantes documentadas.</p>
<p>Segue princípios de clean code, confirma cobertura de testes e refatora o que precisar.</p>

</blockquote>
<p>Se o projeto já está em uso, adiciono a parte que muita gente esquece:</p>
<blockquote>
  <p>este projeto já está sendo usado. Não quebre compatibilidade.</p>
<p>Se mexemos em schema de banco ou estrutura de arquivos do usuário, precisa ter migração limpa no upgrade.</p>
<p>Upgrade não pode corromper dados.</p>

</blockquote>
<p>Isso não garante nada. Mas evita erro óbvio.</p>
<p>No ai-memory dá pra ver esse padrão no histórico. Depois de uma leva grande de PRs, tem commits meus de endurecimento. Um exemplo é <a href="https://github.com/akitaonrails/ai-memory/commit/65682dc"target="_blank" rel="noopener"><code>65682dc</code></a>, “fix(audit): address 5 BLOCKING audit findings from today&rsquo;s review”, mexendo em OAuth OpenAI, admin API, admission hooks e servidor MCP. Outro é a sequência de PRs <a href="https://github.com/akitaonrails/ai-memory/pull/65"target="_blank" rel="noopener"><code>#65</code></a>, <a href="https://github.com/akitaonrails/ai-memory/pull/68"target="_blank" rel="noopener"><code>#68</code></a>, <a href="https://github.com/akitaonrails/ai-memory/pull/70"target="_blank" rel="noopener"><code>#70</code></a>, seguida de commits de hardening em base path, wikilinks e strict mode. PR entra, depois vem auditoria, depois vem ajuste. Esse segundo passo é onde mora a diferença.</p>
<p>No <a href="https://github.com/akitaonrails/ai-memory/pull/77"target="_blank" rel="noopener"><code>#77</code></a>, de auto-scope por sessão/ator, o merge mexeu em muita coisa: <code>active_project</code>, router de hooks, servidor MCP, testes de stress e multiusuário. Mais de 3.800 linhas adicionadas. Eu não vou fingir que alguém lê isso manualmente linha por linha com a mesma consistência depois da quinta hora. O agente ajuda a mapear risco. Eu uso meu julgamento pra decidir o que precisa endurecer.</p>
<h2>Regressão acontece com ou sem IA<span class="hx:absolute hx:-mt-20" id="regressão-acontece-com-ou-sem-ia"></span>
    <a href="#regress%c3%a3o-acontece-com-ou-sem-ia" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O caso do rsync é útil porque expõe uma fantasia: a ideia de que código humano era seguro e código de IA é perigoso.</p>
<p>Não. Código é perigoso.</p>
<p>Rust é considerado linguagem segura. E Rust tem bug. Vai no issue tracker do Rust e olha. Zig quer perfeição e tem bug. Curl tem bug. Rsync tem bug. Linux tem bug. SQLite tem bug. Meu código tem bug. Seu código tem bug. Não existe linguagem mágica que produz software sem bug. Nunca vai existir.</p>
<p>Isso não é pessimismo. É limite fundamental. Em computação, a gente sabe há muito tempo que não existe verificador geral perfeito pra propriedades semânticas não triviais de programas. Halting problem, Rice&rsquo;s theorem, esse tipo de coisa. Você pode provar muito em domínios restritos. Pode usar type system melhor. Pode usar Rust pra eliminar classe inteira de memory safety. Pode usar teste, fuzzing, model checking, static analysis. Ótimo. Use tudo.</p>
<p>Mas “software arbitrário sem bug” é fantasia.</p>
<p>Humano erra por contexto incompleto, suposição errada, pressão, cansaço, falta de teste, falta de uso real. IA erra pelos mesmos motivos práticos: contexto incompleto, suposição errada, treino em código ruim, objetivo mal especificado, validação fraca. A diferença é escala. IA consegue produzir mais lixo por minuto. Também consegue produzir mais correção por minuto se você montar o processo direito.</p>
<h2>Eu uso porque eu uso<span class="hx:absolute hx:-mt-20" id="eu-uso-porque-eu-uso"></span>
    <a href="#eu-uso-porque-eu-uso" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Outro ponto que aprendi na prática: é muito difícil manter bem projeto que você mesmo não usa.</p>
<p>Eu uso ai-memory todo dia. Uso ai-jail todo dia. Uso ai-usagebar todo dia. Usei a extensão <a href="https://github.com/akitaonrails/prettify-manga"target="_blank" rel="noopener">Prettify Manga Reader</a> na minha leitura real. Por isso pego bug que teste automatizado não pega.</p>
<p>No Prettify, por exemplo, os commits contam a história. <a href="https://github.com/akitaonrails/prettify-manga/commit/66c6728"target="_blank" rel="noopener"><code>66c6728</code></a> adicionou filtro noturno. Depois veio <a href="https://github.com/akitaonrails/prettify-manga/commit/b5bcb4d"target="_blank" rel="noopener"><code>b5bcb4d</code></a>, release 0.2.2, com suporte a Kindle Web Reader, toolbar, shortcuts e screenshot. Logo depois veio <a href="https://github.com/akitaonrails/prettify-manga/commit/0e6b7ee"target="_blank" rel="noopener"><code>0e6b7ee</code></a>, release 0.2.3, corrigindo o pareamento de spreads pra manter leitura direita-pra-esquerda sem bagunçar a ordem cronológica. Isso nasceu de uso real. Eu estava lendo, achei comportamento estranho, pedi pro LLM corrigir, testei, fiz release.</p>
<p>Esse é o loop saudável: usar, sentir dor, corrigir, testar de novo.</p>
<p>Em ai-jail, algumas contribuições vieram de uso que eu não teria priorizado sozinho. O <a href="https://github.com/akitaonrails/ai-jail/pull/56"target="_blank" rel="noopener"><code>#56</code></a> corrigiu PKGBUILD no AUR. O <a href="https://github.com/akitaonrails/ai-jail/pull/55"target="_blank" rel="noopener"><code>#55</code></a> encaminhou OSC 52 clipboard writes pelo proxy PTY de alt-screen. O <a href="https://github.com/akitaonrails/ai-jail/pull/51"target="_blank" rel="noopener"><code>#51</code></a> reconheceu Grok como agente conhecido e documentou máscara de privacidade de machine-id. São detalhes que aparecem quando outras pessoas usam a ferramenta em setups diferentes do meu.</p>
<p>Em ai-usagebar, isso fica mais claro ainda. O <a href="https://github.com/akitaonrails/ai-usagebar/pull/4"target="_blank" rel="noopener"><code>#4</code></a> adicionou fallback de macOS Keychain pras credenciais da Anthropic. Eu estou em Linux/Omarchy, não em macOS. Eu não ia achar esse bug no meu uso diário. O <a href="https://github.com/akitaonrails/ai-usagebar/pull/7"target="_blank" rel="noopener"><code>#7</code></a> corrigiu leitura de <code>credentials_path</code> customizado no widget. Também é caso de usuário com configuração diferente da minha. É aí que open source brilha: outra pessoa coça a própria coceira e melhora o projeto pra todo mundo.</p>
<p>Mas repare: quando eu não consigo testar manualmente, como macOS e Windows, eu dependo mais de CI. GitHub Actions roda macOS, roda Windows, roda Linux. Não substitui uso real, mas reduz risco. E quando alguém que usa aquele ambiente abre issue ou PR, isso vale ouro.</p>
<p>Manual testing ainda é a última linha de defesa. Se você abre mão dela, você está introduzindo bug por definição. Teste automatizado pega o que você lembrou de especificar. Uso real pega o que você nem sabia que precisava especificar.</p>
<p>Depois de mergear um conjunto grande, meu fluxo final costuma ser:</p>
<blockquote>
  <p>agora roda <code>bin/deploy</code> no meu home server e testa online.</p>
<p>Confere health, confere se ainda funciona como antes.</p>

</blockquote>
<p>De novo: não garante nada. Mas evita quebrar o óbvio.</p>
<h2>Não existe bala de prata<span class="hx:absolute hx:-mt-20" id="não-existe-bala-de-prata"></span>
    <a href="#n%c3%a3o-existe-bala-de-prata" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Eu não acho que todo projeto deve aceitar PR de IA. Também não acho que todo projeto deve banir. Não existe regra universal.</p>
<p>Se você é mantenedor solo de uma biblioteca crítica, sem tempo, sem CI decente, sem energia pra lidar com avalanche de PR ruim, banir AI-assisted contribution pode ser a decisão certa por enquanto. Melhor isso do que aceitar lixo e quebrar usuário.</p>
<p>Se você mantém comunidade pequena e quer ensinar contribuidores humanos, como o Zig argumenta, uma política anti-IA faz sentido dentro daquela cultura. Você está otimizando por formação de contributor, não por throughput de patch.</p>
<p>Mas se você mantém projeto que já recebe volume alto, que já tem CI, que já tem teste, que já tem usuário, eu acho que a adaptação é inevitável. Você vai precisar de triagem automatizada. Vai precisar de agente revisando PR. Vai precisar de bot resumindo issue. Vai precisar de ferramenta que diga “isso parece relatório de vulnerabilidade alucinado”.</p>
<p>Não porque IA é perfeita. Justamente porque IA é imperfeita e escala rápido.</p>
<h2>Minha conclusão<span class="hx:absolute hx:-mt-20" id="minha-conclusão"></span>
    <a href="#minha-conclus%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>AI slop é real. Vai piorar antes de melhorar. Vai ter PR porcaria. Vai ter relatório de segurança falso. Vai ter regressão atribuída a IA que teria acontecido com humano também. Vai ter mantenedor puto. Vai ter usuário gritando. Normal.</p>
<p>Mas a direção não muda.</p>
<p>Código assistido por IA veio pra ficar. A porcentagem de código tocado por agente vai subir sem parar. Proibir pode funcionar localmente, por um tempo, em uma comunidade específica. No macro, é guerra perdida.</p>
<p>O caminho pragmático é fazer a IA trabalhar <strong>a nosso favor</strong>. Usar IA pra triagem. Usar IA pra auditoria. Usar IA pra comparar diffs. Usar IA pra achar regressão. Usar IA pra escrever teste que falha antes e passa depois. Usar IA pra fazer o trabalho chato que cansa humano.</p>
<p>E manter a decisão humana onde ela importa.</p>
<p>Eu já disse isso várias vezes e vou repetir: <strong>IA é um espelho</strong>.</p>
<p>Se você é relaxado, ela acelera sua relaxação. Seu código vira AI slop industrializado.</p>
<p>Se você é engenheiro de verdade, ela amplifica sua engenharia. Você continua exigindo teste, CI, compatibilidade, migração, revisão, clean code, deploy, teste manual. Só que agora faz isso 10 vezes mais rápido.</p>
<p>E pras empresas: se você está pensando “ótimo, agora economizo porque não preciso contratar tantos programadores”, até dá pra entender. Até certo ponto. Mas se vai colocar IA no fluxo, então precisa reforçar QA. Mais teste, mais revisão, mais processo de validação, mais gente boa pensando em qualidade. Se não fizer isso, está ferrado. Vai trocar custo de desenvolvimento por custo de bug em produção, retrabalho, incidente e cliente irritado.</p>
<p>Não existe volta ao mundo 100% manual. Melhor parar de gastar energia tentando fechar a caixa de Pandora e começar a construir processo decente em volta do que saiu dela.</p>
]]></content:encoded><category>open-source</category><category>agentes-de-codigo</category><category>engenharia-de-software</category></item><item><title>Boas práticas de projetos de código aberto com LLM - O Mínimo</title><link>https://akitaonrails.github.io/2026/05/30/boas-praticas-projetos-codigo-aberto-llm-o-minimo/</link><guid isPermaLink="true">https://akitaonrails.github.io/2026/05/30/boas-praticas-projetos-codigo-aberto-llm-o-minimo/</guid><pubDate>Sat, 30 May 2026 13:00:00 -0300</pubDate><description>&lt;p&gt;Nos últimos meses eu publiquei uma penca de projetos pessoais no GitHub. &lt;a href="https://github.com/akitaonrails/frank_fbi"target="_blank" rel="noopener"&gt;Frank FBI&lt;/a&gt;, &lt;a href="https://github.com/akitaonrails/FrankMega"target="_blank" rel="noopener"&gt;Frank Mega&lt;/a&gt;, &lt;a href="https://github.com/akitaonrails/FrankYomik"target="_blank" rel="noopener"&gt;Frank Yomik&lt;/a&gt;, &lt;a href="https://github.com/akitaonrails/FrankSherlock"target="_blank" rel="noopener"&gt;Frank Sherlock&lt;/a&gt;, &lt;a href="https://github.com/akitaonrails/frank_investigator"target="_blank" rel="noopener"&gt;Frank Investigator&lt;/a&gt;, &lt;a href="https://github.com/akitaonrails/ai-jail"target="_blank" rel="noopener"&gt;ai-jail&lt;/a&gt;, &lt;a href="https://github.com/akitaonrails/ai-memory"target="_blank" rel="noopener"&gt;ai-memory&lt;/a&gt;, &lt;a href="https://github.com/akitaonrails/ai-usagebar"target="_blank" rel="noopener"&gt;ai-usagebar&lt;/a&gt;, &lt;a href="https://github.com/akitaonrails/ghpending"target="_blank" rel="noopener"&gt;ghpending&lt;/a&gt;, e por aí vai. Alguns em Ruby on Rails, a maioria em Rust, um ou outro em Flutter. Programados em grande parte com Claude Code e Codex, no embalo da minha &lt;a href="https://akitaonrails.github.io/2026/05/14/terminando-maratona-ia-sucesso-ou-fracasso/"&gt;maratona de vibe coding&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;E aqui está a parte que ninguém comenta quando fala de &amp;ldquo;fiz um projeto com IA&amp;rdquo;: gerar o código é a parte fácil. O difícil, o que separa um repositório que é só um amontoado de código de um projeto de código aberto de verdade, é tudo que vem &lt;strong&gt;depois&lt;/strong&gt; do &lt;code&gt;git init&lt;/code&gt;.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Nos últimos meses eu publiquei uma penca de projetos pessoais no GitHub. <a href="https://github.com/akitaonrails/frank_fbi"target="_blank" rel="noopener">Frank FBI</a>, <a href="https://github.com/akitaonrails/FrankMega"target="_blank" rel="noopener">Frank Mega</a>, <a href="https://github.com/akitaonrails/FrankYomik"target="_blank" rel="noopener">Frank Yomik</a>, <a href="https://github.com/akitaonrails/FrankSherlock"target="_blank" rel="noopener">Frank Sherlock</a>, <a href="https://github.com/akitaonrails/frank_investigator"target="_blank" rel="noopener">Frank Investigator</a>, <a href="https://github.com/akitaonrails/ai-jail"target="_blank" rel="noopener">ai-jail</a>, <a href="https://github.com/akitaonrails/ai-memory"target="_blank" rel="noopener">ai-memory</a>, <a href="https://github.com/akitaonrails/ai-usagebar"target="_blank" rel="noopener">ai-usagebar</a>, <a href="https://github.com/akitaonrails/ghpending"target="_blank" rel="noopener">ghpending</a>, e por aí vai. Alguns em Ruby on Rails, a maioria em Rust, um ou outro em Flutter. Programados em grande parte com Claude Code e Codex, no embalo da minha <a href="/2026/05/14/terminando-maratona-ia-sucesso-ou-fracasso/">maratona de vibe coding</a>.</p>
<p>E aqui está a parte que ninguém comenta quando fala de &ldquo;fiz um projeto com IA&rdquo;: gerar o código é a parte fácil. O difícil, o que separa um repositório que é só um amontoado de código de um projeto de código aberto de verdade, é tudo que vem <strong>depois</strong> do <code>git init</code>.</p>
<p>Eu tenho uma opinião forte sobre isso, então vou cravar logo: nenhum projeto de código aberto está pronto pra ser publicado sem três coisas. Na ordem de importância:</p>
<ol>
<li><strong>Superfície de instalação.</strong> O novo usuário precisa conseguir instalar e testar a ferramenta com o mínimo de atrito possível. Um comando, de preferência.</li>
<li><strong>Testes e CI automatizado.</strong> Pra que contribuições sejam mais fáceis e exista um chão comum sobre o que é minimamente aceitável pra entrar no projeto.</li>
<li><strong>Documentação.</strong> A versão curta e fácil de ler (o README) e um conjunto mais detalhado em <code>docs/</code>, pra novos contribuidores entenderem as decisões arquiteturais.</li>
</ol>
<p>Sem esses três, na minha visão, o projeto não está pronto. Pode ter o código mais genial do mundo dentro dele, não importa. Se um estranho não consegue instalar, não consegue confiar que o que ele mexer não vai quebrar tudo, e não consegue entender por que as coisas são do jeito que são, então você não tem um projeto de código aberto. Você tem um arquivo morto público.</p>
<p>E tem um bônus que virou parte essencial do meu fluxo: <strong>quando todos os meus projetos seguem o mesmo padrão, eu posso simplesmente pedir pro Claude Code ou pro Codex &ldquo;roda o deploy&rdquo; ou &ldquo;solta uma release&rdquo;, e eles conseguem.</strong> Porque a estrutura é previsível. <code>bin/deploy</code> faz a mesma coisa em todo projeto. A release sai de um tag. O agente não precisa adivinhar nada. Padronização é o que torna a automação confiável. Parece preciosismo de gente organizada, mas é o pré-requisito pra eu confiar de olhos fechados no que o agente vai rodar.</p>
<p>Vou destrinchar os três pilares e mostrar o mínimo de configuração que eu uso na prática.</p>
<h2>Pilar 1: A superfície de instalação<span class="hx:absolute hx:-mt-20" id="pilar-1-a-superfície-de-instalação"></span>
    <a href="#pilar-1-a-superf%c3%adcie-de-instala%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Essa é a mais importante e a mais negligenciada. As pessoas passam semanas afinando o algoritmo interno e aí soltam um README que diz &ldquo;clone o repo e rode <code>cargo build --release</code>&rdquo;. Aí o sujeito que tava curioso pra testar precisa ter Rust instalado, esperar dez minutos de compilação, e torcer pra não faltar uma lib de sistema. Você acabou de perder 90% dos seus usuários potenciais.</p>
<p>O ideal é oferecer <strong>vários caminhos</strong>, e deixar o usuário escolher o que combina com o ambiente dele. Olha o cabeçalho de instalação do ai-jail, que é o meu campeão de opções:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl"><span class="c1"># Homebrew (macOS ou Linux)</span>
</span></span><span class="line"><span class="cl">brew tap akitaonrails/tap <span class="o">&amp;&amp;</span> brew install ai-jail
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># AUR (Arch Linux) - binário pré-compilado</span>
</span></span><span class="line"><span class="cl">yay -S ai-jail-bin
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># cargo (qualquer plataforma com Rust)</span>
</span></span><span class="line"><span class="cl">cargo install ai-jail
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># mise</span>
</span></span><span class="line"><span class="cl">mise use -g github:akitaonrails/ai-jail
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Download direto do binário</span>
</span></span><span class="line"><span class="cl">curl -fsSL https://github.com/akitaonrails/ai-jail/releases/latest/download/ai-jail-linux-x86_64.tar.gz <span class="p">|</span> tar xz</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Cinco caminhos. O usuário de Arch usa <code>yay</code>. O do macOS usa <code>brew</code>. O dev Rust usa <code>cargo install</code>. Quem usa <a href="https://github.com/jdx/mise"target="_blank" rel="noopener">mise</a> pra gerenciar versões pega via mise. E quem só quer o binário baixa o tarball direto da release. Cada um pega o que já está acostumado, ninguém é forçado a instalar uma cadeia de ferramentas só pra experimentar.</p>
<h3>O segredo: compile uma vez, reempacote várias<span class="hx:absolute hx:-mt-20" id="o-segredo-compile-uma-vez-reempacote-várias"></span>
    <a href="#o-segredo-compile-uma-vez-reempacote-v%c3%a1rias" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>A pegadinha que assusta no começo é achar que cada formato de pacote exige um build separado. Não exige. O truque é <strong>compilar o binário uma vez por arquitetura, e depois reempacotar o mesmo binário em todos os formatos.</strong></p>
<p>No meu pipeline em Rust, o job de build gera um tarball com o binário pronto e o <code>sha256</code>. As etapas de empacotamento seguintes (Docker, AUR, Homebrew) <strong>baixam esse tarball já compilado</strong> ao invés de recompilar. Reduz tempo de CI, garante que o byte que vai pro AUR é exatamente o mesmo que vai pro Docker, e elimina aquela classe de bug &ldquo;funciona num formato e quebra no outro&rdquo;.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="c"># Job de Docker reaproveitando o binário já compilado</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">docker-amd64</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">needs</span><span class="p">:</span><span class="w"> </span><span class="l">build-linux</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">steps</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/download-artifact@v4</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">ai-memory-linux-x86_64</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">path</span><span class="p">:</span><span class="w"> </span><span class="l">artifacts</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Desempacota o binário pré-compilado</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="l">tar -xzf artifacts/ai-memory-linux-x86_64.tar.gz -C dist/docker/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">docker/build-push-action@v6</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">target</span><span class="p">:</span><span class="w"> </span><span class="l">runtime-prebuilt-amd64 </span><span class="w"> </span><span class="c"># injeta o binário, não recompila</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>O job do AUR faz a mesma coisa: baixa o tarball, calcula o <code>sha256</code>, e injeta no <code>PKGBUILD</code>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl"><span class="nv">X86_SHA</span><span class="o">=</span><span class="k">$(</span>awk <span class="s1">&#39;{print $1}&#39;</span> artifacts/ai-usagebar-linux-x86_64.tar.gz.sha256<span class="k">)</span>
</span></span><span class="line"><span class="cl">sed -i <span class="s2">&#34;s/^sha256sums_x86_64=.*/sha256sums_x86_64=(&#39;</span><span class="nv">$X86_SHA</span><span class="s2">&#39;)/&#34;</span> packaging/aur/PKGBUILD-bin</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Esse é o conceito central. O binário é o artefato de verdade. RPM, DEB, AppImage, AUR, tarball Homebrew, imagem Docker, tudo isso é só <strong>embalagem em volta do mesmo binário</strong>.</p>
<p>Os dois trechos acima são recortes. Se você quiser ver o fluxo inteiro funcionando, o build-once-reuse completo (binário compilado uma vez, reaproveitado nos jobs de Docker e AUR) está no <a href="https://github.com/akitaonrails/ai-memory/blob/main/.github/workflows/release.yml"target="_blank" rel="noopener"><code>release.yml</code> do ai-memory</a>, e a injeção de <code>sha256</code> no <code>PKGBUILD</code> está no <a href="https://github.com/akitaonrails/ai-usagebar/blob/main/.github/workflows/release.yml"target="_blank" rel="noopener"><code>release.yml</code> do ai-usagebar</a>.</p>
<h3>O cardápio de formatos<span class="hx:absolute hx:-mt-20" id="o-cardápio-de-formatos"></span>
    <a href="#o-card%c3%a1pio-de-formatos" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Cada plataforma tem seu mundo. Segue o mínimo que vale conhecer:</p>
<p><strong>Linux</strong> é o mais fragmentado. As opções, do mais simples pro mais trabalhoso:</p>
<ul>
<li><strong>Tarball</strong> (<code>.tar.gz</code>): o denominador comum. Funciona em qualquer distro, é só descompactar e jogar no <code>PATH</code>. Sempre ofereça esse.</li>
<li><strong>AUR</strong> (Arch): dois pacotes, o <code>-bin</code> (binário pré-compilado, instala em segundos) e o de source (compila na máquina do usuário). Eu publico os dois com a action <code>KSXGitHub/github-actions-deploy-aur</code>. O <code>-bin</code> é o que todo mundo usa.</li>
<li><strong>AppImage</strong>: um arquivo único executável que carrega todas as dependências dentro. Bom pra apps desktop. O Frank Sherlock, que é Tauri, gera AppImage direto no build e eu ainda assino com GPG depois (o passo de assinatura está no <a href="https://github.com/akitaonrails/FrankSherlock/blob/master/.github/workflows/release.yml"target="_blank" rel="noopener"><code>release.yml</code> dele</a>). Pra binário simples dá pra usar <code>appimagetool</code>.</li>
<li><strong>RPM e DEB</strong>: pra Fedora/openSUSE e Debian/Ubuntu. A ferramenta que poupa sua vida aqui é o <a href="https://github.com/goreleaser/nfpm"target="_blank" rel="noopener">nfpm</a>, que gera os dois a partir de um único <code>nfpm.yaml</code> declarativo, sem precisar entender as entranhas de <code>rpmbuild</code> ou <code>dpkg-deb</code>. Pega o binário já compilado e cospe os dois pacotes.</li>
</ul>
<p><strong>macOS</strong> tem dois alvos: Apple Silicon (<code>aarch64-apple-darwin</code>) e Intel (<code>x86_64-apple-darwin</code>). Você compila os dois separados ou gera um binário universal com <code>lipo</code>. E aqui mora a maior dor de cabeça da plataforma: <strong>assinatura e notarização</strong>. Sem isso, o Gatekeeper do macOS recusa abrir seu app. O fluxo é decodificar o certificado P12, importar num keychain temporário, assinar com <code>codesign --options runtime --timestamp</code>, e notarizar:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">codesign --sign <span class="s2">&#34;</span><span class="nv">$APPLE_SIGNING_IDENTITY</span><span class="s2">&#34;</span> --options runtime --timestamp ./meu-binario
</span></span><span class="line"><span class="cl">ditto -c -k meu-binario notarize.zip
</span></span><span class="line"><span class="cl">xcrun notarytool submit notarize.zip <span class="se">\
</span></span></span><span class="line"><span class="cl">  --apple-id <span class="s2">&#34;</span><span class="nv">$APPLE_ID</span><span class="s2">&#34;</span> --password <span class="s2">&#34;</span><span class="nv">$APPLE_PASSWORD</span><span class="s2">&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">  --team-id <span class="s2">&#34;</span><span class="nv">$APPLE_TEAM_ID</span><span class="s2">&#34;</span> --wait</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Isso exige uma conta paga de Apple Developer. É chato, mas é o preço de não dar erro de &ldquo;app danificado&rdquo; na cara do usuário. O job inteiro de assinatura e notarização, com a dança do keychain temporário, está no <a href="https://github.com/akitaonrails/ai-jail/blob/master/.github/workflows/release.yml"target="_blank" rel="noopener"><code>release.yml</code> do ai-jail</a>.</p>
<p><strong>Windows</strong> é o mais simples de buildar (<code>x86_64-pc-windows-msvc</code>) e o mais espinhoso de assinar. Certificado de code signing pra Windows é caro e burocrático, então eu, sinceramente, não assino. Aceito que o SmartScreen vai dar um aviso na primeira execução e deixo isso claro no README. Pra projeto pessoal de código aberto, está de bom tamanho.</p>
<p><strong>Rust crates</strong> (<code>cargo publish</code>): se é uma biblioteca ou CLI em Rust, publicar no <a href="https://crates.io"target="_blank" rel="noopener">crates.io</a> dá o <code>cargo install</code> de graça. Uma linha no pipeline. Dica: torne idempotente, porque rodar de novo num tag já publicado dá erro. Eu faço um <code>grep</code> na saída procurando &ldquo;already exists&rdquo; pra não quebrar a release inteira por causa disso.</p>
<p><strong>Homebrew</strong>: a forma limpa é manter um tap próprio (<code>akitaonrails/homebrew-tap</code>). O pipeline atualiza a fórmula com a nova URL e o novo <code>sha256</code> a cada release. O usuário faz <code>brew tap</code> uma vez e depois é só <code>brew upgrade</code>.</p>
<p><strong>mise</strong>: o <a href="https://github.com/jdx/mise"target="_blank" rel="noopener">mise</a> consegue instalar direto de releases do GitHub sem você configurar nada do seu lado, contanto que seus tarballs sigam uma convenção de nome de plataforma. Você ganha esse caminho praticamente de graça só por ter releases bem nomeadas.</p>
<p>Repara num detalhe: AUR, Homebrew, mise e o download direto <strong>todos consomem o mesmo tarball da release</strong>. Você publica os binários uma vez, e quatro gerenciadores de pacote diferentes sabem se virar. É por isso que &ldquo;compile uma vez, reempacote várias&rdquo; é a regra de ouro.</p>
<h2>Pilar 2: GitHub Actions, releases por tag e changelog<span class="hx:absolute hx:-mt-20" id="pilar-2-github-actions-releases-por-tag-e-changelog"></span>
    <a href="#pilar-2-github-actions-releases-por-tag-e-changelog" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A segunda coisa que torna um projeto de código aberto sério é CI. Esquece o selo de &ldquo;build passing&rdquo; no README, o valor está no chão comum que ele cria: quando alguém manda um pull request, o CI roda os testes, o linter e o scanner de segurança, e você sabe na hora se aquela contribuição quebra alguma coisa. Sem isso, todo PR vira uma negociação manual e cansativa.</p>
<p>Nos meus projetos Rust o CI roda <code>cargo fmt --check</code>, <code>cargo clippy -D warnings</code>, <code>cargo test</code>, e <code>cargo audit</code>. Nos projetos Rails, é <code>rubocop</code>, <code>brakeman</code> (scanner de segurança), <code>bundler-audit</code> e a suíte de testes em Minitest. O <a href="https://github.com/akitaonrails/FrankMD"target="_blank" rel="noopener">FrankMD</a> sozinho tem mais de 1800 testes entre Ruby e JavaScript. O Frank Sherlock passa de 300 testes em Rust mais 300 no frontend. É essa rede de segurança que me deixa aceitar PR de estranho sem medo.</p>
<h3>Revisão de PR com LLM<span class="hx:absolute hx:-mt-20" id="revisão-de-pr-com-llm"></span>
    <a href="#revis%c3%a3o-de-pr-com-llm" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Os testes e o CI são a rede de baixo. Acima dela tem uma camada que virou central no meu fluxo: usar o próprio LLM pra revisar os pull requests. O Opus e o GPT são absurdamente bons em code review e em refatoração de qualidade. Melhores que eu na consistência, porque não cansam e não passam o olho por cima de 200 linhas só porque já é a quinta revisão do dia.</p>
<p>Eu tenho dois prompts que uso o tempo todo. O primeiro, pra um PR específico que acabou de chegar:</p>
<blockquote>
  <p>olha o PR aberto no github. não confie na descrição do autor. audita o código a fundo pra ver se faz sentido. garante que não tem regressão nem queda na qualidade do código. garante que a cobertura de testes está adequada. depois me diz o que você acha que a gente deveria fazer.</p>

</blockquote>
<p>Repara no &ldquo;não confie na descrição do autor&rdquo;. Isso é de propósito. A descrição do PR conta o que a pessoa achou que fez, e nem sempre bate com o que ela realmente fez. O LLM tem que ler o código de verdade, não o resumo.</p>
<p>O segundo prompt é pra depois de uma sessão longa de código ou de vários PRs mergeados de uma vez:</p>
<blockquote>
  <p>a gente mexeu em muito código. audita o código que esses PRs mudaram, procura código morto, duplicação desnecessária, valor mágico hardcoded que deveria ser constante e/ou estar melhor documentado, falta de cobertura de teste, mira nos princípios de <a href="/2026/04/20/clean-code-para-agentes-de-ia/">clean code</a>, e depois verifica se a documentação foi devidamente atualizada.</p>

</blockquote>
<p>Com o parecer na mão, eu decido. Pra PR incompleto, o que eu faço depende do tamanho e da minha prioridade naquele momento. Se é coisa pequena, eu mesmo corrijo direto no PR com um <code>amend</code>, respondo explicando o que mudei, e aí mergeio e fecho. Quando dá pra mergear mas não dá pra corrigir antes, mergeio e já solto um commit de correção logo em seguida. E quando é mudança grande, peço pro LLM responder o PR explicando por que a gente não vai mergear, com a direção certa do que precisa ser feito.</p>
<p>Foi assim que eu fechei quase 40 PRs e 20 issues só no ai-memory, em poucos dias. Esse volume não sai na mão, e também não pode sair no piloto automático.</p>
<p>E é nesse ponto que eu mais bato: nada disso é cego. Eu estou o tempo todo pilotando o LLM na direção desses objetivos. Ele faz a auditoria, joga as sugestões na mesa e até escreve o texto da resposta, mas quem decide mergear, corrigir ou recusar sou eu. O LLM é o revisor incansável; eu sou quem assina embaixo.</p>
<h3>O gatilho por tag<span class="hx:absolute hx:-mt-20" id="o-gatilho-por-tag"></span>
    <a href="#o-gatilho-por-tag" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>A parte de release é separada do CI. Enquanto o CI roda a cada push e PR, a release dispara <strong>só quando você empurra um tag de versão</strong>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">on</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">push</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">tags</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="s1">&#39;v*.*.*&#39;</span><span class="w">   </span><span class="c"># dispara em v1.2.3, v0.5.0, etc.</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">workflow_dispatch</span><span class="p">:</span><span class="w"> </span><span class="c"># permite disparar manualmente também</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>O fluxo de soltar uma versão vira isso:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">git tag v0.5.0
</span></span><span class="line"><span class="cl">git push origin v0.5.0</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>E pronto. O GitHub Actions percebe o tag, dispara o workflow de release, compila pros alvos, empacota tudo, assina o que precisa assinar, cria o GitHub Release e publica nos gerenciadores de pacote. Eu não toco em mais nada. Inclusive é literalmente isso que eu peço pro Claude Code: &ldquo;solta a v0.5.0&rdquo;. Ele faz <code>cargo set-version</code>, atualiza o CHANGELOG, commita, cria o tag, empurra, e o resto é o pipeline.</p>
<p>A matriz de build em Rust compila cada alvo na plataforma nativa dele:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">strategy</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">matrix</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">include</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">os</span><span class="p">:</span><span class="w"> </span><span class="l">ubuntu-22.04</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">target</span><span class="p">:</span><span class="w"> </span><span class="l">x86_64-unknown-linux-gnu</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">os</span><span class="p">:</span><span class="w"> </span><span class="l">ubuntu-22.04-arm</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">target</span><span class="p">:</span><span class="w"> </span><span class="l">aarch64-unknown-linux-gnu</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">os</span><span class="p">:</span><span class="w"> </span><span class="l">macos-latest</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">target</span><span class="p">:</span><span class="w"> </span><span class="l">aarch64-apple-darwin</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">os</span><span class="p">:</span><span class="w"> </span><span class="l">windows-latest</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">target</span><span class="p">:</span><span class="w"> </span><span class="l">x86_64-pc-windows-msvc</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Uma pegadinha de cross-compilation: se você compila ARM dentro de uma máquina x86 (via <a href="https://github.com/cross-rs/cross"target="_blank" rel="noopener">cross</a>), você <strong>não consegue rodar os testes</strong> daquele binário ali, porque a arquitetura não bate. A solução é rodar os testes só no alvo nativo e cross-compilar o resto sem testar. O ai-usagebar faz exatamente isso, x86 nativo e ARM via <code>cross</code>, na matriz do <a href="https://github.com/akitaonrails/ai-usagebar/blob/main/.github/workflows/release.yml"target="_blank" rel="noopener"><code>release.yml</code> dele</a>. E sempre use cache de compilação: o <code>Swatinem/rust-cache</code> corta o tempo de build pela metade fácil.</p>
<h3>Release notes e changelog importam<span class="hx:absolute hx:-mt-20" id="release-notes-e-changelog-importam"></span>
    <a href="#release-notes-e-changelog-importam" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Aqui é onde muita gente relaxa, e não devia. Quando você solta uma release, a pessoa que está pensando em atualizar quer saber <strong>o que mudou</strong>. &ldquo;v0.5.0&rdquo; não diz nada. Um changelog diz.</p>
<p>Eu mantenho um <code>CHANGELOG.md</code> no formato <a href="https://keepachangelog.com/"target="_blank" rel="noopener">Keep a Changelog</a>, com uma seção por versão. E o pipeline extrai automaticamente a seção da versão atual pra colar no corpo do GitHub Release. Um <code>awk</code> simples resolve:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">awk -v <span class="nv">ver</span><span class="o">=</span><span class="s2">&#34;</span><span class="nv">$VERSION</span><span class="s2">&#34;</span> <span class="s1">&#39;
</span></span></span><span class="line"><span class="cl"><span class="s1">  BEGIN { hdr = &#34;## [&#34; ver &#34;]&#34; }
</span></span></span><span class="line"><span class="cl"><span class="s1">  index($0, hdr) == 1 { flag=1; next }
</span></span></span><span class="line"><span class="cl"><span class="s1">  flag &amp;&amp; index($0, &#34;## [&#34;) == 1 { exit }
</span></span></span><span class="line"><span class="cl"><span class="s1">  flag { print }
</span></span></span><span class="line"><span class="cl"><span class="s1">&#39;</span> CHANGELOG.md &gt; changelog_section.md</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Esse <code>awk</code> é o mesmo que roda na release do ai-usagebar (de novo no <a href="https://github.com/akitaonrails/ai-usagebar/blob/main/.github/workflows/release.yml"target="_blank" rel="noopener"><code>release.yml</code> dele</a>, que é o meu mais caprichado nessa parte). Aí eu anexo, depois do changelog, as instruções de instalação e os checksums <code>sha256</code> de cada artefato. O resultado é um GitHub Release que se explica sozinho: o que mudou, como instalar, e como verificar a integridade do download. O usuário lê e decide se atualiza. Esse é o tipo de cuidado que faz um estranho confiar no seu projeto.</p>
<h2>Pilar 3: Deploy de verdade, sem complicação<span class="hx:absolute hx:-mt-20" id="pilar-3-deploy-de-verdade-sem-complicação"></span>
    <a href="#pilar-3-deploy-de-verdade-sem-complica%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Os projetos que rodam como serviço (os Rails, principalmente) precisam ir pra algum lugar. E aqui eu vou na contramão do hype. Não tem Kubernetes. Não tem Kamal. Não tem pipeline de deploy de três estágios com aprovação manual.</p>
<p>Eu tenho um home server. Um <a href="/2026/03/31/migrando-meu-home-server-com-claude-code/">Minisforum MS-S1 Max rodando openSUSE MicroOS</a> que eu migrei recentemente, com um <a href="https://github.com/go-gitea/gitea"target="_blank" rel="noopener">Gitea</a> servindo de registry Docker privado na porta 3007. Pra um desenvolvedor solo com um servidor caseiro simples, isso é mais que suficiente. Toda a cerimônia de orquestração de cluster é resolver um problema que eu não tenho.</p>
<p>O deploy inteiro cabe num único <code>bin/deploy</code>. Ele faz três coisas: builda a imagem, empurra pro registry, e dá um SSH no servidor pra subir a versão nova:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl"><span class="cp">#!/usr/bin/env bash
</span></span></span><span class="line"><span class="cl"><span class="nb">set</span> -euo pipefail
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Config vem de um arquivo .gitignored, fora do repositório</span>
</span></span><span class="line"><span class="cl"><span class="nb">source</span> <span class="s2">&#34;</span><span class="k">$(</span>dirname <span class="s2">&#34;</span><span class="nv">$0</span><span class="s2">&#34;</span><span class="k">)</span><span class="s2">/../config/deploy.env&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">IMAGE</span><span class="o">=</span><span class="s2">&#34;</span><span class="si">${</span><span class="nv">REGISTRY_HOST</span><span class="si">}</span><span class="s2">:</span><span class="si">${</span><span class="nv">REGISTRY_PORT</span><span class="si">}</span><span class="s2">/akitaonrails/frank_fbi:latest&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;==&gt; Buildando a imagem...&#34;</span>
</span></span><span class="line"><span class="cl">docker build -t <span class="s2">&#34;</span><span class="nv">$IMAGE</span><span class="s2">&#34;</span> .
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;==&gt; Empurrando pro registry...&#34;</span>
</span></span><span class="line"><span class="cl">docker push <span class="s2">&#34;</span><span class="nv">$IMAGE</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;==&gt; Subindo no servidor...&#34;</span>
</span></span><span class="line"><span class="cl">ssh <span class="s2">&#34;</span><span class="si">${</span><span class="nv">DEPLOY_USER</span><span class="si">}</span><span class="s2">@</span><span class="si">${</span><span class="nv">DEPLOY_HOST</span><span class="si">}</span><span class="s2">&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">  <span class="s2">&#34;cd </span><span class="si">${</span><span class="nv">REMOTE_DIR</span><span class="si">}</span><span class="s2"> &amp;&amp; \
</span></span></span><span class="line"><span class="cl"><span class="s2">   docker compose pull &amp;&amp; \
</span></span></span><span class="line"><span class="cl"><span class="s2">   docker compose down --remove-orphans &amp;&amp; \
</span></span></span><span class="line"><span class="cl"><span class="s2">   docker compose up -d&#34;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>É isso. <code>build</code>, <code>push</code>, <code>ssh</code> com <code>pull</code>, <code>down</code>, <code>up</code>. Quatro comandos no servidor remoto, encadeados num SSH só. Sem agente rodando lá, sem webhook, sem painel de controle. O servidor tem um <code>docker-compose.production.yml</code> que aponta pra imagem <code>:latest</code> do registry, e o <code>pull</code> traz a versão nova.</p>
<p>Repara que os dados sensíveis ficam num <code>config/deploy.env</code> que <strong>não vai pro Git</strong>. No repositório vai só o <code>config/deploy.env.example</code>, com a estrutura e valores fictícios. Esse padrão de &ldquo;exemplo versionado, real ignorado&rdquo; se repete em todo projeto meu, e é o que permite o projeto ser público sem vazar host, usuário ou caminho do meu servidor.</p>
<p>A imagem em si vem de um Dockerfile multi-estágio. O estágio de build instala as ferramentas de compilação, builda tudo, e o estágio final copia só o resultado pra uma imagem enxuta, rodando como usuário não-root. O compose de produção troca <code>build:</code> por <code>image:</code>, aponta os volumes pros caminhos persistentes do servidor (<code>/var/opt/docker/...</code>) e usa <code>restart: always</code> pra subir tudo de novo se o servidor reiniciar.</p>
<p>E de novo a beleza da padronização: como <strong>todo</strong> projeto meu tem esse mesmo <code>bin/deploy</code>, eu posso falar pro Claude Code &ldquo;faz o deploy do Frank FBI&rdquo; e ele sabe exatamente o que rodar. Não preciso lembrar de comando nenhum. A ferramenta é a documentação executável do processo.</p>
<h2>A lição: ninguém liga pra sua stack<span class="hx:absolute hx:-mt-20" id="a-lição-ninguém-liga-pra-sua-stack"></span>
    <a href="#a-li%c3%a7%c3%a3o-ningu%c3%a9m-liga-pra-sua-stack" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Agora a parte que eu mais queria escrever, e que vale mais que todos os snippets de YAML acima.</p>
<p>A maioria das pessoas, quando vai apresentar um projeto, concentra tudo na tecnologia. &ldquo;Olha meu banco vetorial novinho.&rdquo; &ldquo;Olha meu framework reativo de última geração.&rdquo; &ldquo;Usei tal arquitetura de microsserviços.&rdquo; E enchem o topo do README com isso: a lista de dependências, o diagrama de componentes, a stack.</p>
<p>Ninguém liga.</p>
<p>Sério. O usuário que chega no seu README não quer saber qual banco de dados você usou. Ele quer saber <strong>que problema isso resolve pra ele</strong>. Detalhe de implementação não pertence ao topo do README. Pertence ao <code>docs/</code>, pra quem vai contribuir. No README, o que importa é o caso de uso.</p>
<p>Olha a diferença. &ldquo;Servidor MCP em Rust com FTS5 e consolidação opcional via LLM&rdquo; não diz nada pra ninguém. Agora &ldquo;memória de longo prazo compartilhada entre Claude Code, Codex e Cursor, com handoff entre sessões&rdquo; — isso o cara entende na hora, porque é a dor que ele tem. Os dois descrevem o ai-memory. Um fala de tecnologia, o outro fala do problema resolvido.</p>
<p>O caso de uso é a coisa mais importante do projeto inteiro. Antes de escrever uma linha de código, a pergunta certa é &ldquo;que problema isso resolve, e pra quem?&rdquo;. Se você não consegue responder isso numa frase, você está construindo uma <strong>solução em busca de um problema</strong>. E solução em busca de problema é, na prática, solução que não resolve nada. Não importa quão elegante seja o código por dentro.</p>
<p>A camada de UX, a superfície que o usuário toca, vale muito mais que a engenharia interna. Um projeto com tecnologia medíocre mas que é trivial de instalar, que diz claramente que problema resolve, e que tem documentação honesta, vai mais longe que um projeto genial que ninguém consegue rodar. Toda vez.</p>
<p>Então o mínimo, o verdadeiro mínimo pra um projeto de código aberto, é isto: instalação fácil, CI que dá confiança, documentação que começa pelo problema. O algoritmo bonito vem muito depois disso na fila de prioridades. Os três pilares deste post existem pra servir uma coisa só, que é a experiência de quem chega de fora. Acerta isso primeiro. O resto é detalhe de implementação.</p>
]]></content:encoded><category>open-source</category><category>engenharia-de-software</category><category>devops</category></item><item><title>Terminando Minha Maratona de IA: Sucesso ou Fracasso?</title><link>https://akitaonrails.github.io/2026/05/14/terminando-maratona-ia-sucesso-ou-fracasso/</link><guid isPermaLink="true">https://akitaonrails.github.io/2026/05/14/terminando-maratona-ia-sucesso-ou-fracasso/</guid><pubDate>Thu, 14 May 2026 14:00:00 -0300</pubDate><description>&lt;p&gt;Acho que finalmente saí do meu hiperfoco em IA. Quando comecei a acelerar em fevereiro e fui até quase maio, o objetivo era responder uma pergunta simples: dá ou não dá pra usar a nova geração de frontier LLMs da Anthropic e da OpenAI pra codar 100% do tempo? Resposta curta: dá.&lt;/p&gt;
&lt;p&gt;Em vez de fazer um demo de 1 dia e arriscar um &amp;ldquo;eu acho que sim&amp;rdquo;, resolvi ir all-in: mais de 500 horas, quase meio milhão de linhas de código e documentação, 24 repositórios entre públicos e privados.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Acho que finalmente saí do meu hiperfoco em IA. Quando comecei a acelerar em fevereiro e fui até quase maio, o objetivo era responder uma pergunta simples: dá ou não dá pra usar a nova geração de frontier LLMs da Anthropic e da OpenAI pra codar 100% do tempo? Resposta curta: dá.</p>
<p>Em vez de fazer um demo de 1 dia e arriscar um &ldquo;eu acho que sim&rdquo;, resolvi ir all-in: mais de 500 horas, quase meio milhão de linhas de código e documentação, 24 repositórios entre públicos e privados.</p>
<p>Mas hoje me chamaram atenção pra um ponto que eu não imaginei que fosse gerar dúvida:</p>
<blockquote>
  <p>&ldquo;Todos os 24 projetos são perfeitos, modelos de excelência de código?&rdquo; — <strong>ABSOLUTAMENTE NÃO.</strong></p>

</blockquote>
<p>Achei que isso fosse óbvio. Pra começo de conversa, se eu achasse que qualquer um deles fosse tão bom assim, já estaria abrindo uma startup em cima. Não me falta recurso pra investir. Se não estou fazendo isso, obviamente é tudo em ritmo de hobby.</p>
<p>Segundo ponto óbvio: se eu pulo de um projeto pra outro em poucos dias, é porque perdi o interesse. Se gostasse muito, estaria ajustando até hoje. Sempre falei nos vídeos: software nunca &ldquo;acaba&rdquo;. Quando para, morre.</p>
<p>O objetivo era testar tipos diferentes de projetos pra ver como as LLMs se saíam em cada caso. Por isso tem projeto em Ruby on Rails, Rust, Go, Python, Crystal. Mais frameworks como Tauri e Flutter. Eu achava, por exemplo, que Flutter sendo bem popular, as LLMs não teriam muito trabalho. Tiveram. Conseguem avançar, só não tão suave quanto em Rails. Tauri foi &ldquo;ruim&rdquo; também. Crystal foi BEM ruim.</p>
<p>Terceiro ponto: todo projeto experimental virou &ldquo;Frank&rdquo;. Sarcasmo, claro. Não tenho paciência pra inventar nome bonito num projeto que sei de antemão que vai ser one-off.</p>
<p>Eu uso meu GitHub basicamente como repositório de exercícios e experimentos. Olhem todos os repos do passado: quase nenhum é &ldquo;projeto&rdquo; de verdade que eu queira manter. Faço o que eu prego nos vídeos: pra aprender, exercite-se em MUITOS projetos, mesmo que a maioria seja pra JOGAR FORA. Ninguém aprende tentando fazer um único projeto perfeito. Veja meus vídeos <a href="/2020/05/15/a-dor-de-aprender/">A Dor de Aprender</a> ou o <a href="/2020/05/16/guia-definitivo-de-aprendendo-a-aprender/">Guia Definitivo de Aprendendo a Aprender</a>.</p>
<p>No meio de vários projetos meia-boca, alguns emergem naturalmente como os que eu gosto e mantenho. Na prática joguei todos contra a parede pra ver quais grudam. Os melhores naturalmente atraíram mais contribuidores também. Não fico vendo Issues e PRs todos os dias. Vejo uma vez por semana. Há uns dois ou três dias dei uma passada e fechei tudo que estava pendente, por exemplo. Mesmo nos projetos que não gosto tanto, se chega PR, eu reviso e aceito. Não foi útil pra mim, mas pode ser útil pra outra pessoa.</p>
<h2>O ranking dos projetos<span class="hx:absolute hx:-mt-20" id="o-ranking-dos-projetos"></span>
    <a href="#o-ranking-dos-projetos" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Pra ficar claro, segue um ranking dos projetos com comentário em cada um. As contagens de PR abaixo são não-dependabot (bump de gem não conta). A nota é minha estimativa de &ldquo;quão estável e usável isso está no estado atual&rdquo;.</p>
<h3>Tier de cima (7-8/10)<span class="hx:absolute hx:-mt-20" id="tier-de-cima-7-810"></span>
    <a href="#tier-de-cima-7-810" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p><strong><a href="https://github.com/akitaonrails/ai-jail"target="_blank" rel="noopener">ai-jail</a> — 8/10.</strong> O único que está bem próximo de uma release estável 1.0. Foi o que teve mais tração: 19 PRs fechadas, 23 Issues resolvidas. Recomendo usar, funciona muito bem.</p>
<p><strong>akitando-news (the M.Akita Chronicles) — 8/10.</strong> Foi o que fiz com mais cuidado, no modo &ldquo;Agile Vibe Coding&rdquo; que descrevi alguns posts atrás. E é o que eu mexo com mais frequência. Sempre tem coisinha pra ajustar, coisas que vou colocando, tirando, experimentando. Tanto que está funcionando toda semana. Por isso também: é fechado e não pretendo abrir.</p>
<p><strong><a href="https://github.com/akitaonrails/akitaonrails.github.io"target="_blank" rel="noopener">akitaonrails.github.io</a> — 7/10.</strong> É este blog. Mexo com frequência e já fechei umas 7 Issues e 30 PRs de contribuidores. Continuo ajustando aos poucos.</p>
<p><strong><a href="https://github.com/akitaonrails/FrankMD"target="_blank" rel="noopener">FrankMD</a> — 7/10.</strong> Foi um dos primeiros que fiz, sem critério nenhum: só queria um editor que tivesse upload automático de imagem pro meu S3. Hoje uso Claude Code pra editar os posts, então só quem contribui é quem usa. Esse teve bastante tração, fechei 17 PRs e 29 Issues. Não é perfeito, mas está bom pra usar, pelo menos foi testado o suficiente.</p>
<p><strong><a href="https://github.com/akitaonrails/easy-ffmpeg"target="_blank" rel="noopener">easy-ffmpeg</a> — 7/10.</strong> Projetinho pequeno, mas esse eu uso de fato nos vídeos. Meu OBS sempre grava em MKV e, quando quero compartilhar, converto pra MP4. Casos de uso pequenos assim. Está bom o suficiente pra usar.</p>
<h3>Tier do meio (5/10)<span class="hx:absolute hx:-mt-20" id="tier-do-meio-510"></span>
    <a href="#tier-do-meio-510" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p><strong><a href="https://github.com/akitaonrails/distrobox-gaming"target="_blank" rel="noopener">distrobox-gaming</a> — 5/10.</strong> É o mais recente, serve como &ldquo;dump&rdquo; de documentação dos meus retrogames. Uso como bloco de anotações e tem funcionado bem pro meu setup. Não estou preocupado que funcione pra mais ninguém. Quem quiser, manda PR.</p>
<p><strong><a href="https://github.com/akitaonrails/llm-coding-benchmark"target="_blank" rel="noopener">llm-coding-benchmark</a> — 5/10.</strong> Esse projeto não roda sozinho. Eu mando o Claude Code executar ele. O objetivo é tabular dados pra escrever os artigos sobre LLMs novas. O código deve estar BEM ruim.</p>
<p><strong><a href="https://github.com/akitaonrails/FrankMega"target="_blank" rel="noopener">FrankMega</a> — 5/10.</strong> É o mais próximo de um exercício &ldquo;todo list&rdquo;. Eu só precisava compartilhar um arquivo grande com um amigo e pensei &ldquo;hum, aposto que dá pra fazer um mini-mega em 1 dia&rdquo;. Foi isso. O nome é brincadeira, de jeito nenhum chega perto do Mega de verdade, óbvio.</p>
<p><strong><a href="https://github.com/akitaonrails/distrobox-llm"target="_blank" rel="noopener">distrobox-llm</a> — 5/10.</strong> Mais organização pessoal do meu PC: queria separar as ferramentas de IA num distrobox pra não ficar atualizando pacote grande toda hora.</p>
<h3>Tier de baixo (3-4/10)<span class="hx:absolute hx:-mt-20" id="tier-de-baixo-3-410"></span>
    <a href="#tier-de-baixo-3-410" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p><strong><a href="https://github.com/akitaonrails/FrankYomik"target="_blank" rel="noopener">FrankYomik</a> — 4/10.</strong> Essa era uma ideia na minha cabeça há anos. Só queria ver se o conceito funcionava. Funciona. Mas rodar LLMs locais pra isso é lento e não tão prático quanto eu gostaria. É o único que ainda devo voltar pra mexer mais, porque realmente quero usar. No estado atual, está em &ldquo;funciona, mais ou menos&rdquo;.</p>
<p><strong><a href="https://github.com/akitaonrails/NW-Omarchy"target="_blank" rel="noopener">NW-Omarchy</a> — 4/10.</strong> Outro experimento de &ldquo;será que dá?&rdquo;, que durou 2 dias. O conceito funcionou, mas não pretendo fazer muito mais que isso. Fica pra quem tiver interesse de continuar. Na prática eu quis testar se em X11 ficaria MUITO mais ruim que em Wayland. O gap é menor do que eu esperava, mas realmente não me vejo usando no dia a dia. Como já falei, pro nicho de pessoas que não tem como usar Wayland, é uma boa alternativa.</p>
<p><strong><a href="https://github.com/akitaonrails/frank_investigator"target="_blank" rel="noopener">frank_investigator</a> — 3/10.</strong> Comecei, mas não tive saco pra continuar. Plantei as sementes da ideia. Se ninguém mandar PR, vai evoluir pouco. Precisa de mais pesquisa e muito mais teste.</p>
<p><strong><a href="https://github.com/akitaonrails/frank_fbi"target="_blank" rel="noopener">frank_fbi</a> — 3/10.</strong> Mais um que quis testar o conceito, sem uso pessoal — nunca caí em phishing. Não sei pra onde levaria isso ainda.</p>
<p><strong><a href="https://github.com/akitaonrails/frank_karaoke"target="_blank" rel="noopener">frank_karaoke</a> — 3/10.</strong> Nasceu de uma conversa de fim de semana com meus irmãos. Mais uma tentativa de usar Flutter (e ver como tem limitação tanto no Flutter quanto nas LLMs usando Flutter). Serviu pra eu aprender sobre o ecossistema de karaokê e descobrir que pontuação de verdade só com metadado específico por música. Então não avancei muito além de brinquedo.</p>
<h3>Fundo do poço (1-2/10)<span class="hx:absolute hx:-mt-20" id="fundo-do-poço-1-210"></span>
    <a href="#fundo-do-po%c3%a7o-1-210" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p><strong><a href="https://github.com/akitaonrails/FrankSherlock"target="_blank" rel="noopener">FrankSherlock</a> — 2/10.</strong> Eu mesmo não uso. Por isso deve estar cheio de bug que precisa de correção. Foi teste pra ver se dava pra fazer um app Tauri, mas perdi o interesse rápido. Ainda dá pra melhorar, mas precisa de muito mais horas de uso, testes e correções. Foi a primeira vez que usei Tauri, então essa parte deve estar bem ruim também.</p>
<p><strong><a href="https://github.com/akitaonrails/FrankClaw"target="_blank" rel="noopener">FrankClaw</a> — 1/10.</strong> Eu mesmo não uso, e esse é o único que eu nem rodei uma única vez. O exercício foi só ver a dificuldade de traduzir o openclaw original de TypeScript pra Rust. Mas, como já postei várias vezes, não vejo utilidade no openclaw pra mim. Quando terminei a versão 0.1, parei. Ainda assim teve 6 PRs que fechei. Se alguém estiver interessado, pode contribuir.</p>
<p><strong><a href="https://github.com/akitaonrails/shadPS4"target="_blank" rel="noopener">shadPS4</a> — 1/10.</strong> Apesar de ter gerado muito código e muita documentação, nada foi pensado em virar contribuição. Foi exclusivamente aprendizado e pra resolver um problema muito específico. Deixei aberto pra mostrar como código puramente de material de estudo se parece.</p>
<p><strong><a href="https://github.com/akitaonrails/easy-subtitle"target="_blank" rel="noopener">easy-subtitle</a> — 1/10.</strong> Comecei, perdi o interesse, nunca parei pra testar de verdade. Só dei push e esqueci.</p>
<h3>Os privados<span class="hx:absolute hx:-mt-20" id="os-privados"></span>
    <a href="#os-privados" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Além do akitando-news, tenho no meu Gitea privado coisas como <code>my-omarchy-config</code>, <code>emulators-reorg-2026</code>, <code>thinkpad-omarchy-config</code>, <code>homelab-docs</code>, <code>akitando_english_translation</code> etc. Não vou descrever porque vocês nunca vão ver. Servem como &ldquo;scratchpads&rdquo; pro Claude Code administrar minhas máquinas.</p>
<h2>O que esse ranking diz<span class="hx:absolute hx:-mt-20" id="o-que-esse-ranking-diz"></span>
    <a href="#o-que-esse-ranking-diz" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Notem: não tem nenhum projeto que eu fiz que considero 10/10.</p>
<p>Pra um projeto sair de hobby e virar projeto de verdade, precisa de usuários e feedback. Se ninguém usa, sempre vai ter dezenas de bug funcional que nunca vai ser corrigido, porque ninguém esbarrou neles. Projeto sem usuário está morto.</p>
<p>Por isso eu repito nos vídeos: não existe planejar em detalhes, escrever um monte de código, e uma hora &ldquo;terminar&rdquo;. Não. Quando você acha que &ldquo;terminou&rdquo;, na verdade é a versão 0.1. Aí começam os meses de experimentação com usuário real reportando bug. Sair corrigindo. Dessas correções saem refatoramentos, mudanças de arquitetura porque as premissas iniciais estavam erradas comparado ao uso real. Software NUNCA acaba.</p>
<h2>O resumo do aprendizado dessa maratona<span class="hx:absolute hx:-mt-20" id="o-resumo-do-aprendizado-dessa-maratona"></span>
    <a href="#o-resumo-do-aprendizado-dessa-maratona" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>16 horas por dia, todos os dias, vibe coding, sempre vai sair com slop. Não tem jeito. Não adianta forçar quantidade. Tem que revisar manualmente, commit a commit, PR a PR. Por que eu não fiz isso em todos? Simples: não estou sendo pago. Fiz em uns 2 ou 3 projetos. O resto eu só queria testar o conceito e seguir pro próximo.</p>
<p>A forma correta é o que reportei vários posts atrás: &ldquo;Agile&rdquo; Vibe Coding. É meu jeito sarcástico de dizer &ldquo;use XP e técnicas normais de engenharia de software&rdquo;. Métricas, monitoramento, CI, etc. etc. Nada disso mudou. Sem isso, vai acabar como vários dos meus exercícios: one-off pra jogar fora.</p>
<p>Não tenha vergonha de subir projeto &ldquo;ruim&rdquo;. O que eu não pensei é que tem gente que assume que, só porque subi código, eu acho que é perfeito. Mas isso é o que essas pessoas fazem: acham que só vale a pena subir código bem feito, por isso nunca sobem nada. Eu já disse VÁRIAS vezes e demonstro: não ligo pro meu código, não tenho apreço pelo meu código, GitHub é diretório temporário de dump de qualquer coisa. Os que eu realmente gosto, normalmente estão privados.</p>
<p>Projeto realmente bom não basta &ldquo;dizer&rdquo; que é bom. Coloque seu dinheiro onde está sua boca: abra um negócio em cima, cobre dos usuários, entregue qualidade. Eu estou aposentado, não preciso cobrar nada, mas também não tenho vontade de trabalhar de graça. No momento que o código parou de me divertir, eu abandono e pulo pro próximo. Os que me interessaram mais (ai-jail, M.Akita Chronicles) continuo com mais frequência. Simples assim.</p>
<p>Como eu esperava, e como mostrei tanto nesses projetinhos quanto no benchmark, a escolha é simples: use GPT Codex ou Claude Code num dos planos subsidiados. Não pague por token. É onde está a produtividade 5x (máximo 10x, com slop junto). Sim, tem Kimi v2.6 ou DeepSeek V4 Pro. Mas adianto: os projetinhos abaixo de nota 5 virariam projetinhos abaixo de nota 2 com eles.</p>
<h2>O ponto que mais importa<span class="hx:absolute hx:-mt-20" id="o-ponto-que-mais-importa"></span>
    <a href="#o-ponto-que-mais-importa" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>IA não substitui um bom programador. IA reflete e acelera quem você é. Se é um bom programador, a IA acelera bom código. Se é um mau programador, a IA acelera mau código.</p>
<p>Foi exatamente o que eu mostrei: a maior parte dos projetos que eu fiz eram one-off e teste de conceito. Mau código, sem interesse de continuar. A IA acelerou eu terminar esses testes de forma meia-boca. Pra mim está ótimo: sem a IA eu nem teria começado. Agora que vi como fica, posso riscar da minha lista e seguir em frente.</p>
<p>O que importa é qual é seu OBJETIVO. Se for fazer um negócio e cobrar de gente, tem que ter 10x mais cuidado do que eu tive. Tudo que eu faço é pra jogar fora. Não preciso ganhar dinheiro com nenhum desses projetos. Não assumam coisa que eu nunca falei.</p>
]]></content:encoded><category>vibe-coding</category><category>agentes-de-codigo</category><category>engenharia-de-software</category></item><item><title>Clean Code pra Agentes de IA</title><link>https://akitaonrails.github.io/2026/04/20/clean-code-para-agentes-de-ia/</link><guid isPermaLink="true">https://akitaonrails.github.io/2026/04/20/clean-code-para-agentes-de-ia/</guid><pubDate>Mon, 20 Apr 2026 12:00:00 -0300</pubDate><description>&lt;p&gt;Em 2008, Robert C. Martin (Uncle Bob) lançou &lt;strong&gt;Clean Code: A Handbook of Agile Software Craftsmanship&lt;/strong&gt;. É um dos livros mais influentes da engenharia de software das últimas décadas. Pra quem não sabe, Uncle Bob começou a programar profissionalmente aos 17 anos, fundou a Object Mentor, assinou o Agile Manifesto, foi o primeiro chairman da Agile Alliance, é o criador do acrônimo SOLID. Ele escreveu uma dúzia de livros de design, arquitetura e prática, e influenciou gerações inteiras de desenvolvedores.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Em 2008, Robert C. Martin (Uncle Bob) lançou <strong>Clean Code: A Handbook of Agile Software Craftsmanship</strong>. É um dos livros mais influentes da engenharia de software das últimas décadas. Pra quem não sabe, Uncle Bob começou a programar profissionalmente aos 17 anos, fundou a Object Mentor, assinou o Agile Manifesto, foi o primeiro chairman da Agile Alliance, é o criador do acrônimo SOLID. Ele escreveu uma dúzia de livros de design, arquitetura e prática, e influenciou gerações inteiras de desenvolvedores.</p>
<p>Eu acompanho o Uncle Bob há muitos anos. Troquei mensagem com ele algumas vezes ao longo das décadas, tenho opinião formada sobre as posições dele, e cheguei a fazer uma live no meu canal onde a gente conversou por quase uma hora sobre Clean Code, Agile, Craftsmanship e pra onde a indústria tava indo. Se você nunca viu, recomendo:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/ycvaECDc31w"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>O Clean Code especificamente estabeleceu um padrão: código é escrito uma vez, mas lido dezenas de vezes. O trabalho do programador não é só fazer funcionar. É fazer funcionar <strong>de um jeito que outro programador consiga entender, modificar e não quebrar</strong>. Nomes significativos, funções pequenas, uma responsabilidade por classe, sem repetição, testes automatizados, estrutura clara. O público-alvo sempre foi outro ser humano sentado em frente ao editor tentando entender o que o primeiro fez.</p>
<p>Em 2026, esse público-alvo mudou.</p>
<h2>O público não é mais humano<span class="hx:absolute hx:-mt-20" id="o-público-não-é-mais-humano"></span>
    <a href="#o-p%c3%bablico-n%c3%a3o-%c3%a9-mais-humano" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Semana passada escrevi <a href="/2026/04/11/vs-code-e-o-novo-cartao-perfurado/">VS Code é o novo cartão perfurado</a>. A tese do artigo é que digitar código manualmente em editor de texto tá virando atividade de nicho, do mesmo jeito que digitar binário direto em painel de Altair virou relíquia depois que compiladores ficaram bons. O agente de IA é o novo compilador: eu descrevo intenção em linguagem natural, o agente navega código, edita, roda teste, ajusta, entrega.</p>
<p>Se essa tese tiver mesmo em pé, a pergunta seguinte é óbvia: <strong>pra quem a gente tá escrevendo código agora?</strong></p>
<p>Não é pro programador humano que vai sentar amanhã pra manter. É pro agente que vai ler, editar e estender. E agente não é humano. Agente tem restrições técnicas diferentes, vieses diferentes, limitações diferentes. Uma parte do Clean Code continua valendo (em alguns casos fica mais crítica). Outra parte muda de peso. E aparecem exigências novas que o Uncle Bob não tinha como antecipar em 2008.</p>
<p>Esse artigo é sobre isso. Qual a versão de Clean Code que faz sentido quando o leitor primário é um LLM?</p>
<h2>As restrições reais dos agentes<span class="hx:absolute hx:-mt-20" id="as-restrições-reais-dos-agentes"></span>
    <a href="#as-restri%c3%a7%c3%b5es-reais-dos-agentes" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Antes de re-ranquear, vale revisar o que os agentes enfrentam de verdade.</p>
<p><strong>Truncamento de arquivo.</strong> A maioria das CLIs de agente limita leitura de arquivo a faixas pequenas. O Claude Code lê por default 2000 linhas por vez. Cursor, Codex, Windsurf, todos têm limites parecidos. Arquivo gigante simplesmente não entra inteiro na janela de contexto numa tacada só, agente tem que pedir pedaço por pedaço, ou pior, usar grep e reconstruir mentalmente.</p>
<p><strong>Atenção degrada com contexto.</strong> Claude Opus tem contexto de 200k tokens, Sonnet de 1M, Gemini de 1M. Parece muito. Na prática, testes de &ldquo;needle in haystack&rdquo; mostram que a qualidade da recuperação cai bem antes do limite declarado. Flash Attention e variantes aceleram o cálculo, mas não substituem a atenção nativa cheia. Quanto mais coisa você enfia na janela, pior a precisão de detalhe. E o contexto do agente não tem só o seu código: tem CLAUDE.md, tem prompt do sistema, tem histórico de conversa, tem saída de tool, tem log de erro, tem output de teste. Tudo concorrendo pela mesma janela.</p>
<p><strong>Grep é mais barato que read.</strong> O agente sabe disso. Ele prefere <code>rg &quot;funcName&quot;</code> do que carregar arquivo inteiro. Fica mais rápido, usa menos token, mira no alvo. Nomes únicos e distintivos tornam isso muito mais eficaz. Isso não é atalho, é decisão arquitetural: escrevi sobre isso em detalhe em <a href="/2026/04/06/rag-esta-morto-contexto-longo/">RAG Está Morto? Contexto Longo, Grep e o Fim do Vector DB Obrigatório</a>, mostrando que o próprio Claude Code navega repositório com <code>Glob</code> e <code>Grep</code>, sem vector DB, sem embedding, e isso não é deficiência, é design maduro. Busca lexical + leitor inteligente consome o texto bruto bate retriever denso + top-k em praticamente todo benchmark de domínio real. Você se beneficia disso na hora de organizar seu código: nomes grepáveis não são só &ldquo;bom pra humano&rdquo;, são a API primária de navegação do agente.</p>
<p><strong>Tool calls custam token.</strong> Cada <code>Read</code> ou <code>Edit</code> ou <code>Bash</code> gasta tokens de input e output. Arquivo curto, output de teste pequeno, log enxuto, tudo isso mantém o agente produtivo e a conta baixa.</p>
<p><strong>Latência importa.</strong> Agente em loop, cada tool call adiciona segundos. Arquivo grande demorado de processar vira gargalo perceptível de sessão.</p>
<p><strong>Grepar por padrão visual é difícil.</strong> Se você usou indentação inconsistente, tab vs espaço misturado, brace style variado entre arquivos, o agente gasta tokens internalizando a bagunça. Consistência ajuda.</p>
<p>A partir dessas restrições, dá pra re-ranquear os princípios do Clean Code em ordem de relevância pra trabalho com agente.</p>
<h2>Re-ranqueamento: Clean Code na era dos agentes<span class="hx:absolute hx:-mt-20" id="re-ranqueamento-clean-code-na-era-dos-agentes"></span>
    <a href="#re-ranqueamento-clean-code-na-era-dos-agentes" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Vou da mais importante pra menos. Um aviso: não é que as de baixo deixam de importar. É que as de cima passaram a importar MUITO mais.</p>
<h3>1. Funções pequenas (e arquivos pequenos)<span class="hx:absolute hx:-mt-20" id="1-funções-pequenas-e-arquivos-pequenos"></span>
    <a href="#1-fun%c3%a7%c3%b5es-pequenas-e-arquivos-pequenos" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Uncle Bob: &ldquo;funções devem fazer UMA coisa, devem fazer BEM, e devem fazer só isso&rdquo;. Tamanho ideal de 4 a 20 linhas, no livro.</p>
<p>Pra agente, essa recomendação virou obrigação técnica. Uma função pequena cabe numa única tool call sem truncamento. Um arquivo curto (mantenha abaixo de 500 linhas, idealmente 200-300) cabe numa única leitura. Se o agente consegue pegar a unidade inteira de sentido numa chamada, ele raciocina sobre ela com atenção cheia. Se tem que paginar, ele monta um modelo mental fragmentado, e cada fragmento custa atenção.</p>
<p>Antigamente, &ldquo;função pequena&rdquo; era bom pra humano porque facilita leitura. Hoje, &ldquo;função pequena&rdquo; é bom porque casa com a unidade de processamento do modelo. Se tem uma recomendação pra levar em consideração, é essa.</p>
<h3>2. Single Responsibility Principle (SRP)<span class="hx:absolute hx:-mt-20" id="2-single-responsibility-principle-srp"></span>
    <a href="#2-single-responsibility-principle-srp" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Cada módulo faz uma coisa e tem uma razão pra mudar. Já era o coração do Clean Code. Pra agente, vira ainda mais crítico porque:</p>
<ul>
<li>O agente consegue isolar a unidade pra entender sem carregar o resto do sistema</li>
<li>Dá pra rodar teste focado sobre ela</li>
<li>Dá pra editar sem temer efeito colateral</li>
<li>Grep por responsabilidade vira previsível</li>
</ul>
<p>Código com responsabilidades embaralhadas força o agente a carregar muito mais contexto pra fazer qualquer mudança simples. Classe de 800 linhas que faz três coisas é pior pro agente do que três classes de 250 linhas, mesmo que o total seja o mesmo.</p>
<h3>3. Nomes significativos e únicos<span class="hx:absolute hx:-mt-20" id="3-nomes-significativos-e-únicos"></span>
    <a href="#3-nomes-significativos-e-%c3%banicos" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Clean Code já pregava: nomes revelam intenção, sem disinformação, distintivos, pronunciáveis, pesquisáveis. Pro agente, &ldquo;pesquisáveis&rdquo; virou a propriedade mais importante dessa lista.</p>
<p>Agente pesquisa código via grep/ripgrep o tempo todo. Nome genérico (<code>data</code>, <code>process</code>, <code>handler</code>, <code>Manager</code>, <code>Service</code>) retorna cinquenta matches e obriga o agente a ler cada um. Nome distintivo (<code>UserRegistrationValidator</code>, <code>InvoiceLineItemTotal</code>, <code>ClaudeCodeSessionTracker</code>) retorna três matches e o agente vai direto no certo.</p>
<p>Regra prática: se você grep o nome e vem muita coisa irrelevante, o nome tá ruim pro agente. Se vem só o que importa, o nome tá certo.</p>
<h3>4. Comentários com contexto e proveniência<span class="hx:absolute hx:-mt-20" id="4-comentários-com-contexto-e-proveniência"></span>
    <a href="#4-coment%c3%a1rios-com-contexto-e-proveni%c3%aancia" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Aqui é onde a inversão é mais gritante. Pra Uncle Bob em 2008, o axioma era: &ldquo;código bom se explica sozinho, comentário em excesso é code smell, cada comentário é uma dívida que fica desatualizada&rdquo;. Todo programador experiente que leu o livro absorveu essa regra. Código bem nomeado não precisa de comentário. Comentário demais = alerta de código ruim tentando se justificar.</p>
<p>Agora inverte. <strong>O agente lê os comentários. E gosta deles</strong>. Comentário vira contexto de primeira classe. O agente tem fluência perfeita de sintaxe, sabe exatamente o que <code>x++</code> faz, não precisa de legenda óbvia (esse tipo ainda é ruim, olha o item 13). O que ele NÃO sabe é por que você escolheu essa abordagem em vez da óbvia, qual bug de produção motivou essa lógica estranha, qual constraint de negócio força essa ordem específica, qual workaround existe porque a lib upstream tem bug conhecido #1234, qual commit introduziu essa decisão, qual issue do Jira é a referência. Esse tipo de informação é <strong>proveniência</strong>: o porquê da decisão. Só existe na cabeça do humano que escreveu, na mensagem de commit, ou num comentário bem colocado. Pro agente, o comentário é a fonte mais acessível durante um tool call.</p>
<p>Docstring com intenção e exemplo de uso também viraram sinal forte. Quando o agente pega uma função sem entender o contexto, docstring de cabeça (tipo JSDoc com exemplos, Python <code>&quot;&quot;&quot;</code>, Rust <code>///</code>) encurta drasticamente o caminho pra uma mudança correta. Uncle Bob era cético de JavaDoc em 2008 porque ficava desatualizado. Hoje, com o agente podendo reescrever a docstring junto com o código, esse contra-argumento perdeu peso.</p>
<p>Uma consequência prática disso é: <strong>não pode os comentários que o agente escreve</strong>. Se você tem o reflexo &ldquo;comentário verboso é ruído&rdquo; herdado da era Clean Code original, essa regra mudou. O agente colocou aquele comentário porque no ato de gerar o código ele decidiu que aquela informação era digna de preservar pra futura edição. Remover o comentário no code review é tirar contexto que o próprio agente vai querer ler na próxima interação. Deixa o agente comentar. Ele sabe o que faz. O único tipo de comentário do agente que vale remover é o comentário óbvio e redundante (item 13), e mesmo esses os modelos recentes raramente produzem se o system prompt tá bem escrito.</p>
<h3>5. Tipos explícitos<span class="hx:absolute hx:-mt-20" id="5-tipos-explícitos"></span>
    <a href="#5-tipos-expl%c3%adcitos" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Isso não tá no Clean Code de 2008 porque a indústria ainda não tinha se convertido. Mas em 2026 é critério fundamental.</p>
<p>Python sem type hints, JavaScript em vez de TypeScript, Ruby sem RBS. Código dinâmico sem anotação obriga o agente a inferir tipo a partir de uso, o que custa raciocínio e erra frequentemente. Código tipado dá gabarito imediato: assinatura fala o que entra, o que sai, quais estados são válidos. O agente economiza trabalho de descoberta e erra menos.</p>
<p>Se você ainda tá em Python 3 sem type hints, a transição vai aumentar a produtividade do agente muito mais do que qualquer refactoring de lógica.</p>
<h3>6. DRY (Don&rsquo;t Repeat Yourself)<span class="hx:absolute hx:-mt-20" id="6-dry-dont-repeat-yourself"></span>
    <a href="#6-dry-dont-repeat-yourself" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Clean Code já dizia: duplicação é raiz de todo mal. Pra agente, duplicação é pior que pra humano por uma razão específica: quando o agente tem que mudar uma coisa que tá replicada, ele pode atualizar uma cópia e esquecer das outras. A janela de atenção dele não tem gravidade natural que puxe &ldquo;ah, tem mais duas cópias disso em outros arquivos&rdquo;. Ele tem que achar cada uma via grep, e se o padrão tem variação sutil entre as cópias, o resultado fica inconsistente.</p>
<p>Fatorar em função ou módulo reutilizável não é estética. É segurança de refactor automatizado.</p>
<h3>7. Testes que o agente consegue rodar<span class="hx:absolute hx:-mt-20" id="7-testes-que-o-agente-consegue-rodar"></span>
    <a href="#7-testes-que-o-agente-consegue-rodar" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Uncle Bob dedica um capítulo inteiro a Unit Tests e o F.I.R.S.T (Fast, Independent, Repeatable, Self-Validating, Timely). Continua valendo tudo, com um adendo importante: <strong>o teste precisa ser executável pelo agente sem setup humano</strong>.</p>
<p>Isso significa: comando pra rodar o teste tá no README ou CLAUDE.md, tá no <code>Makefile</code>, tá no <code>package.json</code>. Output tem formato previsível que o agente parseia. Não depende de seed manual de banco, de arquivo de config que não tá no repo, de credencial secreta. O agente escreve código, roda teste, lê output, ajusta, roda de novo. Esse ciclo é a base de tudo. Se o teste não roda headless, o agente fica cego.</p>
<p>Aqui eu falo com experiência de campo. Documentei isso no <a href="/2026/02/20/do-zero-a-pos-producao-em-1-semana-como-usar-ia-em-projetos-de-verdade-bastidores-do-the-m-akita-chronicles/">Do Zero a Pós-Produção em 1 Semana com IA</a>, onde mandei ver num projeto real: 274 commits em 8 dias, 4 aplicações integradas, 1.323 testes automatizados no final. O que fez aquilo funcionar não foi &ldquo;IA programa sozinha&rdquo;. Foi <strong>Extreme Programming com agente no lugar do par humano</strong>. Rodar teste em cada commit, ter CI apertado, cobertura acima de 80% (95%+ na lógica de negócio), ratio de linha-de-teste pra linha-de-código em alguns módulos maior que 1:1. Parece overkill. Não é. Em 274 commits, o CI pegou bug real mais de 50 vezes, bugs que iriam direto pra produção se eu tivesse confiado cegamente no agente. Sem teste, o agente te entrega código plausível que silenciosamente quebra algo que funcionava ontem. Com teste forte, o agente vira multiplicador: ele gera teste, o teste valida o código que ele escreveu, o teste é a rede de segurança da próxima mudança dele. Loop virtuoso.</p>
<p>As práticas do XP (pair programming, CI, testes antes, refactoring contínuo, feedback curto) não ficaram obsoletas. Viraram <strong>exatamente o jeito certo de trabalhar com agente</strong>. Quem programa em cowboy mode sem teste, hoje, não é rebelde. É só lento, porque o agente sem teste fica chutando, e chute precisa ser revisado na mão, o que mata a velocidade que o agente deveria trazer. Testes bons com cobertura bem feita viraram a diferença entre agente produtivo e agente que fica chutando. Ou, dito de outro jeito: <strong>TDD virou obrigação técnica, não mais filosofia</strong>.</p>
<p>Cobri esse tema de outro ângulo em <a href="/2026/03/01/software-nunca-esta-pronto-4-projetos-a-vida-pos-deploy-e-por-que-one-shot-prompt-e-mito/">Software Nunca Está &ldquo;Pronto&rdquo;</a>, mostrando que a vida de pós-deploy é onde o teste mais importa: em dez dias de operação depois do lançamento, eu rodei 56 commits de correção, hardening e ajuste em resposta a comportamento real, e cada commit foi acompanhado de teste de regressão. Sem rede, cada um desses 56 commits seria uma oportunidade de quebrar algo que funcionava ontem. TDD não é fase, é hábito.</p>
<h3>8. Estrutura de diretório previsível<span class="hx:absolute hx:-mt-20" id="8-estrutura-de-diretório-previsível"></span>
    <a href="#8-estrutura-de-diret%c3%b3rio-previs%c3%advel" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Clean Code pouco fala sobre isso (tava mais focado em código dentro de arquivo). Pra agente, a organização em árvore importa. Se <code>src/controllers/users.rb</code> implica que tem <code>src/models/user.rb</code> e <code>src/views/users/</code>, o agente consegue antecipar paths sem precisar listar diretório. Se o projeto usa nomenclatura idiossincrática (arquivos random, nomes sem padrão, tudo flat numa pasta), o agente perde tempo com <code>find</code>.</p>
<p>Convenções fortes de framework (Rails, Django, Next.js, Laravel) ajudam muito agente. Projeto sem convenção, o agente cria uma com o tempo, mas até lá gasta tokens explorando.</p>
<h3>9. Dependency Injection e Testabilidade<span class="hx:absolute hx:-mt-20" id="9-dependency-injection-e-testabilidade"></span>
    <a href="#9-dependency-injection-e-testabilidade" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Código com dependências injetadas (não hardcoded) é mais fácil de testar em isolamento. O agente aproveita isso. Ele consegue substituir o <code>EmailSender</code> real por um <code>FakeEmailSender</code> no teste, sem tocar na lógica. Código que instancia suas dependências internamente obriga o agente a gambiarra-monkey-patch-sobe-servidor-de-mentira, que é lento, frágil, e polui a sessão com sujeira de infra.</p>
<p>DI não é cerimônia. É escopo de isolamento. E em projeto de vida real, DI vira rapidamente refactor load-bearing: num dos meus projetos (o <a href="/2026/03/01/software-nunca-esta-pronto-4-projetos-a-vida-pos-deploy-e-por-que-one-shot-prompt-e-mito/">M.Akita Chronicles</a>), eu descobri depois do lançamento que precisava trocar o modelo LLM default pra outro provedor. A variável de ambiente existia desde o início. Mas o nome do modelo ainda estava hardcoded em referência em 24 arquivos. Um commit inteiro (<code>Centralize LLM model config</code>) tocou os 24 pra isolar a config numa constante única. Trocar de modelo depois disso virou mudança de uma linha. Esse é exatamente o tipo de refactor que só aparece depois que o software encosta na realidade, e é onde DI e isolamento de config pagam caro se você não fez antes.</p>
<h3>10. Evitar aninhamento profundo<span class="hx:absolute hx:-mt-20" id="10-evitar-aninhamento-profundo"></span>
    <a href="#10-evitar-aninhamento-profundo" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Clean Code fala de nível único de abstração por função. Um corolário é: evite <code>if</code> dentro de <code>for</code> dentro de <code>if</code> dentro de <code>try</code>. Cada nível de indentação é mais atenção que o modelo tem que gastar rastreando estado. Indentação de quatro níveis é MUITO mais cara cognitivamente pro agente do que dois níveis com early return.</p>
<p>Pattern matching, guard clauses, early returns, flatten de lógica, tudo isso melhora a legibilidade pro modelo igual melhora pra humano, só que de forma mais mensurável porque o custo é medido em qualidade de resposta.</p>
<h3>11. Erro com contexto<span class="hx:absolute hx:-mt-20" id="11-erro-com-contexto"></span>
    <a href="#11-erro-com-contexto" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p><code>raise ValueError(&quot;invalid input&quot;)</code> não ajuda o agente quando ele lê o stack trace. <code>raise ValueError(f&quot;invalid input: received {repr(x)}, expected non-empty string of digits&quot;)</code> ajuda. O agente usa mensagem de exceção como sinal pra debug. Mensagem vaga = agente roda round extra pra descobrir o que deu errado.</p>
<p>Uncle Bob falava disso em Error Handling: &ldquo;Provide context with exceptions&rdquo;. Virou crítico agora.</p>
<h3>12. Formatação e estilo<span class="hx:absolute hx:-mt-20" id="12-formatação-e-estilo"></span>
    <a href="#12-formata%c3%a7%c3%a3o-e-estilo" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Não perde tempo nisso. Usa o formatador default ou mais popular da linguagem: <code>cargo fmt</code> pra Rust, <code>gofmt</code> pra Go, <code>prettier</code> pra JS/TS, <code>black</code> ou <code>ruff</code> pra Python, <code>rubocop -A</code> pra Ruby. Configura no pre-commit, configura no editor pra rodar ao salvar, e segue a vida. O agente lida bem com qualquer estilo consistente, e o formatador automático garante que o diff não fica bagunçado entre commits. Discussão de tab vs espaço, 80 vs 100 colunas, brace style, tudo isso virou ruído. O formatador decide, você aceita.</p>
<h3>13. Comentário que descreve o óbvio<span class="hx:absolute hx:-mt-20" id="13-comentário-que-descreve-o-óbvio"></span>
    <a href="#13-coment%c3%a1rio-que-descreve-o-%c3%b3bvio" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>A última da lista. Continua ruim, virou ainda mais ruim. Comentários como <code>// increment i by 1</code> acima de <code>i++</code> desperdiçam tokens no agente exatamente como desperdiçavam paciência no humano. Modelo sabe ler código, não precisa de legenda óbvia.</p>
<p>Se você tem o hábito de escrever comentários óbvios porque alguma escola te ensinou assim, esse é o momento de parar. Em 2008 era ruim porque poluía visual. Em 2026 é ruim porque custa dinheiro real em tokens.</p>
<h2>O que Uncle Bob não podia antever<span class="hx:absolute hx:-mt-20" id="o-que-uncle-bob-não-podia-antever"></span>
    <a href="#o-que-uncle-bob-n%c3%a3o-podia-antever" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Além de re-ranquear o que tava no livro, algumas coisas novas surgiram que são específicas do mundo de agentes:</p>
<p><strong>Arquivos de meta-documentação pra agentes.</strong> <code>CLAUDE.md</code>, <code>AGENTS.md</code>, <code>.cursor/rules</code>, e afins. São arquivos que o agente lê antes de qualquer tool call, descrevendo convenções do projeto, comandos importantes, caveats, coisas que não vão em docstring. Escrever esses arquivos é um skill novo: curto, direto, imperativo, orientado a ações. Nada de prosa filosófica. Bulletpoint do que agente precisa saber pra não cagar.</p>
<p><strong>README com arquitetura alto nível.</strong> Uncle Bob pouco se importava com README (o livro é sobre código). Pra agente, READMEs bem feitos encurtam muito o caminho pro agente entender o shape do projeto. Diagrama simples em ASCII ou Mermaid ajuda.</p>
<p><strong>Logging estruturado.</strong> Log em formato JSON com campos nomeados é muito mais útil pro agente do que log em prosa. Agente parseia JSON trivialmente, usa os campos pra filtrar erro relevante, correlaciona entre serviços. <code>printf</code> solto em texto livre obriga parsing heurístico.</p>
<p><strong>Comandos de observabilidade acessíveis.</strong> <code>pnpm test</code>, <code>make lint</code>, <code>cargo check</code>, <code>python -m mypy</code> — quanto mais o projeto expõe comandos previsíveis que o agente pode invocar pra validar mudanças, melhor. Se pra rodar teste precisa de 10 passos de setup manual, o agente não roda teste, e o ciclo de feedback quebra.</p>
<p><strong>Scripts de setup idempotentes.</strong> Agente tem que poder rodar <code>bin/setup</code> ou <code>scripts/bootstrap.sh</code> numa máquina limpa e chegar num estado que permita trabalhar. Se o onboarding depende de instruções em cabeça humana, o agente tá excluído do jogo.</p>
<h2>Instruindo o agente a escrever código limpo<span class="hx:absolute hx:-mt-20" id="instruindo-o-agente-a-escrever-código-limpo"></span>
    <a href="#instruindo-o-agente-a-escrever-c%c3%b3digo-limpo" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Tem um detalhe importante que só fica claro depois de umas 500 horas usando agente: <strong>nenhum LLM faz essas coisas por default</strong>. Você pede pra ele &ldquo;implementa a feature X&rdquo; e ele vai implementar do jeito que o modelo acha médio. Sem injeção de dependência. Com funções de 80 linhas. Sem testes, ou com testes que mockam coisa errada. Duplicando lógica porque é mais rápido. Criando arquivo de 2000 linhas porque &ldquo;fica tudo junto&rdquo;. Você precisa ESCREVER essas regras. O agente lê, e segue.</p>
<p>Onde escrever: <code>CLAUDE.md</code>, <code>AGENTS.md</code>, <code>.cursor/rules</code>, <code>.github/copilot-instructions.md</code>, dependendo da CLI. Formato: curto, imperativo, orientado a ação. Agente lê esses arquivos a cada iteração (o Claude Code relê o CLAUDE.md em toda query), então cada linha gasta token de contexto — densidade importa.</p>
<p>Abaixo segue uma proposta de template pra você colar num <code>CLAUDE.md</code> de projeto novo, consolidando o que discuti acima em formato que o agente consome. <strong>Não é versão definitiva</strong>, é ponto de partida pra testar, ajustar à sua linguagem, ao seu time, ao seu fluxo. Se alguma regra não encaixar no teu contexto, remove. Se precisar de regra nova, adiciona. O ponto é ter o esqueleto estruturado:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-markdown" data-lang="markdown"><span class="line"><span class="cl"><span class="gu">## Code style
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">-</span> Functions: 4-20 lines. Split if longer.
</span></span><span class="line"><span class="cl"><span class="k">-</span> Files: under 500 lines. Split by responsibility.
</span></span><span class="line"><span class="cl"><span class="k">-</span> One thing per function, one responsibility per module (SRP).
</span></span><span class="line"><span class="cl"><span class="k">-</span> Names: specific and unique. Avoid <span class="sb">`data`</span>, <span class="sb">`handler`</span>, <span class="sb">`Manager`</span>.
</span></span><span class="line"><span class="cl">  Prefer names that return &lt;5 grep hits in the codebase.
</span></span><span class="line"><span class="cl"><span class="k">-</span> Types: explicit. No <span class="sb">`any`</span>, no <span class="sb">`Dict`</span>, no untyped functions.
</span></span><span class="line"><span class="cl"><span class="k">-</span> No code duplication. Extract shared logic into a function/module.
</span></span><span class="line"><span class="cl"><span class="k">-</span> Early returns over nested ifs. Max 2 levels of indentation.
</span></span><span class="line"><span class="cl"><span class="k">-</span> Exception messages must include the offending value and expected shape.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="gu">## Comments
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">-</span> Keep your own comments. Don&#39;t strip them on refactor — they carry
</span></span><span class="line"><span class="cl">  intent and provenance.
</span></span><span class="line"><span class="cl"><span class="k">-</span> Write WHY, not WHAT. Skip <span class="sb">`// increment counter`</span> above <span class="sb">`i++`</span>.
</span></span><span class="line"><span class="cl"><span class="k">-</span> Docstrings on public functions: intent + one usage example.
</span></span><span class="line"><span class="cl"><span class="k">-</span> Reference issue numbers / commit SHAs when a line exists because
</span></span><span class="line"><span class="cl">  of a specific bug or upstream constraint.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="gu">## Tests
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">-</span> Tests run with a single command: <span class="sb">`&lt;project-specific&gt;`</span>.
</span></span><span class="line"><span class="cl"><span class="k">-</span> Every new function gets a test. Bug fixes get a regression test.
</span></span><span class="line"><span class="cl"><span class="k">-</span> Mock external I/O (API, DB, filesystem) with named fake classes,
</span></span><span class="line"><span class="cl">  not inline stubs.
</span></span><span class="line"><span class="cl"><span class="k">-</span> Tests must be F.I.R.S.T: fast, independent, repeatable,
</span></span><span class="line"><span class="cl">  self-validating, timely.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="gu">## Dependencies
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">-</span> Inject dependencies through constructor/parameter, not global/import.
</span></span><span class="line"><span class="cl"><span class="k">-</span> Wrap third-party libs behind a thin interface owned by this project.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="gu">## Structure
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">-</span> Follow the framework&#39;s convention (Rails, Django, Next.js, etc.).
</span></span><span class="line"><span class="cl"><span class="k">-</span> Prefer small focused modules over god files.
</span></span><span class="line"><span class="cl"><span class="k">-</span> Predictable paths: controller/model/view, src/lib/test, etc.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="gu">## Formatting
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">-</span> Use the language default formatter (<span class="sb">`cargo fmt`</span>, <span class="sb">`gofmt`</span>, <span class="sb">`prettier`</span>,
</span></span><span class="line"><span class="cl">  <span class="sb">`black`</span>, <span class="sb">`rubocop -A`</span>). Don&#39;t discuss style beyond that.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="gu">## Logging
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">-</span> Structured JSON when logging for debugging / observability.
</span></span><span class="line"><span class="cl">- Plain text only for user-facing CLI output.</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Esse bloco cabe em menos de 100 linhas e gasta cerca de 500 tokens por iteração. Parece muito, mas a economia em qualidade de código e em ausência de retrabalho compensa facilmente, especialmente se você tá numa conta API paga por token. Tomem como base e evoluam com a experiência de cada um.</p>
<p>Alguns itens (SRP, funções pequenas, testes) o agente até tenta fazer sozinho. Outros (DI, DRY rigoroso, tipos explícitos em TODO lugar, nomes agressivamente únicos) ele só faz quando você fala explícito. E alguns (como &ldquo;não apaga os comentários que você mesmo escreveu no refactor&rdquo;) são tão contraintuitivos pro treino padrão dele que sem a instrução ele VAI podar. Daí a importância do arquivo de regras existir e ser lido a cada iteração.</p>
<p>Tem um padrão análogo que vale mencionar, ligado ao princípio de defensive programming: o agente implementa circuit breaker, retry com backoff, timeout agressivo, graceful degradation, tudo certinho — <strong>quando você pede</strong>. Mas sozinho ele não vai propor. O agente não sabe quais são os pontos de falha operacional do teu sistema, então ele implementa o caminho feliz e espera instrução. Se a tua CLAUDE.md listar as categorias de defensive code que o projeto precisa (rate limit, retry, breaker, fallback), o agente cobre. Se não listar, ele não inventa. É outro caso em que a instrução explícita pro agente é o que separa código robusto de código ingênuo.</p>
<p>Se você usar o mesmo agente em projetos diferentes, vale ter um template base e adicionar rules específicas por projeto no topo. Mas comece com algo parecido com o acima e itere em cima.</p>
<h2>A versão curta<span class="hx:absolute hx:-mt-20" id="a-versão-curta"></span>
    <a href="#a-vers%c3%a3o-curta" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Uncle Bob escreveu o Clean Code pra ser lido por outros humanos. Em 2026, o leitor primário virou o agente. A boa notícia é que a maioria das coisas que o livro pregava continua valendo. A má notícia é que algumas coisas que eram opinião (&ldquo;arquivo deve ter N linhas&rdquo;) viraram restrição técnica (&ldquo;arquivo com X linhas faz o agente performar pior&rdquo;). A diferença é que agora tem métrica: custo de token, latência de tool call, qualidade de output. Quem escreve código limpo pro agente economiza dinheiro de conta de API, tempo de sessão, e tem menos alucinação no output.</p>
<p>E tem um bônus cultural que vale registrar: todas essas práticas (XP, TDD, SOLID, SRP, DI, código pequeno, testes abundantes) estavam caindo em desuso nos anos 2010, substituídas por &ldquo;move fast and break things&rdquo; e bootcamp de dois meses. Os programadores que investiram em fundamento viraram minoria, e virou fashion falar mal de Uncle Bob na internet. Acontece que exatamente esses fundamentos passaram a ser o diferencial técnico de trabalhar com agente. Quem manteve a disciplina, tá bem servido. Quem desprezou, tá apanhando pra ensinar o agente a não cometer erros que a turma do XP tinha mapeado 25 anos atrás.</p>
<p>Código limpo nunca foi moda. Virou infraestrutura.</p>
]]></content:encoded><category>engenharia-de-software</category><category>agentes-de-codigo</category></item><item><title>O código fonte do Claude Code vazou. O que achamos dentro.</title><link>https://akitaonrails.github.io/2026/03/31/codigo-fonte-do-claude-code-vazou-o-que-achamos-dentro/</link><guid isPermaLink="true">https://akitaonrails.github.io/2026/03/31/codigo-fonte-do-claude-code-vazou-o-que-achamos-dentro/</guid><pubDate>Tue, 31 Mar 2026 17:00:00 -0300</pubDate><description>&lt;blockquote&gt;
&lt;p&gt;Atualizado em 2 de abril de 2026: se você já tinha lido este texto ontem, vale pular direto para a &lt;a href="#update-2026-04-02"&gt;nova seção de atualização&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Hoje de manhã (31 de março de 2026), o pesquisador de segurança &lt;a href="https://x.com/Fried_rice"target="_blank" rel="noopener"&gt;Chaofan Shou&lt;/a&gt; descobriu que o código fonte inteiro do Claude Code, a CLI oficial da Anthropic pra coding com IA, estava disponível pra qualquer pessoa no registry público do npm. 512 mil linhas de TypeScript. 1.900 arquivos. Tudo exposto num arquivo de source map de 59.8MB incluído acidentalmente na versão 2.1.88 do pacote &lt;code&gt;@anthropic-ai/claude-code&lt;/code&gt;.&lt;/p&gt;</description><content:encoded><![CDATA[<blockquote>
  <p>Atualizado em 2 de abril de 2026: se você já tinha lido este texto ontem, vale pular direto para a <a href="#update-2026-04-02">nova seção de atualização</a>.</p>

</blockquote>
<p>Hoje de manhã (31 de março de 2026), o pesquisador de segurança <a href="https://x.com/Fried_rice"target="_blank" rel="noopener">Chaofan Shou</a> descobriu que o código fonte inteiro do Claude Code, a CLI oficial da Anthropic pra coding com IA, estava disponível pra qualquer pessoa no registry público do npm. 512 mil linhas de TypeScript. 1.900 arquivos. Tudo exposto num arquivo de source map de 59.8MB incluído acidentalmente na versão 2.1.88 do pacote <code>@anthropic-ai/claude-code</code>.</p>
<p>Em poucas horas o código já estava espelhado no GitHub, analisado por milhares de desenvolvedores, e a Anthropic soltou uma nota dizendo que foi &ldquo;erro humano no empacotamento de release, não uma brecha de segurança&rdquo;. O que é tecnicamente verdade mas ignora que o resultado é o mesmo.</p>
<p><img src="https://raw.githubusercontent.com/kuberwastaken/claude-code/main/public/leak-tweet.png" alt="Tweet anunciando o vazamento"  loading="lazy" /></p>
<p>Eu uso Claude Code todo dia. Alguns dos artigos que você lê aqui eu escrevi com ele. Então resolvi olhar o que tem dentro. Inclusive comecei este texto no próprio Claude Code, mas meu plano Max acabou antes de eu terminar. O resto eu fechei no Codex.</p>
<h2>Como aconteceu o vazamento<span class="hx:absolute hx:-mt-20" id="como-aconteceu-o-vazamento"></span>
    <a href="#como-aconteceu-o-vazamento" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O Claude Code é empacotado com o <a href="https://bun.sh/"target="_blank" rel="noopener">Bun</a>, o runtime JavaScript que a Anthropic adquiriu no final de 2024. Quando você builda com Bun, source maps são gerados por padrão. Esses arquivos <code>.map</code> contêm o código fonte original completo, não só mapeamentos. Cada arquivo, cada comentário, cada constante interna, cada system prompt.</p>
<p>A teoria inicial era que um <a href="https://github.com/oven-sh/bun/issues/28001"target="_blank" rel="noopener">bug conhecido no Bun</a> teria causado o vazamento: mesmo com <code>development: false</code>, source maps continuavam sendo servidos e incluídos nos bundles. Mas o próprio <a href="https://github.com/oven-sh/bun/issues/28001#issuecomment-4164447815"target="_blank" rel="noopener">Jarred Sumner</a>, criador do Bun, desmentiu: &ldquo;This has nothing to do with claude code. This is with Bun&rsquo;s frontend development server. Claude Code is not a frontend app. It is a TUI. It doesn&rsquo;t use Bun.serve() to compile a single-file executable.&rdquo; Ou seja, o bug do Bun afeta o dev server de frontend, não o processo de build que gerou o pacote npm do Claude Code.</p>
<p>O que de fato aconteceu é mais simples: alguém na Anthropic esqueceu de adicionar <code>*.map</code> ao <code>.npmignore</code> ou não configurou o bundler pra pular geração de source maps em builds de produção. E pior: segundo o <a href="https://www.theregister.com/2026/03/31/anthropic_claude_code_source_code/"target="_blank" rel="noopener">The Register</a>, o source map não só apontava pros arquivos originais, como referenciava um ZIP hospedado num bucket Cloudflare R2 da própria Anthropic. O npm serviu feliz pra qualquer pessoa que rodasse <code>npm pack</code>, e o resto virou trabalho de espelho.</p>
<p><img src="https://raw.githubusercontent.com/kuberwastaken/claude-code/main/public/claude-files.png" alt="Arquivos fonte expostos no pacote npm"  loading="lazy" /></p>
<p>A ironia é que o código contém um sistema inteiro chamado &ldquo;Undercover Mode&rdquo; feito especificamente pra evitar que informações internas da Anthropic vazem em commits e PRs. Eles construíram um subsistema pra impedir o AI de revelar codinomes internos, e aí o source map expôs tudo.</p>
<h2>O que tem dentro: as features escondidas<span class="hx:absolute hx:-mt-20" id="o-que-tem-dentro-as-features-escondidas"></span>
    <a href="#o-que-tem-dentro-as-features-escondidas" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O código fonte revela 44 feature flags cobrindo funcionalidades prontas mas ainda não lançadas. Não é vaporware. É código real escondido atrás de flags que compilam pra <code>false</code> nos builds externos. Vou destacar as mais interessantes.</p>
<h3>KAIROS: Claude que nunca para<span class="hx:absolute hx:-mt-20" id="kairos-claude-que-nunca-para"></span>
    <a href="#kairos-claude-que-nunca-para" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Dentro do diretório <code>assistant/</code>, existe um modo chamado KAIROS, um assistente persistente que não espera você digitar. Ele observa, registra e age proativamente sobre coisas que percebe. Mantém arquivos de log diários append-only, recebe prompts <code>&lt;tick&gt;</code> em intervalos regulares pra decidir se deve agir ou ficar quieto, e tem um budget de 15 segundos: qualquer ação proativa que bloquearia o workflow do usuário por mais de 15 segundos é adiada.</p>
<p>Ferramentas exclusivas do KAIROS: <code>SendUserFile</code> (envia arquivos pro usuário), <code>PushNotification</code> (notificações push), <code>SubscribePR</code> (monitora pull requests). Nada disso existe no build público.</p>
<h3>BUDDY: um Tamagotchi no terminal<span class="hx:absolute hx:-mt-20" id="buddy-um-tamagotchi-no-terminal"></span>
    <a href="#buddy-um-tamagotchi-no-terminal" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Não estou inventando. O Claude Code tem um sistema completo de pet companion estilo Tamagotchi chamado &ldquo;Buddy&rdquo;. Um sistema gacha determinístico com 18 espécies, raridade, variantes shiny, stats gerados proceduralmente, e uma &ldquo;alma&rdquo; escrita pelo Claude no primeiro hatch.</p>
<p>A espécie é determinada por um PRNG Mulberry32 seedado pelo hash do userId. Mesmo usuário sempre recebe o mesmo buddy. Tem 5 stats (DEBUGGING, PATIENCE, CHAOS, WISDOM, SNARK), 6 estilos de olhos, 8 opções de chapéu, e sprites renderizados como ASCII art de 5 linhas com animações. O código referencia 1-7 de abril de 2026 como janela de teaser, com lançamento completo pra maio de 2026.</p>
<h3>ULTRAPLAN: 30 minutos de planejamento remoto<span class="hx:absolute hx:-mt-20" id="ultraplan-30-minutos-de-planejamento-remoto"></span>
    <a href="#ultraplan-30-minutos-de-planejamento-remoto" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>O ULTRAPLAN offloads tarefas complexas de planejamento pra uma sessão remota rodando Opus 4.6, dá até 30 minutos pra pensar, e permite que você aprove o resultado pelo browser. O terminal mostra polling a cada 3 segundos, e quando aprovado, um valor sentinela <code>__ULTRAPLAN_TELEPORT_LOCAL__</code> &ldquo;teletransporta&rdquo; o resultado de volta pro terminal local.</p>
<h3>Multi-Agent: &ldquo;Coordinator Mode&rdquo;<span class="hx:absolute hx:-mt-20" id="multi-agent-coordinator-mode"></span>
    <a href="#multi-agent-coordinator-mode" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>O sistema de orquestração multi-agente no diretório <code>coordinator/</code> transforma o Claude Code de um agente único num coordenador que spawna, dirige e gerencia múltiplos workers em paralelo. Research em paralelo, síntese pelo coordenador, implementação pelos workers, verificação pelos workers. O prompt ensina paralelismo explicitamente e proíbe delegação preguiçosa: &ldquo;Do NOT say &lsquo;based on your findings&rsquo; - read the actual findings and specify exactly what to do.&rdquo;</p>
<p>E tem mais. O leak também mostra teammates in-process com <code>AsyncLocalStorage</code> pra isolar contexto, workers em processos separados via tmux/iTerm2 panes, sincronização de memória entre agentes, e flags já prontas para <code>BRIDGE_MODE</code>, <code>VOICE_MODE</code>, <code>WORKFLOW_SCRIPTS</code>, <code>AFK mode</code>, <code>advisor-tool</code> e <code>history snipping</code>. Isso não garante lançamento, mas sugere um roadmap bem mais adiantado do que a versão pública deixa transparecer.</p>
<h2>A arquitetura de memória<span class="hx:absolute hx:-mt-20" id="a-arquitetura-de-memória"></span>
    <a href="#a-arquitetura-de-mem%c3%b3ria" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O sistema de memória me chamou atenção. Não é um &ldquo;guarde tudo e recupere&rdquo;. É uma arquitetura de três camadas:</p>
<p><a href="https://x.com/himanshustwts/status/2038924027411222533"target="_blank" rel="noopener"><img src="https://new-uploads-akitaonrails.s3.amazonaws.com/2026/03/31/claude-code-memory-architecture.jpg" alt="Resumo da arquitetura de memória do Claude Code"  loading="lazy" /></a></p>
<p>O <code>MEMORY.md</code> é um índice leve de ponteiros (~150 caracteres por linha) que fica permanentemente carregado no contexto. Não guarda dados, guarda localizações. O conhecimento real está distribuído em &ldquo;topic files&rdquo; buscados sob demanda. Transcrições brutas nunca são lidas inteiras de volta no contexto, apenas pesquisadas com grep pra identificadores específicos.</p>
<p>E isso vem com uma disciplina importante: o sistema escreve primeiro no arquivo de tópico e só depois atualiza o índice. O <code>MEMORY.md</code> não vira depósito de fatos. Continua sendo só mapa. Se você deixa o índice virar storage, ele polui o contexto permanente e degrada o sistema inteiro.</p>
<p>O sistema &ldquo;Dream&rdquo; (<code>services/autoDream/</code>) é um motor de consolidação de memória que roda como subagent em background. O nome é intencional. É o Claude sonhando.</p>
<p>O sonho tem um sistema de trigger com três portas: 24 horas desde o último sonho, pelo menos 5 sessões desde o último sonho, e aquisição de um lock de consolidação (impede sonhos concorrentes). As três precisam passar.</p>
<p>Quando roda, segue quatro fases: Orient (ls no diretório de memória, lê o índice), Gather (busca sinais novos em logs, memórias desatualizadas, transcrições), Consolidate (escreve ou atualiza topic files, converte datas relativas pra absolutas, deleta fatos contraditos), e Prune (mantém o índice abaixo de 200 linhas e ~25KB).</p>
<p>Os tipos de memória são quatro: <code>user</code> (perfil do usuário), <code>feedback</code> (correções e confirmações), <code>project</code> (contexto sobre o trabalho em andamento), <code>reference</code> (ponteiros pra sistemas externos). A taxonomia exclui explicitamente coisas deriváveis do código (patterns, arquitetura, git history, file structure).</p>
<p>O subagent de sonho recebe bash read-only. Pode olhar o projeto mas não pode modificar nada. É puramente uma passada de consolidação.</p>
<p>E tem outro detalhe que eu achei elegante: memória não é tratada como verdade. É tratada como pista. O sistema assume que memória pode estar velha, errada ou contraditória, então o modelo ainda precisa verificar antes de confiar. Isso é o oposto da fantasia de &ldquo;joga tudo num banco vetorial e deixa a mágica acontecer&rdquo;.</p>
<h2>O &ldquo;Undercover Mode&rdquo;<span class="hx:absolute hx:-mt-20" id="o-undercover-mode"></span>
    <a href="#o-undercover-mode" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Funcionários da Anthropic (identificados por <code>USER_TYPE === 'ant'</code>) usam o Claude Code em repositórios públicos e open source. O Undercover Mode (<code>utils/undercover.ts</code>) impede que o AI revele informações internas acidentalmente em commits e PRs.</p>
<p>Quando ativo, injeta no system prompt:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>## UNDERCOVER MODE - CRITICAL

You are operating UNDERCOVER in a PUBLIC/OPEN-SOURCE repository. Your commit
messages, PR titles, and PR bodies MUST NOT contain ANY Anthropic-internal
information. Do not blow your cover.

NEVER include in commit messages or PR descriptions:
- Internal model codenames (animal names like Capybara, Tengu, etc.)
- Unreleased model version numbers (e.g., opus-4-7, sonnet-4-8)
- Internal repo or project names
- Internal tooling, Slack channels, or short links
- The phrase &#34;Claude Code&#34; or any mention that you are an AI
- Co-Authored-By lines or any other attribution</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Não tem como desligar. Se o sistema não tem certeza que está num repositório interno, fica em modo undercover. Isso confirma uma coisa meio desconfortável: a Anthropic usa Claude Code pra contribuir em open source, e o agente é instruído a esconder que é IA.</p>
<p>Os codinomes internos são nomes de animais: Tengu (codinome do projeto Claude Code), Fennec (Opus), Capybara, Numbat (em teste). O &ldquo;Fast Mode&rdquo; é internamente chamado de &ldquo;Penguin Mode&rdquo; com endpoint <code>claude_code_penguin_mode</code> e kill-switch <code>tengu_penguins_off</code>.</p>
<h2>As partes mais paranoicas<span class="hx:absolute hx:-mt-20" id="as-partes-mais-paranoicas"></span>
    <a href="#as-partes-mais-paranoicas" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Tem uma parte da análise que eu quase deixei passar porque estava olhando mais pras features escondidas. Mas talvez o mais revelador sobre a mentalidade da Anthropic esteja nos mecanismos de defesa contra cópia e abuso.</p>
<p>Segundo a análise do <a href="https://alex000kim.com/posts/2026-03-31-claude-code-source-leak/"target="_blank" rel="noopener">Alex Kim</a>, existe um modo de anti-distillation que pode pedir ao servidor pra injetar ferramentas falsas no prompt do sistema. A ideia é envenenar tráfego gravado por quem estiver tentando destilar o comportamento do Claude Code pra treinar concorrente. Tem também um segundo mecanismo de sumarização de texto de conectores, assinado criptograficamente, pra que parte do tráfego observável não corresponda ao raciocínio bruto original. Não é proteção perfeita. É mais uma camada de atrito. Mas mostra que a empresa está pensando explicitamente em cópia por observação, não só em segurança tradicional.</p>
<p>E tem a parte mais agressiva: client attestation. Cada request inclui um header de billing com um placeholder <code>cch=00000</code>, e o runtime nativo do Bun substitui isso por um hash calculado abaixo da camada JavaScript. Em outras palavras, não basta parecer Claude Code. O binário tenta provar que é Claude Code. Isso ajuda a explicar por que a briga com ferramentas terceiras como OpenCode ficou tão sensível: não era só questão comercial ou jurídica. Tinha enforcement técnico embutido no transporte.</p>
<h3>Atualização: o DRM morreu em menos de 24 horas<span class="hx:absolute hx:-mt-20" id="atualização-o-drm-morreu-em-menos-de-24-horas"></span>
    <a href="#atualiza%c3%a7%c3%a3o-o-drm-morreu-em-menos-de-24-horas" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Lembram que eu mencionei o client attestation como &ldquo;a parte mais agressiva&rdquo;? Pois é. Durou menos de um dia.</p>
<p>Pra entender o contexto: a Anthropic vinha travando uma guerra contra ferramentas terceiras desde janeiro de 2026. Primeiro veio o bloqueio server-side de tokens OAuth vindos de clientes não-oficiais. Depois, em março, o maintainer do <a href="https://github.com/anomalyco/opencode"target="_blank" rel="noopener">OpenCode</a> mergeou um <a href="https://github.com/anomalyco/opencode/issues/7456"target="_blank" rel="noopener">PR</a> removendo toda autenticação Claude do projeto. O commit message tinha duas palavras: &ldquo;anthropic legal requests.&rdquo; O <a href="https://www.theregister.com/2026/02/20/anthropic_clarifies_ban_third_party_claude_access/"target="_blank" rel="noopener">The Register reportou</a> que a Anthropic atualizou seus termos de serviço pra deixar explícito que tokens OAuth de assinaturas Pro/Max só podem ser usados no Claude Code oficial e no Claude.ai. Quem pagava $100-200/mês pelo Max e queria usar a ferramenta de sua escolha ficou na mão.</p>
<p>O mecanismo técnico por trás do bloqueio era justamente o <code>cch=</code>. Com o código vazado dá pra ver que o sistema tem duas partes. A primeira é um sufixo de versão: o campo <code>cc_version</code> inclui 3 caracteres hex derivados da primeira mensagem do usuário via SHA-256, usando um salt de 12 caracteres embutido no JavaScript. A segunda é o body hash propriamente dito: o corpo inteiro do request (mensagens, ferramentas, metadata, modelo, config de thinking, tudo) é serializado como JSON compacto com o placeholder <code>cch=00000</code>, e então hasheado com <a href="https://github.com/Cyan4973/xxHash"target="_blank" rel="noopener">xxHash64</a> usando um seed fixo. O resultado é mascarado com <code>0xFFFFF</code> (20 bits) e formatado como 5 caracteres hex lowercase. O placeholder é substituído pelo hash calculado antes do request sair do processo.</p>
<p>O detalhe que faz a diferença: essa substituição acontece dentro do runtime nativo do Bun, escrito em Zig, abaixo da camada JavaScript. O Bun literalmente muta a string JavaScript in-place, sobrescrevendo os bytes <code>00000</code> no buffer da string com o hash computado. Se você rodasse o mesmo bundle em Node ou num Bun stock, o placeholder iria pro servidor como está e o request seria rejeitado.</p>
<p>E aí veio o vazamento. Com o source code exposto, o <a href="https://x.com/StraughterG/status/2039344027556798476"target="_blank" rel="noopener">@StraughterG</a> (Jay Guthrie) anunciou na noite do mesmo dia: &ldquo;Yesterday I said Anthropic&rsquo;s compiled Zig cch= hash was banning 3rd-party Claude clients. Tonight, the DRM is dead. We extracted the algorithm from the binary. It&rsquo;s not advanced cryptography. It&rsquo;s a static xxHash64 seed.&rdquo;</p>
<p>O seed é <code>0x6E52736AC806831E</code>. O <a href="https://a10k.co/b/reverse-engineering-claude-code-cch.html"target="_blank" rel="noopener">algoritmo completo</a>, como explicou numa sequência de tweets, cabe em poucas linhas de TypeScript:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">xxhash</span> <span class="kr">from</span> <span class="s2">&#34;xxhash-wasm&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="p">{</span> <span class="nx">h64Raw</span> <span class="p">}</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">xxhash</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">body</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">request</span><span class="p">);</span> <span class="c1">// com cch=00000 no placeholder
</span></span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">hash</span> <span class="o">=</span> <span class="nx">h64Raw</span><span class="p">(</span><span class="k">new</span> <span class="nx">TextEncoder</span><span class="p">().</span><span class="nx">encode</span><span class="p">(</span><span class="nx">body</span><span class="p">),</span> <span class="mh">0x6E52736AC</span><span class="nx">n</span> <span class="o">|</span> <span class="p">(</span><span class="mh">0x806831E</span><span class="nx">n</span> <span class="o">&lt;&lt;</span> <span class="mi">32</span><span class="nx">n</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">cch</span> <span class="o">=</span> <span class="p">(</span><span class="nx">hash</span> <span class="o">&amp;</span> <span class="mh">0xFFFFF</span><span class="nx">n</span><span class="p">).</span><span class="nx">toString</span><span class="p">(</span><span class="mi">16</span><span class="p">).</span><span class="nx">padStart</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="s2">&#34;0&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="c1">// substituir cch=00000 por cch={valor calculado}
</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>O <a href="https://x.com/paoloanzn/status/2039348588741087341"target="_blank" rel="noopener">@paoloanzn</a> celebrou: &ldquo;we cracked it. the cch= signing system in claude code is fully reverse engineered.&rdquo; E já colocou o bypass no <a href="https://github.com/paoloanzn/free-code"target="_blank" rel="noopener">free-code</a>, um fork do Claude Code com telemetria removida, guardrails de system prompt stripados, e todas as 54 feature flags experimentais desbloqueadas.</p>
<p><a href="https://github.com/paoloanzn/free-code"target="_blank" rel="noopener"><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/01/free-code-screenshot.png" alt="Screenshot do free-code rodando com features experimentais"  loading="lazy" /></a></p>
<p>O ponto técnico que importa: xxHash64 não é criptografia. É um hash de checksum projetado pra velocidade, não pra segurança. O seed é estático, embutido no binário. Muda a cada versão do Claude Code, mas dentro de uma versão é o mesmo pra todo mundo. A &ldquo;segurança&rdquo; dependia inteiramente de ninguém conseguir extrair o seed do binário Zig compilado. Com o source code vazado, essa obscuridade evaporou em horas.</p>
<p>Agora qualquer client terceiro — OpenCode, Claw-Code, o que for — pode interceptar o <code>fetch()</code>, hashear o body com o seed correto, e passar pela validação do servidor como se fosse o Claude Code oficial. A barreira que a Anthropic construiu pra proteger seu modelo de negócio de $2.5 bilhões de ARR era, no fim das contas, security by obscurity num hash não-criptográfico.</p>
<p>O terceiro detalhe é pequeno mas diz muito sobre produto real em produção: o sistema detecta frustração de usuário com regex. Sim, regex. Palavrão, insulto, &ldquo;this sucks&rdquo;, esse tipo de coisa. É engraçado ver uma empresa de LLM fazendo sentiment analysis na base do <code>wtf|ffs|shit</code>, mas também é o tipo de solução pragmática que alguém coloca quando precisa de resposta barata e imediata, não de elegância conceitual.</p>
<h2>O que o código revela sobre como você usa o Claude Code<span class="hx:absolute hx:-mt-20" id="o-que-o-código-revela-sobre-como-você-usa-o-claude-code"></span>
    <a href="#o-que-o-c%c3%b3digo-revela-sobre-como-voc%c3%aa-usa-o-claude-code" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O <a href="https://x.com/iamfakeguru/status/2038965567269249484"target="_blank" rel="noopener">@iamfakeguru</a> compilou uma thread com sete achados técnicos do código que qualquer usuário deveria saber:</p>
<p>O Claude Code tem um cap de 2.000 linhas por leitura de arquivo. Quando você pede pra ler um arquivo maior, ele trunca silenciosamente. Resultados de ferramentas são cortados em 50.000 caracteres. O sistema de compressão de context window descarta mensagens antigas pra caber mais contexto novo. E existe uma diferença entre o nível de acesso de funcionários Anthropic (<code>USER_TYPE === 'ant'</code>) e o acesso público: ferramentas internas como <code>ConfigTool</code> e <code>TungstenTool</code> são invisíveis no build externo.</p>
<p>A descoberta mais útil da thread é como funcionários Anthropic contornam as limitações que os usuários externos enfrentam. O código revela que <code>USER_TYPE === 'ant'</code> desbloqueia ferramentas internas, beta headers exclusivos (<code>cli-internal-2026-02-09</code>), acesso a staging (<code>claude-ai.staging.ant.dev</code>), e um <code>ConfigTool</code> que permite alterar configurações em runtime. Builds externos compilam tudo isso pra <code>false</code> via dead code elimination.</p>
<p>Mas o ponto que interessa é: o CLAUDE.md que você coloca na raiz do seu projeto é lido inteiro pelo Claude Code e injetado no system prompt. É literalmente o lugar onde você controla como o agente se comporta. O <a href="https://x.com/iamfakeguru/status/2038965567269249484"target="_blank" rel="noopener">@iamfakeguru</a> publicou um override completo com 10 regras mecânicas, e depois subiu o arquivo inteiro num repositório separado: <a href="https://github.com/iamfakeguru/claude-md"target="_blank" rel="noopener">iamfakeguru/claude-md</a>.</p>
<p><a href="https://github.com/iamfakeguru/claude-md/blob/main/CLAUDE.md"target="_blank" rel="noopener"><img src="https://new-uploads-akitaonrails.s3.amazonaws.com/2026/03/31/claude-md-production-grade-agent-directives.png" alt="Screenshot do CLAUDE.md publicado pelo fakeguru"  loading="lazy" /></a></p>
<p>Eu não vou colar o bloco inteiro aqui. O que importa é o conteúdo: ele força verificação pós-edição (<code>tsc</code> e <code>eslint</code> antes de declarar sucesso), impõe releitura de arquivos antes de editar, exige leitura em chunks para arquivos grandes, assume truncamento silencioso de resultados muito longos, e manda quebrar trabalho maior em fases ou subagentes paralelos. Em outras palavras: ele transforma em regra explícita tudo que os usuários externos estavam apanhando para descobrir empiricamente.</p>
<p>Essas não são instruções mágicas. São guardrails. A diferença é que agora sabemos quais limites o sistema realmente tem e podemos escrever um CLAUDE.md que trabalha a favor deles, não contra eles.</p>
<h2>Bugs de cache que custam caro<span class="hx:absolute hx:-mt-20" id="bugs-de-cache-que-custam-caro"></span>
    <a href="#bugs-de-cache-que-custam-caro" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O <a href="https://x.com/altryne/status/2038676458026189225"target="_blank" rel="noopener">@altryne</a> (Alex Volkov) reportou bugs de invalidação de cache que fazem tokens não-cacheados custarem 10-20x mais que os cacheados. São dois bugs: um de substituição de string no Bun que afeta a CLI standalone (workaround: usar <code>npx @anthropic-ai/claude-code</code> em vez do binário instalado), e outro na flag <code>--resume</code> que quebra o cache sem workaround conhecido. Mais de 500 usuários reportaram problemas similares de exaustão de quota. Se você sentiu que o Claude Code estava gastando tokens mais rápido que o esperado nos últimos dias, provavelmente não era impressão.</p>
<h2>&ldquo;Spaghetti de staff engineer&rdquo;<span class="hx:absolute hx:-mt-20" id="spaghetti-de-staff-engineer"></span>
    <a href="#spaghetti-de-staff-engineer" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A análise do código revelou problemas reais. Um comentário no próprio fonte admite: &ldquo;1.279 sessões tiveram 50+ falhas consecutivas (até 3.272) numa única sessão, desperdiçando ~250K chamadas de API por dia globalmente.&rdquo; O fix foram três linhas: limitar falhas consecutivas a três antes de desabilitar compactação.</p>
<p>O arquivo <code>print.ts</code> tem 5.594 linhas com uma única função de 3.167 linhas contendo doze níveis de nesting. O <code>main.tsx</code> tem 803.924 bytes num único arquivo. O <code>interactiveHelpers.tsx</code> tem 57.424 bytes. São arquivos que nenhum humano consegue revisar com confiança.</p>
<p>A reação mais viral veio do <a href="https://x.com/thekitze/status/2038956521942577557"target="_blank" rel="noopener">@thekitze</a>: ele pediu pro GPT-5.4 avaliar o codebase e a nota foi 6.5/10. A descrição: &ldquo;This is not junior spaghetti. This is staff-engineer spaghetti: performance-aware, feature-flagged, telemetry-instrumented, surgically optimized spaghetti.&rdquo; Ou seja, não é código ruim de inexperiência. É código ruim de pressão pra entregar rápido sem pagar o custo de organizar depois.</p>
<p>O <a href="https://x.com/thekitze/status/2038986445839622405"target="_blank" rel="noopener">@thekitze</a> também elaborou em outra thread sobre como o código evidencia falta de práticas básicas de engenharia. E é aqui que eu me sinto vindicado.</p>
<p>Eu venho repetindo em vários posts sobre <a href="/tags/vibe-coding/">vibe coding</a> que velocidade sem disciplina produz exatamente isso. Os princípios que eu defendo, incrementos pequenos, testes a cada passo, revisão antes de commitar, refactoring contínuo, CI que rejeita complexidade ciclomática alta, são os mesmos princípios do Extreme Programming que funcionam desde os anos 2000. A Anthropic aparentemente não seguiu nenhum deles no próprio produto.</p>
<p>Uma função de 3.167 linhas com 12 níveis de nesting não é algo que aparece da noite pro dia. É acúmulo. É o resultado de dezenas de adições onde ninguém parou pra refatorar porque &ldquo;tá funcionando, não mexe&rdquo;. É o anti-pattern clássico de vibe coding sem disciplina: gerar código com IA, ver que compila, fazer commit, repetir. Sem review rigoroso. Sem limites de complexidade no CI. Sem a regra básica de que se uma função passa de 50 linhas, ela precisa ser quebrada.</p>
<p>A ironia é que a Anthropic vende a ferramenta de vibe coding mais popular do mercado e não pratica o que eu chamo de vibe coding responsável. O Claude Code vale $2.5 bilhões de ARR. O código que gera esse faturamento tem qualidade 6.5/10.</p>
<h2>A questão do &ldquo;clean room&rdquo;<span class="hx:absolute hx:-mt-20" id="a-questão-do-clean-room"></span>
    <a href="#a-quest%c3%a3o-do-clean-room" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Com o código fonte inteiro público, surge uma implicação legal e competitiva séria. E aqui eu acho que muita gente começou a usar o termo &ldquo;clean room&rdquo; com uma leveza que não combina com o assunto.</p>
<p>Clean room de verdade não é só &ldquo;reescrevi em outra linguagem&rdquo; nem &ldquo;não dei copy and paste&rdquo;. O modelo clássico é bem mais chato: um grupo estuda o original e produz uma especificação funcional; outro grupo, isolado, implementa a partir dessa especificação sem ver o código original. A ideia é justamente reduzir o risco de contaminação.</p>
<p>O <a href="https://x.com/braelyn_ai/status/2039025584626397491"target="_blank" rel="noopener">@braelyn_ai</a> levantou outro ponto interessante: com ferramentas generativas, alguém poderia tentar um &ldquo;clean room rebuild&rdquo; usando testes, comportamento observável e documentação, sem reaproveitar a implementação original. Em tese, faz sentido. Na prática, o que aparece no calor do vazamento costuma ficar numa zona bem mais cinzenta.</p>
<p>O caso do <a href="https://github.com/ultraworkers/claw-code"target="_blank" rel="noopener">Claw-Code</a> ilustra isso bem. O projeto se apresenta como rewrite independente e já migrou o foco para Python e Rust, mas o próprio README admite estudo direto do código exposto e fala até em parity audit contra archive local. Então eu não chamaria isso de clean room clássico no sentido mais rigoroso. Eu chamaria de reimplementação inspirada, com tentativa deliberada de se afastar do snapshot vazado.</p>
<p>Isso não quer dizer que toda reimplementação está condenada. Copyright de software não protege ideia abstrata, fluxo genérico de ferramenta, arquitetura em alto nível ou &ldquo;uma CLI que faz X&rdquo;. Protege expressão concreta. Mas justamente por isso a disciplina importa. Quanto mais um projeto quiser sustentar independência, menos ele deveria depender do material vazado como benchmark direto.</p>
<p>Tem um detalhe mais pragmático aí: as cópias literais do source vazado provavelmente vão sumir rápido quando os primeiros DMCA começarem a chegar. Mirror cai fácil. É por isso que uma reimplementação interessa mais do que um espelho bruto. Isso não apaga a discussão jurídica, mas muda bastante o tipo de briga e a chance de continuar no ar.</p>
<p>Foi mais ou menos o que eu mesmo fiz quando <a href="/2026/03/16/reescrevi-o-openclaw-em-rust-funcionou-frankclaw/">reescrevi o OpenClaw em Rust</a>. O ponto não era copiar linha por linha. Era entender o comportamento e reescrever a peça inteira com código meu.</p>
<p>O site satírico <a href="https://malus.sh/"target="_blank" rel="noopener">malus.sh</a> apareceu hoje oferecendo &ldquo;Clean Room as a Service&rdquo; com o tagline &ldquo;Robot-Reconstructed, Zero Attribution&rdquo;. A piada: robôs de IA recriam projetos open source eliminando obrigações de atribuição, com garantias tipo &ldquo;This has never happened because it legally cannot happen. Trust us.&rdquo; e indenização via subsidiária offshore numa jurisdição que não reconhece copyright de software. É sátira, mas é sátira que descreve o que alguém vai tentar fazer de verdade.</p>
<p><a id="update-2026-04-02"></a></p>
<h2>Atualização em 2 de abril de 2026<span class="hx:absolute hx:-mt-20" id="atualização-em-2-de-abril-de-2026"></span>
    <a href="#atualiza%c3%a7%c3%a3o-em-2-de-abril-de-2026" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Como o texto acima abre no calor do dia 31, vale registrar o que aconteceu logo depois. Resolvi adicionar esta atualização depois de ler <a href="https://x.com/k1rallik/status/2039686500619534818"target="_blank" rel="noopener">este tweet do @k1rallik</a>, que resume bem o clima do pós-vazamento, mas mistura fatos confirmáveis com um pouco de épica demais.</p>
<p>Primeiro: a parte do DMCA ficou mais bagunçada do que parecia. A própria notice publicada no repositório <code>github/dmca</code> diz que o GitHub processou a remoção contra a rede inteira de <strong>8.1 mil repositórios</strong>, porque a notificação afirmava que &ldquo;all or most of the forks&rdquo; eram infringing na mesma medida que o repositório principal. No dia seguinte, a Anthropic publicou uma <strong>retratação parcial</strong>: pediu reinstalação de todos os repositórios removidos, exceto o <code>nirholas/claude-code</code> e <strong>96 forks listados individualmente</strong>. Então a tese de que a tentativa inicial foi ampla demais está certa. O retrato final, porém, não é &ldquo;8.100 repositórios ficaram derrubados&rdquo;. O que houve foi um recuo formal depois da remoção em massa.</p>
<p>Segundo: o projeto <a href="https://github.com/ultraworkers/claw-code"target="_blank" rel="noopener">Claw-Code</a> realmente explodiu. Na hora em que atualizei este post, o GitHub já mostrava <strong>142.829 stars</strong> e <strong>101.510 forks</strong>. Isso por si só já basta pra dizer que a história saiu da categoria &ldquo;fork curioso do vazamento&rdquo; e entrou na categoria &ldquo;efeito colateral competitivo real&rdquo;. O tweet viral que circulou hoje acerta no tamanho do estrago, mas exagera em alguns detalhes. O próprio README do projeto se autodescreve como &ldquo;the fastest repo in history to surpass 50K stars&rdquo; e diz que a marca veio em duas horas. Eu não consegui confirmar esse marco histórico de forma independente, então prefiro tratar isso como alegação do próprio projeto, não como fato fechado.</p>
<p>Terceiro: a parte do Rust também precisa de nuance. Sim, já existe workspace em Rust no branch principal e o <code>Cargo.toml</code> está com versão <code>0.1.0</code>. Mas eu não encontrei release pública no GitHub para sustentar a frase &ldquo;já saiu release 0.1.0&rdquo; como um lançamento formal. O que dá pra afirmar com segurança é outra coisa: o projeto já tem base em Python, já tem workspace em Rust, e já virou alvo de atenção suficiente para continuar existindo mesmo sem o mirror literal do código vazado.</p>
<h2>O que a Anthropic deveria ter feito<span class="hx:absolute hx:-mt-20" id="o-que-a-anthropic-deveria-ter-feito"></span>
    <a href="#o-que-a-anthropic-deveria-ter-feito" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A Anthropic respondeu rápido. Tirou o pacote comprometido, soltou uma nota pública, e limpou o que podia. Mas o dano já estava feito. O código foi espelhado antes da remoção. Mirrors no GitHub, análises em blogs, threads no X/Twitter. Não tem como des-publicar algo na internet.</p>
<p>O que me incomoda não é o vazamento em si. Bugs acontecem. O que me incomoda é que isso era evitável com práticas básicas de engenharia:</p>
<ol>
<li>Adicionar <code>*.map</code> ao <code>.npmignore</code>. Uma linha.</li>
<li>Configurar o bundler pra não gerar source maps em builds de produção. Uma flag.</li>
<li>Ter um CI check que rejeita publicação se o pacote contém <code>.map</code>. Um script de 5 linhas.</li>
<li>Ter um pipeline de release com review manual antes de publicar no npm. Processo, não código.</li>
</ol>
<p>Nenhuma dessas é difícil. Todas são o tipo de coisa que se perde quando você está movendo rápido demais e não tem disciplina no processo de release. É exatamente o que eu prego como <a href="/tags/vibe-coding/">vibe coding disciplinado</a>: mover rápido não significa pular os guardrails.</p>
<p>E a segunda falha: a qualidade do código em si. 512 mil linhas com funções de 3 mil linhas e 12 níveis de nesting não é engenharia. É acúmulo. É o que acontece quando você gera código com IA sem review rigoroso, sem refactoring contínuo, sem CI que rejeita complexidade ciclomática alta. A ironia de ser justamente a empresa que vende a ferramenta de vibe coding mais popular do mundo não passa despercebida.</p>
<h2>Fontes<span class="hx:absolute hx:-mt-20" id="fontes"></span>
    <a href="#fontes" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><ul>
<li><a href="https://github.com/Kuberwastaken/claude-code"target="_blank" rel="noopener">Kuberwastaken/claude-code - Breakdown completo do código vazado</a></li>
<li><a href="https://alex000kim.com/posts/2026-03-31-claude-code-source-leak/"target="_blank" rel="noopener">Alex Kim - Claude Code Source Leak: fake tools, frustration regexes, undercover mode</a></li>
<li><a href="https://venturebeat.com/technology/claude-codes-source-code-appears-to-have-leaked-heres-what-we-know/"target="_blank" rel="noopener">VentureBeat - Claude Code&rsquo;s source code appears to have leaked</a></li>
<li><a href="https://www.theregister.com/2026/03/31/anthropic_claude_code_source_code/"target="_blank" rel="noopener">The Register - Anthropic accidentally exposes Claude Code source code</a></li>
<li><a href="https://fortune.com/2026/03/31/anthropic-source-code-claude-code-data-leak-second-security-lapse-days-after-accidentally-revealing-mythos/"target="_blank" rel="noopener">Fortune - Anthropic leaks its own AI coding tool&rsquo;s source code</a></li>
<li><a href="https://cybernews.com/security/anthropic-claude-code-source-leak/"target="_blank" rel="noopener">Cybernews - Full source code for Anthropic&rsquo;s Claude Code leaks</a></li>
<li><a href="https://gizmodo.com/source-code-for-anthropics-claude-code-leaks-at-the-exact-wrong-time-2000740379"target="_blank" rel="noopener">Gizmodo - Source Code for Anthropic&rsquo;s Claude Code Leaks at the Exact Wrong Time</a></li>
<li><a href="https://www.anthropic.com/news/anthropic-acquires-bun-as-claude-code-reaches-usd1b-milestone?s=33"target="_blank" rel="noopener">Anthropic - Anthropic acquires Bun as Claude Code reaches $1B milestone</a></li>
<li><a href="https://github.com/oven-sh/bun/issues/28001"target="_blank" rel="noopener">Bun Issue #28001 - Source maps incorrectly served in production</a></li>
<li><a href="https://news.ycombinator.com/item?id=43909409"target="_blank" rel="noopener">Hacker News - Claude&rsquo;s system prompt is over 24k tokens with tools</a></li>
<li><a href="https://malus.sh/"target="_blank" rel="noopener">malus.sh - Clean Room as a Service (sátira)</a></li>
<li><a href="https://x.com/iamfakeguru/status/2038965567269249484"target="_blank" rel="noopener">@iamfakeguru - Thread com 7 achados técnicos do código</a></li>
<li><a href="https://x.com/altryne/status/2038676458026189225"target="_blank" rel="noopener">@altryne - Bugs de cache que custam 10-20x mais</a></li>
<li><a href="https://x.com/thekitze/status/2038956521942577557"target="_blank" rel="noopener">@thekitze - &ldquo;Staff-engineer spaghetti&rdquo; 6.5/10</a></li>
<li><a href="https://x.com/braelyn_ai/status/2039025584626397491"target="_blank" rel="noopener">@braelyn_ai - Clean room e implicações legais</a></li>
<li><a href="https://github.com/github/dmca/blob/master/2026/03/2026-03-31-anthropic.md"target="_blank" rel="noopener">GitHub DMCA - Anthropic takedown notice processada contra a rede de 8.1K repositórios</a></li>
<li><a href="https://github.com/github/dmca/blob/master/2026/04/2026-04-01-anthropic-retraction.md"target="_blank" rel="noopener">GitHub DMCA - Retratação parcial da Anthropic no dia seguinte</a></li>
<li><a href="https://github.com/ultraworkers/claw-code"target="_blank" rel="noopener">ultraworkers/claw-code - Reimplementação em Python e Rust que virou o principal projeto pós-vazamento</a></li>
<li><a href="https://x.com/mem0ai/status/2039041449854124229"target="_blank" rel="noopener">@mem0ai - Análise da arquitetura de memória</a></li>
<li><a href="https://x.com/himanshustwts/status/2038924027411222533"target="_blank" rel="noopener">@himanshustwts - Resumo da arquitetura de memória</a></li>
<li><a href="https://github.com/iamfakeguru/claude-md"target="_blank" rel="noopener">iamfakeguru/claude-md - Override publicado com o CLAUDE.md completo</a></li>
<li><a href="https://x.com/StraughterG/status/2039344027556798476"target="_blank" rel="noopener">@StraughterG - &ldquo;the DRM is dead&rdquo; - reverse engineering do cch= hash</a></li>
<li><a href="https://x.com/StraughterG/status/2039344035555344550"target="_blank" rel="noopener">@StraughterG - Seed xxHash64 e código TypeScript do bypass</a></li>
<li><a href="https://x.com/paoloanzn/status/2039348588741087341"target="_blank" rel="noopener">@paoloanzn - &ldquo;we cracked it&rdquo; - confirmação do reverse engineering</a></li>
<li><a href="https://github.com/paoloanzn/free-code"target="_blank" rel="noopener">paoloanzn/free-code - Fork do Claude Code com telemetria removida e features desbloqueadas</a></li>
<li><a href="https://a10k.co/b/reverse-engineering-claude-code-cch.html"target="_blank" rel="noopener">a10k.co - What&rsquo;s cch? Reverse Engineering Claude Code&rsquo;s Request Signing</a></li>
<li><a href="https://www.theregister.com/2026/02/20/anthropic_clarifies_ban_third_party_claude_access/"target="_blank" rel="noopener">The Register - Anthropic clarifies ban on third-party tool access to Claude</a></li>
<li><a href="https://github.com/anomalyco/opencode/issues/7456"target="_blank" rel="noopener">OpenCode Issue #7456 - Claude Code API credentials removal</a></li>
</ul>
]]></content:encoded><category>agentes-de-codigo</category><category>seguranca</category><category>engenharia-de-software</category></item><item><title>Software Nunca Está 'Pronto' — 4 Projetos, a Vida Pós-Deploy, e Por Que One-Shot Prompt É Mito</title><link>https://akitaonrails.github.io/2026/03/01/software-nunca-esta-pronto-4-projetos-a-vida-pos-deploy-e-por-que-one-shot-prompt-e-mito/</link><guid isPermaLink="true">https://akitaonrails.github.io/2026/03/01/software-nunca-esta-pronto-4-projetos-a-vida-pos-deploy-e-por-que-one-shot-prompt-e-mito/</guid><pubDate>Sun, 01 Mar 2026 12:00:00 -0300</pubDate><description>&lt;p&gt;E não deixe de assinar minha newsletter &lt;a href="https://themakitachronicles.com/"target="_blank" rel="noopener"&gt;The M.Akita Chronicles&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;&amp;ndash;&lt;/p&gt;
&lt;p&gt;Publiquei o &amp;ldquo;post final&amp;rdquo; da série &lt;a href="https://akitaonrails.github.io/2026/02/20/do-zero-a-pos-producao-em-1-semana-como-usar-ia-em-projetos-de-verdade-bastidores-do-the-m-akita-chronicles/"&gt;Bastidores do The M.Akita Chronicles&lt;/a&gt; há 10 dias. 274 commits, 1.323 testes, deploy em produção. Escrevi as lições, fiz a conclusão, coloquei a citação no final. Done.&lt;/p&gt;
&lt;p&gt;125 commits de pós-produção depois, posso confirmar: &lt;strong&gt;software &lt;em&gt;&amp;ldquo;done&amp;rdquo;&lt;/em&gt; não existe.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Hoje o repositório do M.Akita Chronicles tem 335 commits e 1.422 testes. Amanhã, segunda-feira, os assinantes recebem a 3ª newsletter consecutiva — gerada, revisada, e enviada por um sistema que não para de evoluir. Enquanto isso, o &lt;a href="https://akitaonrails.github.io/2026/02/23/vibe-code-fiz-um-indexador-inteligente-de-imagens-com-ia-em-2-dias/"&gt;Frank Sherlock&lt;/a&gt; saiu de 50 commits e v0.1 pra 103 commits e v0.7 com face detection. O &lt;a href="https://akitaonrails.github.io/2026/02/01/vibe-code-fiz-um-editor-de-markdown-do-zero-com-claude-code-frankmd-part-1/"&gt;FrankMD&lt;/a&gt; recebeu 3 contribuidores externos e lançou a v0.2.0. E até o &lt;a href="https://akitaonrails.github.io/2026/02/21/vibe-code-fiz-um-clone-do-mega-em-rails-em-1-dia-pro-meu-home-server/"&gt;FrankMega&lt;/a&gt; — um projeto construído em 1 dia — precisou de correções quando usuários reais apareceram.&lt;/p&gt;</description><content:encoded><![CDATA[<p>E não deixe de assinar minha newsletter <a href="https://themakitachronicles.com/"target="_blank" rel="noopener">The M.Akita Chronicles</a>!</p>
<p>&ndash;</p>
<p>Publiquei o &ldquo;post final&rdquo; da série <a href="/2026/02/20/do-zero-a-pos-producao-em-1-semana-como-usar-ia-em-projetos-de-verdade-bastidores-do-the-m-akita-chronicles/">Bastidores do The M.Akita Chronicles</a> há 10 dias. 274 commits, 1.323 testes, deploy em produção. Escrevi as lições, fiz a conclusão, coloquei a citação no final. Done.</p>
<p>125 commits de pós-produção depois, posso confirmar: <strong>software <em>&ldquo;done&rdquo;</em> não existe.</strong></p>
<p>Hoje o repositório do M.Akita Chronicles tem 335 commits e 1.422 testes. Amanhã, segunda-feira, os assinantes recebem a 3ª newsletter consecutiva — gerada, revisada, e enviada por um sistema que não para de evoluir. Enquanto isso, o <a href="/2026/02/23/vibe-code-fiz-um-indexador-inteligente-de-imagens-com-ia-em-2-dias/">Frank Sherlock</a> saiu de 50 commits e v0.1 pra 103 commits e v0.7 com face detection. O <a href="/2026/02/01/vibe-code-fiz-um-editor-de-markdown-do-zero-com-claude-code-frankmd-part-1/">FrankMD</a> recebeu 3 contribuidores externos e lançou a v0.2.0. E até o <a href="/2026/02/21/vibe-code-fiz-um-clone-do-mega-em-rails-em-1-dia-pro-meu-home-server/">FrankMega</a> — um projeto construído em 1 dia — precisou de correções quando usuários reais apareceram.</p>
<p>Ao longo de fevereiro, publiquei mais de uma dezena de posts detalhando a construção de cada projeto. Este post é diferente. Não é sobre construir do zero, já cobri isso. É sobre o que acontece <strong>depois</strong>. E o que acontece depois destrói a narrativa do one-shot prompt. Software precisa de um humano experiente no volante. Desenvolvimento iterativo é a única forma que funciona. Quem discorda não botou sistema em produção ainda.</p>
<p>Vou provar com <code>git log</code>.</p>
<h2>A Vida Depois do Deploy<span class="hx:absolute hx:-mt-20" id="a-vida-depois-do-deploy"></span>
    <a href="#a-vida-depois-do-deploy" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><table>
  <thead>
      <tr>
          <th>Projeto</th>
          <th>Commits pós-publicação</th>
          <th>Destaque</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>The M.Akita Chronicles</td>
          <td>56</td>
          <td>3ª semana em produção, features novas, 13 bug fixes, prompt tuning</td>
      </tr>
      <tr>
          <td>Frank Sherlock</td>
          <td>53</td>
          <td>De v0.3 a v0.7: video support, face detection, AUR publish</td>
      </tr>
      <tr>
          <td>FrankMD</td>
          <td>14</td>
          <td>3 contribuidores externos, 4 PRs merged, v0.2.0</td>
      </tr>
      <tr>
          <td>FrankMega</td>
          <td>2</td>
          <td>MIME types que ninguém previu</td>
      </tr>
      <tr>
          <td><strong>Total</strong></td>
          <td><strong>125</strong></td>
          <td></td>
      </tr>
  </tbody>
</table>
<p>Vamos aos detalhes.</p>
<h2>The M.Akita Chronicles: 3 Semanas em Produção<span class="hx:absolute hx:-mt-20" id="the-makita-chronicles-3-semanas-em-produção"></span>
    <a href="#the-makita-chronicles-3-semanas-em-produ%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O sistema de newsletter está no ar desde 16 de fevereiro. Já enviou 2 newsletters e amanhã envia a terceira. 56 commits aconteceram desde o &ldquo;post final&rdquo;:</p>
<table>
  <thead>
      <tr>
          <th>Data</th>
          <th>Commits</th>
          <th>O que aconteceu</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>20/fev (qui)</td>
          <td>16</td>
          <td>Steam Gaming (seção nova inteira), bug fixes em paywall detection</td>
      </tr>
      <tr>
          <td>21/fev (sex)</td>
          <td>12</td>
          <td>/preview command, YouTube collage, notificações de /rerun</td>
      </tr>
      <tr>
          <td>22/fev (sáb)</td>
          <td>1</td>
          <td>Fix: /preflight mandando resultado pro channel errado</td>
      </tr>
      <tr>
          <td>23/fev (dom)</td>
          <td>10</td>
          <td>Publicação da 2ª newsletter, Gmail clipping warning, TTS revert</td>
      </tr>
      <tr>
          <td>24/fev (seg)</td>
          <td>1</td>
          <td>Ajuste de prompt do podcast</td>
      </tr>
      <tr>
          <td>28/fev (sáb)</td>
          <td>7</td>
          <td>Marvin prompt tuning, rate limiting, /rerun comments</td>
      </tr>
      <tr>
          <td>01/mar (dom)</td>
          <td>9</td>
          <td>Mood system, switch pra Grok-4, QA pipeline, centralização de config</td>
      </tr>
  </tbody>
</table>
<h3>Features que Ninguém Previu<span class="hx:absolute hx:-mt-20" id="features-que-ninguém-previu"></span>
    <a href="#features-que-ningu%c3%a9m-previu" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p><strong>Steam Gaming.</strong> Não existia no plano original. Nasceu porque a seção de entretenimento só tinha anime — e leitores gamers ficaram de fora. Resultado: 6 commits só no dia de lançamento. O primeiro commit (<code>bf41e25</code>) adicionou a seção completa — serviço de API Steam, job de geração, testes, shortcode Hugo. Os 5 seguintes corrigiram: parsing de datas em português, offset pro ranking não repetir o top 10, filtro de wishlist pra releases, dark theme. Nenhum spec do mundo prevê que a API do Steam retorna datas com abreviações em português (<code>&quot;fev&quot;</code>, <code>&quot;mar&quot;</code>, <code>&quot;abr&quot;</code>) quando você pede <code>l=brazilian</code>. Isso você descobre quando o parser quebra em produção.</p>
<p><strong>Sistema de preview.</strong> O <code>/preview</code> nasceu porque eu precisava ver como o conteúdo auto-gerado ficava <strong>antes</strong> de publicar a newsletter inteira. Parece óbvio em retrospecto, mas na v1 a única forma de validar era gerar tudo e olhar o resultado final. 5 commits pra construir um sistema de preview com 9 seções, aliases (<code>hn</code> pra hacker_news, <code>steam</code> pra steam_gaming), modo de preview de comentários separado, e rescue quando uma seção falha sem derrubar as outras (<code>d23c725</code> — porque uma seção com erro estava matando o preview inteiro).</p>
<p><strong>Moods do Marvin.</strong> O Marvin (a persona sarcástica do bot) sofre de um problema crônico de LLMs: suavização. Sem intervenção, todo comentário vira o mesmo tom morno. A solução iterativa foi um sistema de moods — 9 modos que o operador escolhe por story:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="no">MARVIN_MOODS</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;sarcastic&#34;</span>   <span class="o">=&gt;</span> <span class="s2">&#34;Be extra sarcastic and biting in your commentary.&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;ironic&#34;</span>      <span class="o">=&gt;</span> <span class="s2">&#34;Use irony and dark humor to make your point.&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;grounded&#34;</span>    <span class="o">=&gt;</span> <span class="s2">&#34;Be more neutral and journalist-like, factual and measured.&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;provocative&#34;</span> <span class="o">=&gt;</span> <span class="s2">&#34;Be provocative and controversial, challenge assumptions.&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;counter&#34;</span>     <span class="o">=&gt;</span> <span class="s2">&#34;Take the opposite position from Akita&#39;s comment.&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;insightful&#34;</span>  <span class="o">=&gt;</span> <span class="s2">&#34;Find a non-obvious angle -- a historical parallel, a second-order consequence.&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;positive&#34;</span>    <span class="o">=&gt;</span> <span class="s2">&#34;Find the genuinely positive angle.&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;hopeful&#34;</span>     <span class="o">=&gt;</span> <span class="s2">&#34;Be cautiously optimistic. Acknowledge the good potential.&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;negative&#34;</span>    <span class="o">=&gt;</span> <span class="s2">&#34;Be extra pessimistic and bleak.&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span><span class="o">.</span><span class="n">freeze</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Nada disso surgiu de uma spec. Surgiu de 3 semanas lendo comentários genéricos e pensando <em>&ldquo;isso não tá bom&rdquo;</em>. São 7 commits só de prompt tuning ao longo de 10 dias. Bani padrões formulaicos (<code>d4bd3a6</code>). Eliminei o &ldquo;Ah,&rdquo; como abertura (<code>4171628</code>). Removi o Marvin de seções inteiras do podcast porque ele tava contaminando o tom (<code>246cc60</code>). Forcei substância ao invés de trocadilhos (<code>8bc47c4</code>). Cada commit de prompt é uma micro-correção que só faz sentido depois de ler o output anterior.</p>
<h3>Bugs que Só Existem em Produção<span class="hx:absolute hx:-mt-20" id="bugs-que-só-existem-em-produção"></span>
    <a href="#bugs-que-s%c3%b3-existem-em-produ%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Dos 56 commits, 13 são bug fixes. Alguns favoritos:</p>
<ul>
<li>
<p><strong>Gmail clipping</strong> (<code>3258f5b</code>): Gmail silenciosamente corta emails maiores que 102KB. Descobri quando a 2ª newsletter saiu mais longa e leitores no Gmail não viram o final. Resultado: um check de tamanho no content preflight que avisa antes de publicar. Reduzi as seções de história de 10 pra 5 itens (<code>51ce528</code>) pra caber no limite.</p>
</li>
<li>
<p><strong>False paywall detection</strong> (<code>1fd8739</code>): o scraper marcava sites como paywall quando encontrava texto de bloqueio acidental num rodapé genérico. Só apareceu quando a lista de stories cresceu pra dezenas de fontes reais.</p>
</li>
<li>
<p><strong>t.co link mangling</strong> (<code>6bd056f</code>): o Twitter encurta URLs com t.co, mas também auto-linka nomes de arquivo que parecem domínios. <code>config.yml</code> vira um link pro domínio <code>config.yml</code>. 158 linhas de fix pra tratar corretamente textos de tweet.</p>
</li>
<li>
<p><strong>TTS language revert</strong> (<code>7803ad9</code> -&gt; <code>c1dd668</code>): tentei trocar o idioma do TTS de &ldquo;Portuguese&rdquo; pra &ldquo;Auto&rdquo;. O modelo gerou sotaque misturado. Revertido no mesmo dia.</p>
</li>
<li>
<p><strong>Podcast section ordering</strong> (<code>5bef18c</code>): seções do podcast saíram fora de ordem. Fix de 3 linhas + untrack de 1.504 linhas de conteúdo gerado que foi commitado por acidente.</p>
</li>
<li>
<p><strong>Elementor sites com múltiplos <code>&lt;article&gt;</code></strong> (<code>e70b756</code>): sites construídos com Elementor usam a tag <code>&lt;article&gt;</code> de forma não-semântica. O extrator de conteúdo pegava o bloco errado. 171 linhas de fix + testes.</p>
</li>
</ul>
<p>Nenhum desses bugs poderia ter sido previsto numa spec. Eles só existem porque o sistema tá no ar, processando dados reais, batendo em APIs reais, sendo lido por gente real.</p>
<h3>De 1.323 pra 1.422 Testes<span class="hx:absolute hx:-mt-20" id="de-1323-pra-1422-testes"></span>
    <a href="#de-1323-pra-1422-testes" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>A suíte de testes continuou crescendo junto:</p>
<table>
  <thead>
      <tr>
          <th>App</th>
          <th>Testes (20/fev)</th>
          <th>Testes (01/mar)</th>
          <th>Crescimento</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>marvin-bot</td>
          <td>970</td>
          <td>1.060</td>
          <td>+90</td>
      </tr>
      <tr>
          <td>newsletter</td>
          <td>353</td>
          <td>362</td>
          <td>+9</td>
      </tr>
      <tr>
          <td><strong>Total</strong></td>
          <td><strong>1.323</strong></td>
          <td><strong>1.422</strong></td>
          <td><strong>+99</strong></td>
      </tr>
  </tbody>
</table>
<p>Feature nova? Vem com teste. Bug fix? Vem com teste de regressão. Sem isso, os 56 commits de pós-produção seriam 56 oportunidades de quebrar algo que funcionava ontem. TDD não é fase, é hábito.</p>
<h3>O Modelo Mudou: De Claude pra Grok-4<span class="hx:absolute hx:-mt-20" id="o-modelo-mudou-de-claude-pra-grok-4"></span>
    <a href="#o-modelo-mudou-de-claude-pra-grok-4" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Commit <code>8f9d11c</code>: <code>Switch default model to x-ai/grok-4</code>. A arquitetura isolou o modelo LLM numa variável de ambiente desde o início. Mas o nome do modelo ainda estava referenciado em código por 24 arquivos. Resultado: commit <code>c8c688e</code> — <code>Centralize LLM model config</code> — 24 arquivos tocados pra garantir que trocar de modelo seja uma mudança de 1 linha de config.</p>
<p>Esse tipo de refactoring só surge na operação. Quando você começa o projeto, não sabe que vai trocar de modelo. Quando troca, quer que seja trivial. E a limpeza pra tornar trivial? Só acontece quando a dor aparece.</p>
<h2>Frank Sherlock: De v0.1 a v0.7 em 4 Dias<span class="hx:absolute hx:-mt-20" id="frank-sherlock-de-v01-a-v07-em-4-dias"></span>
    <a href="#frank-sherlock-de-v01-a-v07-em-4-dias" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O <a href="/2026/02/23/vibe-code-fiz-um-indexador-inteligente-de-imagens-com-ia-em-2-dias/">post sobre o Frank Sherlock</a> cobriu os primeiros 2 dias e ~50 commits: a pesquisa de benchmarks, o scaffold do app Tauri (Rust + React), a pipeline de classificação com Ollama, e o lançamento da v0.1.0 com binários pra Linux, macOS e Windows.</p>
<p>O que o post não cobriu: os 53 commits seguintes, em 4 dias, que levaram o projeto da v0.3 pra v0.7:</p>
<table>
  <thead>
      <tr>
          <th>Versão</th>
          <th>Data</th>
          <th>Destaque</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>v0.4.0</td>
          <td>24/fev</td>
          <td>Duplicate detection (SHA-256 + dHash), PDF password manager</td>
      </tr>
      <tr>
          <td>v0.5.0</td>
          <td>24/fev</td>
          <td>Auto-update, scan performance 2x, checkpoint resume</td>
      </tr>
      <tr>
          <td>v0.6.0</td>
          <td>25/fev</td>
          <td>Video support (11 formatos), directory tree, FTS stemmer</td>
      </tr>
      <tr>
          <td>v0.7.0</td>
          <td>27/fev</td>
          <td><strong>Face detection</strong> com ONNX nativo, person management</td>
      </tr>
  </tbody>
</table>
<h3>Face Detection: A Feature que Nasceu da Iteração<span class="hx:absolute hx:-mt-20" id="face-detection-a-feature-que-nasceu-da-iteração"></span>
    <a href="#face-detection-a-feature-que-nasceu-da-itera%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>A v0.1 era um indexador de imagens com classificação por LLM. A v0.7 tem detecção de rostos com embeddings de 512 dimensões, clustering por similaridade de cosseno, e busca por pessoa (<code>face:alice</code>). Nada disso tava no plano original. Surgiu porque comecei a usar o app com fotos de verdade e pensei <em>&ldquo;quero encontrar todas as fotos de fulano&rdquo;</em> A feature nasceu do uso, não da spec.</p>
<p>O caminho até lá foi metódico:</p>
<ol>
<li><strong><code>f34132f</code></strong>: A/B testing framework pra face detection — benchmarkear antes de implementar, não depois</li>
<li><strong><code>ef3be82</code></strong>: Resultados do A/B (SCRFD + ArcFace venceu)</li>
<li><strong><code>6d9174a</code></strong>: Implementação nativa com ONNX Runtime — sem Python, sem dependência externa</li>
<li><strong><code>3b25eaf</code></strong>: Clustering, person management, FacesView completa</li>
<li><strong><code>a02d67f</code></strong>: Refactoring — extrair helpers, deletar código morto, compartilhar CSS</li>
</ol>
<p>Benchmark -&gt; implementar -&gt; refatorar. O mesmo ciclo de sempre. E algo que nenhum one-shot prompt produz.</p>
<h3>Video Support: Outro Emergente<span class="hx:absolute hx:-mt-20" id="video-support-outro-emergente"></span>
    <a href="#video-support-outro-emergente" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>O app foi pensado pra imagens. Mas pastas reais de mídia têm vídeos. Commit <code>a67a2f9</code> adicionou suporte completo: scanning de 11 formatos (MP4, MKV, AVI, MOV, WebM&hellip;), extração de keyframe pra classificação pelo LLM, skip de frames pretos, parsing de legendas .srt pro índice full-text, e preview inline com streaming HTTP Range.</p>
<p>1.626 linhas adicionadas num commit. Uma feature inteira que nasceu do uso real, não de uma especificação.</p>
<h3>7 Releases, 3 Plataformas, AUR Automático<span class="hx:absolute hx:-mt-20" id="7-releases-3-plataformas-aur-automático"></span>
    <a href="#7-releases-3-plataformas-aur-autom%c3%a1tico" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Em 7 dias, o Frank Sherlock teve 7 releases. Cada um com binários compilados pra Linux (AppImage), macOS (DMG com notarização e code signing), e Windows (MSI). A pipeline de CI/CD (<code>release.yml</code>) faz tudo automaticamente. A partir da v0.5.0, um workflow adicional (<code>aur-publish.yml</code>) publica automaticamente no AUR — o repositório de pacotes do Arch Linux.</p>
<p>No final: 17.210 linhas de Rust, 10.863 linhas de TypeScript, 621 testes (322 Rust + 299 frontend). Cross-platform. Releases publicados e instaláveis por qualquer usuário. Uma semana, um dev, um agente de IA.</p>
<p>A parte de CI/CD pra cross-platform é onde a fantasia do <em>&ldquo;funciona na minha máquina&rdquo;</em> morre. Foram 17 commits só de build: Windows UNC paths, macOS signing com notarização, Linux AppImage, permissões de release workflow, macOS Intel target removido. Nenhum LLM do mundo sabe que o macOS exige entitlements específicos pra hardened runtime ou que paths no Windows começam com <code>\\?\</code>. Esse tipo de trabalho de deploy exige alguém que já passou por essa dor antes.</p>
<h2>FrankMD: Open Source de Verdade<span class="hx:absolute hx:-mt-20" id="frankmd-open-source-de-verdade"></span>
    <a href="#frankmd-open-source-de-verdade" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O FrankMD foi o primeiro projeto desta saga, um editor Markdown self-hosted com Rails 8. Os <a href="/2026/02/01/vibe-code-fiz-um-editor-de-markdown-do-zero-com-claude-code-frankmd-part-1/">posts de fevereiro</a> cobriram a construção. O que aconteceu depois é mais interessante: outras pessoas começaram a contribuir.</p>
<p>14 commits desde 20 de fevereiro. 3 contribuidores externos. 4 PRs merged. Release v0.2.0 no dia 28:</p>
<table>
  <thead>
      <tr>
          <th>PR</th>
          <th>Autor</th>
          <th>Tipo</th>
          <th>O que fez</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>#34</td>
          <td>@murilo-develop</td>
          <td>Bug fix</td>
          <td>Integração Ollama: ModelNotFoundError + API base URL</td>
      </tr>
      <tr>
          <td>#36</td>
          <td>@rafaself</td>
          <td>Bug fix</td>
          <td>Comportamento de table hints no editor (3 commits iterativos)</td>
      </tr>
      <tr>
          <td>#38</td>
          <td>@LuccaRomanelli</td>
          <td>Feature</td>
          <td>Auto-sync de tema com o desktop environment Omarchy</td>
      </tr>
      <tr>
          <td>#39</td>
          <td>@LuccaRomanelli</td>
          <td>Feature</td>
          <td>&ldquo;New Folder&rdquo; no menu de contexto do explorer</td>
      </tr>
  </tbody>
</table>
<h3>O Padrão do Maintainer<span class="hx:absolute hx:-mt-20" id="o-padrão-do-maintainer"></span>
    <a href="#o-padr%c3%a3o-do-maintainer" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>O mais revelador não são as contribuições em si, mas o que eu fiz depois de cada merge.</p>
<p>Quando o @LuccaRomanelli submeteu o PR do Omarchy theme sync (+308 linhas), eu mergeei e imediatamente commitei <code>fix: harden Omarchy theme integration and fix broken tests</code> — <strong>+163 linhas</strong> de fixes e testes no commit seguinte. O contribuidor implementou a feature. O maintainer endureceu.</p>
<p>Quando o @rafaself submeteu o fix de table hints, foram 3 commits iterativos no mesmo dia — <code>enhance</code>, <code>improve</code>, <code>streamline</code> — mostrando o mesmo padrão de refinamento progressivo que eu faço com o agente de IA. No dia seguinte, ele mandou um commit separado atualizando faraday, nokogiri e rack por security advisories.</p>
<p>No dia 28, sentei e fiz tudo de uma vez: mergeei as 4 PRs, commitei o hardening, atualizei 5 gems (brakeman, bootsnap, selenium-webdriver, web-console, mocha), e publiquei as release notes da v0.2.0. Um <em>&ldquo;release day&rdquo;</em> clássico.</p>
<p>O FrankMD hoje tem 226 commits, 1.804 testes (425 Ruby + 1.379 JavaScript), e contribuidores ativos. Não é mais <em>&ldquo;meu projetinho pessoal&rdquo;</em>. Virou software com comunidade. E comunidade não aparece pra protótipo sem testes que <em>&ldquo;funciona na minha máquina&rdquo;</em>. Aparece pra projeto com CI verde, documentação, releases versionados, e código que dá pra ler.</p>
<h2>FrankMega: Até o Menor Projeto Precisa de Pós-Produção<span class="hx:absolute hx:-mt-20" id="frankmega-até-o-menor-projeto-precisa-de-pós-produção"></span>
    <a href="#frankmega-at%c3%a9-o-menor-projeto-precisa-de-p%c3%b3s-produ%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O FrankMega foi construído em <a href="/2026/02/21/vibe-code-fiz-um-clone-do-mega-em-rails-em-1-dia-pro-meu-home-server/">1 dia</a>. 26 commits, file sharing seguro com Rails 8, 210 testes, deploy via Docker + Cloudflare Tunnel. Post publicado no mesmo dia. Pronto, certo?</p>
<p>Três dias depois, 2 commits:</p>
<ul>
<li><code>db4bb705</code> — Add macOS, Linux, and Windows package MIME types to seed defaults</li>
<li><code>b0c4829a</code> — Fix MIME types to match Marcel detection, add normalizes strip</li>
</ul>
<p>Usuários tentaram compartilhar arquivos <code>.dmg</code>, <code>.deb</code>, e <code>.msi</code>. O MIME type detection (via gem Marcel) não reconhecia esses formatos porque não estavam nos defaults do seed. Dois commits. 22 linhas. 15 minutos.</p>
<p>Mas sem eles, o FrankMega não servia pra compartilhar pacotes de instalação — que é exatamente o caso de uso mais comum num home server de devs.</p>
<blockquote>
  <p>Nenhum prompt no mundo prevê que seus usuários vão querer compartilhar <code>.deb</code> no primeiro dia.</p>

</blockquote>
<p>O projeto mais simples de todos, com a pós-produção mais curta. E mesmo assim, precisou de iteração.</p>
<h2>Os Números Consolidados<span class="hx:absolute hx:-mt-20" id="os-números-consolidados"></span>
    <a href="#os-n%c3%bameros-consolidados" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><table>
  <thead>
      <tr>
          <th>Projeto</th>
          <th>Commits (total)</th>
          <th>Testes</th>
          <th>Pós-produção</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>The M.Akita Chronicles</td>
          <td>335</td>
          <td>1.422</td>
          <td>56 commits, 10 dias em produção</td>
      </tr>
      <tr>
          <td>Frank Sherlock</td>
          <td>103</td>
          <td>621</td>
          <td>53 commits, 4 releases extras</td>
      </tr>
      <tr>
          <td>FrankMD</td>
          <td>226</td>
          <td>1.804</td>
          <td>14 commits, 3 contribuidores</td>
      </tr>
      <tr>
          <td>FrankMega</td>
          <td>28</td>
          <td>210</td>
          <td>2 commits, MIME fixes</td>
      </tr>
      <tr>
          <td><strong>Total</strong></td>
          <td><strong>692</strong></td>
          <td><strong>4.057</strong></td>
          <td><strong>125 commits pós-publicação</strong></td>
      </tr>
  </tbody>
</table>
<p>692 commits. 4.057 testes. 4 projetos em produção. Fevereiro de 2026. Eu e um agente de IA.</p>
<h2>Por Que One-Shot Prompt É Mito<span class="hx:absolute hx:-mt-20" id="por-que-one-shot-prompt-é-mito"></span>
    <a href="#por-que-one-shot-prompt-%c3%a9-mito" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Olha os 125 commits de pós-produção e me diz qual deles poderia ter sido previsto por uma especificação.</p>
<p>Gmail corta emails maiores que 102KB, e você só descobre quando manda o primeiro email longo. A Steam API retorna datas com abreviações em português (<code>&quot;fev&quot;</code>, <code>&quot;abr&quot;</code>), e você só descobre quando o parser quebra no domingo de geração. Usuários de macOS tentam compartilhar <code>.dmg</code> e não conseguem porque o MIME type não tá no seed. O Marvin abre todo comentário com <em>&ldquo;Ah,&rdquo;</em> e você só percebe quando lê 30 seguidos e quer arrancar os olhos. O modelo LLM precisa ser trocável com 1 linha de config, mas tá espalhado em 24 arquivos. Windows usa UNC paths que começam com <code>\\?\</code>, e o CI explode na sua cara. E o TTS em modo &ldquo;Auto&rdquo;? Gera um sotaque que parece português de Lisboa tentando ser carioca.</p>
<p>Nada disso é &ldquo;debugar&rdquo; no sentido tradicional. É navegar um espaço de problemas que só se revela quando o software encontra a realidade. Cada um desses foi uma decisão tomada em tempo real por alguém com contexto.</p>
<p>A fantasia do one-shot prompt é que, se você escrever uma especificação suficientemente detalhada, a IA produz o software perfeito. Mas a especificação perfeita exigiria que você soubesse de antemão tudo que vai dar errado. E se você soubesse de antemão tudo que vai dar errado, você não precisaria da especificação — já teria o software pronto na cabeça.</p>
<p>Software bom é o resultado de centenas de micro-decisões tomadas com o sistema rodando. Não de uma macro-decisão tomada antes de escrever a primeira linha.</p>
<h2>O Papel do Desenvolvedor Experiente<span class="hx:absolute hx:-mt-20" id="o-papel-do-desenvolvedor-experiente"></span>
    <a href="#o-papel-do-desenvolvedor-experiente" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A IA acelerou tudo isso. Sem ela, 692 commits em um mês seria impossível pra uma pessoa só. Mas aceleração sem direção é só entropia mais rápida.</p>
<p>Em cada projeto houve decisões que a IA não teria como tomar sozinha. Trocar de Claude pra Grok-4 porque o modelo anterior tava fraco num domínio específico. Benchmark de SCRFD vs alternativas <em>antes</em> de implementar face detection, porque a escolha errada ia custar dias. O hardening de +163 linhas que eu commitei imediatamente depois de mergear o PR do Omarchy, porque eu vi onde ia quebrar. O revert do TTS em modo Auto no mesmo dia, porque eu sei que &ldquo;Auto&rdquo; num modelo de TTS pra português brasileiro vai produzir sotaque misturado.</p>
<p>O caso do circuit breaker é o mais ilustrativo. Quando adicionei rate limiting, a Brave Search API começou a retornar 429 de vez em quando. Se eu pedisse, o agente implementaria um retry com backoff exponencial. Mas eu não pedi retry. Pedi circuit breaker:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">WebSearcher</span>
</span></span><span class="line"><span class="cl">  <span class="no">CIRCUIT_BREAKER_SECONDS</span> <span class="o">=</span> <span class="mi">120</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">search</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="ss">max_results</span><span class="p">:</span> <span class="mi">5</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="o">[]</span> <span class="k">if</span> <span class="n">circuit_open?</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">response</span> <span class="o">=</span> <span class="n">brave_search</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">max_results</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">response</span><span class="o">.</span><span class="n">code</span> <span class="o">==</span> <span class="mi">429</span>
</span></span><span class="line"><span class="cl">      <span class="n">trip_circuit!</span>
</span></span><span class="line"><span class="cl">      <span class="no">Rails</span><span class="o">.</span><span class="n">logger</span><span class="o">.</span><span class="n">warn</span><span class="p">(</span><span class="s2">&#34;WebSearcher rate limited (429)&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="o">[]</span>
</span></span><span class="line"><span class="cl">    <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="k">rescue</span> <span class="no">Net</span><span class="o">::</span><span class="no">OpenTimeout</span><span class="p">,</span> <span class="no">Net</span><span class="o">::</span><span class="no">ReadTimeout</span> <span class="o">=&gt;</span> <span class="n">e</span>
</span></span><span class="line"><span class="cl">    <span class="n">trip_circuit!</span>
</span></span><span class="line"><span class="cl">    <span class="o">[]</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Se a API retorna 429 ou timeout, para de tentar por 120 segundos. Sem retry, sem backoff, sem fila. Por quê? Porque eu sei que o cron roda todo dia às 8h e que nos domingos de geração de newsletter o volume de queries triplica. Uma manada de retries atrasando tudo é pior que resultados vazios numa seção.</p>
<p>A IA implementa um circuit breaker quando você pede. Mas ela não vai pedir pra implementar um circuit breaker. Ela não tem o contexto operacional. Isso é conhecimento que vem de rodar sistemas em produção por décadas.</p>
<blockquote>
  <p>O agente escreve o código. Eu decido qual código escrever. E essa decisão exige experiência que nenhum prompt substitui.</p>

</blockquote>
<h2>As Lições<span class="hx:absolute hx:-mt-20" id="as-lições"></span>
    <a href="#as-li%c3%a7%c3%b5es" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p><strong>1. Software em produção diverge da spec em horas, não em meses.</strong> Os primeiros bugs do M.Akita Chronicles surgiram na primeira newsletter real. Os MIME types do FrankMega quebraram nos primeiros uploads. Quem acha que deploya e acabou tá vivendo num mundo que não existe.</p>
<p><strong>2. Pós-produção não é &ldquo;manutenção&rdquo;.</strong> 56 commits em 10 dias no M.Akita Chronicles não são patches. São features novas (Steam Gaming, preview, moods), refactoring de arquitetura (centralização de config do LLM), hardening de segurança (rate limiting). Isso é desenvolvimento. O software não parou de evoluir só porque eu disse <em>&ldquo;done&rdquo;</em> num blog post.</p>
<p><strong>3. TDD protege a evolução.</strong> 99 novos testes em 10 dias. Os 1.804 testes do FrankMD permitiram mergear 4 PRs de contribuidores externos sem medo. Sem testes, cada merge é roleta russa.</p>
<p><strong>4. Small releases mantêm a sanidade.</strong> 7 releases do Frank Sherlock em 7 dias. CI verde, binários compilados, release notes. Deu problema? Reverte uma versão. Compara com &ldquo;6 meses + big bang release&rdquo; e me conta qual funciona melhor.</p>
<p><strong>5. Comunidade aparece pra projetos reais.</strong> Ninguém manda PR pra protótipo sem testes que <em>&ldquo;funciona na minha máquina&rdquo;</em>. O FrankMD recebeu 3 contribuidores porque tem CI verde, documentação, e releases versionados.</p>
<p><strong>6. A experiência do desenvolvedor é o gargalo, não a velocidade da IA.</strong> 692 commits em um mês. Mas cada commit que importa exigiu décadas de experiência pra saber que era necessário. A IA digita rápido. Eu sei o que digitar.</p>
<p><strong>7. One-shot é pra demo. Iteração é pra produção.</strong> Se o objetivo é um vídeo de 10 minutos mostrando um <em>&ldquo;SaaS pronto&rdquo;</em>, one-shot serve. Se o objetivo é software que sobrevive ao contato com usuários reais, só iteração funciona. E iteração sustentável exige disciplina: TDD, CI, small releases, refactoring contínuo. Sem atalho.</p>
<h2>Pro Sênior que Ainda Tá de Braços Cruzados<span class="hx:absolute hx:-mt-20" id="pro-sênior-que-ainda-tá-de-braços-cruzados"></span>
    <a href="#pro-s%c3%aanior-que-ainda-t%c3%a1-de-bra%c3%a7os-cruzados" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Até aqui eu bati nos amadores que acham que podem mandar um prompt e a IA cospe um sistema pronto. Justo. Mas tem um outro grupo que me preocupa tanto quanto: o desenvolvedor sênior que viu a IA errar três vezes, declarou que <em>&ldquo;isso não serve pra nada&rdquo;</em>, e voltou a fazer tudo na mão.</p>
<p>Eu entendo o raciocínio. A IA alucina, gera código com bugs sutis, sugere soluções over-engineered. Tudo verdade, e eu documentei cada um desses problemas nos posts anteriores. Mas me diz uma coisa: você nunca fez exatamente a mesma coisa? Você nunca passou 2 horas lendo documentação pra descobrir que era um typo na config? A diferença é que quando a IA erra, você pega nos testes e corrige em minutos. Quando você erra sozinho, leva o mesmo tempo pra cometer o erro e mais tempo ainda pra achar, porque você confia no próprio código.</p>
<p>Vamos olhar pros números concretos do que eu entreguei em fevereiro, uma pessoa e um agente de IA:</p>
<table>
  <thead>
      <tr>
          <th>Projeto</th>
          <th>Tempo</th>
          <th>Resultado</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>M.Akita Chronicles</td>
          <td>8 dias</td>
          <td>4 apps (Rails + Python + Hugo), 335 commits, 1.422 testes, em produção há 3 semanas</td>
      </tr>
      <tr>
          <td>Frank Sherlock</td>
          <td>7 dias</td>
          <td>App desktop Tauri (Rust + React), 103 commits, 621 testes, 7 releases, binários pra 3 OS</td>
      </tr>
      <tr>
          <td>FrankMD</td>
          <td>~4 dias</td>
          <td>Editor Markdown Rails 8, 226 commits, 1.804 testes, 3 contribuidores externos</td>
      </tr>
      <tr>
          <td>FrankMega</td>
          <td>1 dia</td>
          <td>File sharing Rails 8, 28 commits, 210 testes, deploy Docker + Cloudflare</td>
      </tr>
  </tbody>
</table>
<p>Agora faz a conta de cabeça. Quanto tempo você levaria pra fazer o Frank Sherlock sozinho? Um app Tauri do zero, com pipeline de classificação por LLM em Rust, OCR via Python, full-text search com FTS5, detecção de duplicatas por perceptual hash, face detection com ONNX nativo, suporte a vídeo com extração de keyframe, CI pra 3 plataformas com code signing e notarização no macOS, auto-update, e publicação automática no AUR. Com 621 testes. Em Rust, que não perdoa.</p>
<p>Sendo honesto: sem IA, um dev sênior bom levaria no mínimo 3-4 semanas nisso, provavelmente mais. Eu fiz em 7 dias, sozinho, e cada release tá publicado com binários que qualquer pessoa pode baixar e instalar.</p>
<p>O M.Akita Chronicles eu já estimei no <a href="/2026/02/20/do-zero-a-pos-producao-em-1-semana-como-usar-ia-em-projetos-de-verdade-bastidores-do-the-m-akita-chronicles/">post anterior</a>: ~200 user stories. Em Scrum com equipe sênior de 2-3 devs, sem impedimentos, seriam 10-15 semanas. Fiz em 8 dias. Hoje, 3 semanas depois, o sistema continua rodando, evoluindo, com 99 testes a mais do que quando <em>&ldquo;acabou&rdquo;</em>.</p>
<p>O FrankMega é mais modesto, mas file sharing seguro com Rails 8, I18n em 2 idiomas, 22 issues de segurança corrigidos, deploy via Docker, 210 testes. Fiz em 1 dia. Um sênior bom, sem IA, faria em 1-2 semanas na melhor das hipóteses.</p>
<p>E não estou falando de protótipos descartáveis. Gente de fora manda PR pro FrankMD. Assinantes reais recebem a newsletter do M.Akita Chronicles toda segunda-feira. Qualquer pessoa pode baixar o Frank Sherlock no GitHub Releases ou no AUR. CI verde, Brakeman zerado, testes reais, deploys automatizados. Isso é software de produção, não demo de conferência.</p>
<p><em>&ldquo;Ah, mas eu faço código melhor sem IA.&rdquo;</em> Talvez. Mas em quanto tempo? O que eu mostrei aqui não é que a IA faz código perfeito. Longe disso. É que com TDD, CI, pair programming com agente, e refactoring contínuo, o resultado final é código de produção com qualidade. 4.057 testes estão lá pra provar. Brakeman zerado. 125 commits de pós-produção mostram que o código aguenta evolução sem virar uma bola de lama.</p>
<p>E usar IA de vez em quando pra gerar um trecho de código aqui e ali, tipo autocomplete glorificado, também não é a resposta. Você tá deixando 90% do ganho na mesa. O que eu fiz em fevereiro foi pair programming full-time com um agente. Do primeiro commit ao deploy em produção. Com a mesma disciplina que eu usaria com um par humano. Resultado: 4 projetos em produção em 1 mês, com qualidade que eu coloco meu nome. Porque eu coloquei.</p>
<p>Se você é sênior e ainda tá esperando a IA <em>&ldquo;melhorar&rdquo;</em> pra começar a usar de verdade, eu digo o seguinte: ela já tá boa o suficiente. Os 692 commits estão aí pra provar. O gargalo agora é você aprender a trabalhar com ela.</p>
<h2>Conclusão<span class="hx:absolute hx:-mt-20" id="conclusão"></span>
    <a href="#conclus%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Em fevereiro de 2026, eu construí 4 projetos do zero à produção com IA. Mas a construção é a parte fácil. O que separa software de verdade de demo são os 125 commits que vieram depois, quando os bugs que ninguém previu apareceram, quando contribuidores externos mandaram PRs que precisaram de hardening, quando features novas surgiram do uso real e não de uma planilha de requisitos.</p>
<p>A IA me tornou absurdamente mais produtivo. Sem ela, o Frank Sherlock não teria face detection em 7 dias. Sem ela, o M.Akita Chronicles não estaria na 3ª semana de operação com 1.422 testes. A velocidade é real.</p>
<p>Mas nenhuma das decisões que importam veio da IA. Trocar de modelo, revertar o TTS no mesmo dia, olhar pro PR do contribuidor e ver que ia quebrar, pedir circuit breaker ao invés de retry. Tudo isso fui eu. A IA executou. As decisões foram minhas.</p>
<p>A IA é o acelerador. As técnicas de Extreme Programming (TDD, small releases, pair programming, refactoring contínuo) são o freio e a direção. Sem disciplina, IA produz código rápido que acumula dívida técnica mais rápido ainda. Com disciplina, IA produz software que evolui de verdade, semana após semana.</p>
<p>692 commits. 4.057 testes. 4 projetos em produção. E amanhã, segunda-feira, às 7h, os assinantes do The M.Akita Chronicles recebem a 3ª newsletter. Gerada, revisada, e enviada por um sistema que nunca vai estar <em>&ldquo;pronto&rdquo;</em>. Porque software pronto é software morto.</p>
<blockquote>
  <p>&ldquo;Software pronto é software morto. Software vivo itera.&rdquo;</p>

</blockquote>
]]></content:encoded><category>frank</category><category>llms</category><category>engenharia-de-software</category><category>off-topic</category></item><item><title>Testes de Integração em MonoRepo | Bastidores do The M.Akita Chronicles</title><link>https://akitaonrails.github.io/2026/02/20/testes-de-integracao-em-monorepo-bastidores-do-the-m-akita-chronicles/</link><guid isPermaLink="true">https://akitaonrails.github.io/2026/02/20/testes-de-integracao-em-monorepo-bastidores-do-the-m-akita-chronicles/</guid><pubDate>Fri, 20 Feb 2026 12:48:45 +0000</pubDate><description>&lt;p&gt;Este post vai fazer parte de uma série; acompanhe pela tag &lt;a href="https://akitaonrails.github.io/tags/the-m-akita-chronicles/"&gt;/themakitachronicles&lt;/a&gt;. Esta é a parte 8.&lt;/p&gt;
&lt;p&gt;E não deixe de assinar minha nova newsletter &lt;a href="https://themakitachronicles.com/"target="_blank" rel="noopener"&gt;The M.Akita Chronicles&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;&amp;ndash;&lt;/p&gt;
&lt;p&gt;Testes unitários são a zona de conforto de todo desenvolvedor. Você mocka tudo, isola tudo, roda em milissegundos, e o verde no terminal te dá uma falsa sensação de segurança. Até o dia que você deploya e descobre que o serviço A grava num formato que o serviço B não consegue ler. Ou que o RSS do Hacker News mudou de Atom pra RSS e seu parser explodiu. Ou que a Yahoo Finance começou a retornar 429 depois do terceiro ticker porque o rate limit que funcionava em teste não existe na vida real.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Este post vai fazer parte de uma série; acompanhe pela tag <a href="/tags/the-m-akita-chronicles/">/themakitachronicles</a>. Esta é a parte 8.</p>
<p>E não deixe de assinar minha nova newsletter <a href="https://themakitachronicles.com/"target="_blank" rel="noopener">The M.Akita Chronicles</a>!</p>
<p>&ndash;</p>
<p>Testes unitários são a zona de conforto de todo desenvolvedor. Você mocka tudo, isola tudo, roda em milissegundos, e o verde no terminal te dá uma falsa sensação de segurança. Até o dia que você deploya e descobre que o serviço A grava num formato que o serviço B não consegue ler. Ou que o RSS do Hacker News mudou de Atom pra RSS e seu parser explodiu. Ou que a Yahoo Finance começou a retornar 429 depois do terceiro ticker porque o rate limit que funcionava em teste não existe na vida real.</p>
<p>Testes unitários provam que as peças funcionam isoladas. Testes de integração provam que o <strong>sistema</strong> funciona. E num projeto com múltiplas aplicações compartilhando dados via filesystem, a diferença entre os dois é a diferença entre &ldquo;o código compila&rdquo; e &ldquo;a newsletter chega na inbox&rdquo;.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/frankmd/2026/02/screenshot-2026-02-20_12-22-50.jpg" alt="unit tests"  loading="lazy" /></p>
<h2>O Problema: Três Apps, Um Filesystem, Zero Garantias<span class="hx:absolute hx:-mt-20" id="o-problema-três-apps-um-filesystem-zero-garantias"></span>
    <a href="#o-problema-tr%c3%aas-apps-um-filesystem-zero-garantias" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O projeto tem uma arquitetura incomum: três aplicações Rails/Hugo num monorepo, integradas via um diretório <code>content/</code> compartilhado:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>akitando-news/
├── marvin-bot/    # Gera conteúdo (Discord bot, AI, scraping)
├── newsletter/    # Monta e envia a newsletter
├── blog/          # Hugo &#43; Hextra → Netlify
├── podcast-tts/   # Servidor TTS (Python/FastAPI)
└── content/       # Markdown &#43; YAML, a cola entre tudo</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>O marvin-bot escreve Markdown com frontmatter YAML em <code>content/anime/</code>, <code>content/hacker_news/</code>, etc. O newsletter lê esses arquivos pra montar a newsletter. O blog serve o mesmo conteúdo como páginas estáticas. O podcast lê a newsletter montada pra gerar o script de diálogo.</p>
<p>O contrato entre esses sistemas é <strong>implícito</strong>. Não tem schema. Não tem API versionada. Não tem protobuf. O contrato é: &ldquo;o arquivo Markdown tem esse frontmatter, com esses campos, nessa estrutura&rdquo;. Se o marvin-bot muda o formato de um campo — digamos, muda <code>image</code> de string pra array — o newsletter quebra silenciosamente. Nenhum teste unitário de nenhum dos dois apps detecta isso.</p>
<p>Essa é a falha fundamental de testar sistemas distribuídos com testes unitários: <strong>você está testando cada lado do contrato separadamente, mas nunca o contrato em si</strong>.</p>
<h2>Camada 1: Testes Unitários com Isolamento Paranoico<span class="hx:absolute hx:-mt-20" id="camada-1-testes-unitários-com-isolamento-paranoico"></span>
    <a href="#camada-1-testes-unit%c3%a1rios-com-isolamento-paranoico" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Antes de falar de integração, preciso explicar o que os testes unitários fazem nesse projeto — porque sem essa base, os testes de integração não teriam onde pisar.</p>
<p>Os 977 testes do marvin-bot rodam em paralelo usando todos os cores da máquina. Cada worker de teste tem seu próprio diretório:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="n">parallelize</span><span class="p">(</span><span class="ss">workers</span><span class="p">:</span> <span class="ss">:number_of_processors</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">parallelize_setup</span> <span class="k">do</span> <span class="o">|</span><span class="n">worker</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">  <span class="no">Rails</span><span class="o">.</span><span class="n">application</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">content_dir</span> <span class="o">=</span>
</span></span><span class="line"><span class="cl">    <span class="no">Rails</span><span class="o">.</span><span class="n">root</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="s2">&#34;tmp&#34;</span><span class="p">,</span> <span class="s2">&#34;test_content_w</span><span class="si">#{</span><span class="n">worker</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span><span class="o">.</span><span class="n">to_s</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Mas worker-level não é suficiente. Dentro de cada worker, múltiplos testes rodam sequencialmente — e se um teste deixa um arquivo em <code>content/stories/</code>, o próximo teste pode encontrar dados espúrios. A solução: <strong>um diretório único por teste</strong>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="n">setup</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">  <span class="vi">@base_content_dir</span> <span class="o">=</span> <span class="no">Rails</span><span class="o">.</span><span class="n">application</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">content_dir</span>
</span></span><span class="line"><span class="cl">  <span class="vi">@test_content_dir</span> <span class="o">=</span> <span class="no">File</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="vi">@base_content_dir</span><span class="p">,</span> <span class="no">SecureRandom</span><span class="o">.</span><span class="n">hex</span><span class="p">(</span><span class="mi">8</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">  <span class="no">Rails</span><span class="o">.</span><span class="n">application</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">content_dir</span> <span class="o">=</span> <span class="vi">@test_content_dir</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="no">FileUtils</span><span class="o">.</span><span class="n">mkdir_p</span><span class="p">(</span><span class="no">File</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="vi">@test_content_dir</span><span class="p">,</span> <span class="s2">&#34;stories&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">  <span class="no">FileUtils</span><span class="o">.</span><span class="n">mkdir_p</span><span class="p">(</span><span class="no">File</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="vi">@test_content_dir</span><span class="p">,</span> <span class="s2">&#34;newsletters&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">  <span class="no">FileUtils</span><span class="o">.</span><span class="n">mkdir_p</span><span class="p">(</span><span class="no">File</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="vi">@test_content_dir</span><span class="p">,</span> <span class="s2">&#34;images&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">teardown</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">  <span class="no">FileUtils</span><span class="o">.</span><span class="n">rm_rf</span><span class="p">(</span><span class="vi">@test_content_dir</span><span class="p">)</span> <span class="k">if</span> <span class="vi">@test_content_dir</span>
</span></span><span class="line"><span class="cl">  <span class="no">Rails</span><span class="o">.</span><span class="n">application</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">content_dir</span> <span class="o">=</span> <span class="vi">@base_content_dir</span> <span class="k">if</span> <span class="vi">@base_content_dir</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Presta atenção na linha do teardown que restaura <code>@base_content_dir</code>. Sem ela, o próximo teste criaria seu diretório <strong>dentro</strong> do diretório do teste anterior — <code>tmp/test_content_w3/abc123/def456/</code> — e em 50 testes você teria um caminho com 50 níveis de profundidade. Aprendi isso perdendo uma tarde inteira debugando por que os testes ficavam cada vez mais lentos ao longo da suite.</p>
<p>Esse padrão — worker-level base + per-test subdirectory + restore no teardown — é idêntico nos dois apps. E é o que permite rodar 977 testes em 7 segundos com 32 workers paralelos.</p>
<p>A regra de ouro: <strong>o <code>content_dir</code> de teste NUNCA pode apontar pro <code>../content</code> real</strong>. Se apontar, o <code>rm_rf</code> do teardown apaga os prompts de produção. Não é hipotético — aconteceu durante o desenvolvimento.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/frankmd/2026/02/screenshot-2026-02-20_12-24-08.jpg" alt="unit tests newsletter"  loading="lazy" /></p>
<h2>Camada 2: O Ambiente de Integração<span class="hx:absolute hx:-mt-20" id="camada-2-o-ambiente-de-integração"></span>
    <a href="#camada-2-o-ambiente-de-integra%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Testes unitários mockam tudo: APIs externas, AI, Discord, SES. Isso é correto — você não quer gastar $2 em tokens do GPT-5.2 toda vez que roda <code>bin/rails test</code>. Mas significa que os testes nunca exercitam o pipeline real.</p>
<p>O projeto tem um terceiro environment além de development e test: <strong>integration</strong>. Não é test. Não é staging. É um modo específico pra rodar o pipeline completo com dados reais, usando APIs reais, mas sem mandar emails de verdade:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="c1"># config/environments/integration.rb</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Jobs rodam inline (perform_later vira perform_now)</span>
</span></span><span class="line"><span class="cl"><span class="n">config</span><span class="o">.</span><span class="n">active_job</span><span class="o">.</span><span class="n">queue_adapter</span> <span class="o">=</span> <span class="ss">:inline</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Emails salvos em arquivo ao invés de enviados via SES</span>
</span></span><span class="line"><span class="cl"><span class="n">config</span><span class="o">.</span><span class="n">action_mailer</span><span class="o">.</span><span class="n">delivery_method</span> <span class="o">=</span> <span class="ss">:file</span>
</span></span><span class="line"><span class="cl"><span class="n">config</span><span class="o">.</span><span class="n">action_mailer</span><span class="o">.</span><span class="n">file_settings</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="ss">location</span><span class="p">:</span> <span class="no">Rails</span><span class="o">.</span><span class="n">root</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="s2">&#34;tmp/integration_emails&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>O <code>queue_adapter = :inline</code> é crucial. Em produção, <code>perform_later</code> enfileira o job no SolidQueue e um worker separado executa. Em integração, executa <strong>na hora, no mesmo processo</strong>. Isso transforma o pipeline assíncrono de produção num pipeline síncrono que você pode rodar, observar, e debugar sequencialmente.</p>
<p>O SES é substituído por escrita em disco — cada email vira um arquivo HTML em <code>tmp/integration_emails/</code>. Depois de rodar o pipeline, você abre esses HTMLs no browser pra validar visualmente que o email renderiza correto.</p>
<h2>Camada 3: DevCache — LLM Não É Idempotente<span class="hx:absolute hx:-mt-20" id="camada-3-devcache--llm-não-é-idempotente"></span>
    <a href="#camada-3-devcache--llm-n%c3%a3o-%c3%a9-idempotente" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Aqui está um problema que quem trabalha com IA em produção conhece: chamar o GPT-5.2 com o mesmo prompt duas vezes <strong>não retorna a mesma resposta</strong>. E cada chamada custa dinheiro. Se você está iterando no pipeline de integração — rodando, ajustando um prompt, rodando de novo — gastar $3 por iteração fica caro rápido.</p>
<p>A solução é o <code>DevCache</code>: um cache file-based que só ativa no env de integração:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">module</span> <span class="nn">DevCache</span>
</span></span><span class="line"><span class="cl">  <span class="no">CACHE_TTL</span> <span class="o">=</span> <span class="mi">1</span><span class="o">.</span><span class="n">day</span>
</span></span><span class="line"><span class="cl">  <span class="no">CACHE_ENVS</span> <span class="o">=</span> <span class="sx">%w[integration]</span><span class="o">.</span><span class="n">freeze</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">fetch</span><span class="p">(</span><span class="n">namespace</span><span class="p">,</span> <span class="n">key</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="k">yield</span> <span class="k">unless</span> <span class="n">enabled?</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">path</span> <span class="o">=</span> <span class="n">cache_path</span><span class="p">(</span><span class="n">namespace</span><span class="p">,</span> <span class="n">key</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">path</span><span class="o">.</span><span class="n">exist?</span> <span class="o">&amp;&amp;</span> <span class="no">File</span><span class="o">.</span><span class="n">mtime</span><span class="p">(</span><span class="n">path</span><span class="p">)</span> <span class="o">&gt;</span> <span class="no">CACHE_TTL</span><span class="o">.</span><span class="n">ago</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="no">JSON</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">path</span><span class="o">.</span><span class="n">read</span><span class="p">,</span> <span class="ss">symbolize_names</span><span class="p">:</span> <span class="kp">true</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">result</span> <span class="o">=</span> <span class="k">yield</span>
</span></span><span class="line"><span class="cl">    <span class="n">path</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="no">JSON</span><span class="o">.</span><span class="n">generate</span><span class="p">(</span><span class="n">result</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="n">result</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Em produção e em test, <code>DevCache.fetch</code> executa o bloco direto. Em integração, salva o resultado como JSON e retorna o cached na próxima execução. TTL de 1 dia — suficiente pra iterar no mesmo dia sem recalcular, curto o bastante pra não servir dados velhos.</p>
<p>O código de geração usa assim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="n">summary</span> <span class="o">=</span> <span class="no">DevCache</span><span class="o">.</span><span class="n">fetch</span><span class="p">(</span><span class="s2">&#34;summarize&#34;</span><span class="p">,</span> <span class="n">url_key</span><span class="p">)</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">  <span class="no">AiChat</span><span class="o">.</span><span class="n">summarize</span><span class="p">(</span><span class="n">article</span><span class="o">[</span><span class="ss">:content</span><span class="o">]</span><span class="p">,</span> <span class="ss">source_url</span><span class="p">:</span> <span class="n">url</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Primeira execução: chama o GPT-5.2, paga $0.02, salva em <code>tmp/dev_cache/summarize/{md5}.json</code>. Segunda execução: lê do cache, custo zero. O <code>FORCE=1</code> busta o cache quando você quer forçar regeneração — mas como flag explícita, não como default.</p>
<p>O DevCache existe em ambos os apps (marvin-bot e newsletter) com implementação idêntica. Quando roda <code>integration:clean</code>, ambos os caches são limpos.</p>
<p>Ponto: <strong>cache de LLM em ambiente de desenvolvimento não é otimização — é requisito</strong>. Sem ele, iterar num prompt que precisa de 8 chamadas de API fica financeiramente inviável.</p>
<h2>Camada 4: Dados Reais via Rsync<span class="hx:absolute hx:-mt-20" id="camada-4-dados-reais-via-rsync"></span>
    <a href="#camada-4-dados-reais-via-rsync" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Aqui é onde a maioria dos projetos para. Eles têm testes unitários, talvez um ambiente de staging, e mandam pro ar. O problema: staging usa dados de teste. Dados de teste são <strong>limpos demais</strong>. Não têm os edge cases que dados reais têm:</p>
<ul>
<li>Artigos com títulos em japonês (anime ranking)</li>
<li>URLs que redirecionam 3 vezes antes de chegar no destino</li>
<li>Imagens que retornam 200 com Content-Type <code>text/html</code> (CloudFlare error page)</li>
<li>Newsletters anteriores com formatos de frontmatter ligeiramente diferentes</li>
<li>Stories com <code>score: null</code> porque foram criadas antes de o campo existir</li>
</ul>
<p>A solução: <strong>rsync de produção</strong>.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Limpa conteúdo gerado (preserva stories e imagens de produção)</span>
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> marvin-bot <span class="o">&amp;&amp;</span> bin/rails integration:clean
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Sincroniza content/ de produção pra local</span>
</span></span><span class="line"><span class="cl">rsync -avz --delete production:/path/to/content/ ../content/
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Roda o pipeline completo com dados reais</span>
</span></span><span class="line"><span class="cl"><span class="nv">RAILS_ENV</span><span class="o">=</span>integration bin/rails integration:pipeline</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>O <code>integration:clean</code> é cirúrgico: remove diretórios gerados (<code>anime/</code>, <code>hacker_news/</code>, <code>newsletters/</code>, <code>podcasts/</code>) mas preserva <code>stories/</code> e <code>images/</code> — que são dados submetidos pelo usuário via Discord. Depois do rsync, o diretório local é uma cópia exata da produção.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/frankmd/2026/02/screenshot-2026-02-20_12-25-37.jpg" alt="cleanup"  loading="lazy" /></p>
<p>O pipeline então gera todas as seções a partir desses dados reais. Se um parser quebra com um título em coreano, você descobre aqui — não em produção às 17h de domingo quando os 8 jobs rodam em paralelo.</p>
<h2>Camada 5: O Pipeline Completo<span class="hx:absolute hx:-mt-20" id="camada-5-o-pipeline-completo"></span>
    <a href="#camada-5-o-pipeline-completo" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O coração do sistema de integração é o <code>integration:pipeline</code>. Ele simula a semana inteira de produção em uma execução:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nv">RAILS_ENV</span><span class="o">=</span>integration bin/rails integration:pipeline</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>O pipeline roda em ondas, respeitando dependências:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>Wave 1 (paralelo, 8 jobs):
  Book, Holidays, History, Geek History,
  Anime, Hacker News, YouTube, World Events

Wave 2 (depende de World Events):
  Market Recap

Wave 3 (depende de tudo):
  Closing Remarks

Preflight → Newsletter Assembly → Podcast</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/frankmd/2026/02/screenshot-2026-02-20_12-26-13.jpg" alt="waves"  loading="lazy" /></p>
<p>Cada wave roda seus jobs em threads paralelas, exatamente como a produção faz com SolidQueue. A execução paralela não é um detalhe de implementação — é uma feature de teste. Se dois jobs tentam escrever no mesmo arquivo, ou se um job lê um arquivo que outro está no meio de escrever, o bug aparece aqui.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="n">threads</span> <span class="o">=</span> <span class="n">to_run</span><span class="o">.</span><span class="n">map</span> <span class="k">do</span> <span class="o">|</span><span class="nb">name</span><span class="p">,</span> <span class="n">klass</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">  <span class="no">Thread</span><span class="o">.</span><span class="n">new</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Base</span><span class="o">.</span><span class="n">connection_pool</span><span class="o">.</span><span class="n">with_connection</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">      <span class="n">run_single_job</span><span class="p">(</span><span class="nb">name</span><span class="p">,</span> <span class="n">klass</span><span class="p">,</span> <span class="n">target_date</span><span class="p">,</span> <span class="n">results</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="n">threads</span><span class="o">.</span><span class="n">each</span><span class="p">(</span><span class="o">&amp;</span><span class="ss">:join</span><span class="p">)</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>O <code>with_connection</code> é necessário porque cada thread precisa de sua própria conexão SQLite — sem ele, conexões vazam e o pool esgota.</p>
<p>Ao final, o pipeline imprime uma tabela de status e um resumo de billing:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/frankmd/2026/02/screenshot-2026-02-20_12-34-56.jpg" alt="billing"  loading="lazy" /></p>
<p>Esse billing summary não é vaidade — é controle de custos. Se um prompt refatorado aumenta o output tokens em 3x, você vê aqui antes de ir pra produção e gastar 10x num domingo com 200 stories.</p>
<h2>Camada 6: Preflight — Validação Estrutural Automatizada<span class="hx:absolute hx:-mt-20" id="camada-6-preflight--validação-estrutural-automatizada"></span>
    <a href="#camada-6-preflight--valida%c3%a7%c3%a3o-estrutural-automatizada" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Depois de gerar todas as seções, o pipeline roda o <code>ContentPreflight</code>. Ele não valida o <em>conteúdo</em> — valida a <em>estrutura</em>. Cada seção é checada:</p>
<ul>
<li><strong>Arquivo existe?</strong> Se <code>content/anime/2026-02-16.md</code> não existe, algo falhou.</li>
<li><strong>Item count mínimo?</strong> A seção de anime precisa de pelo menos 3 itens. Se tem 1, o gerador teve um problema.</li>
<li><strong>Markers obrigatórios?</strong> O Markdown precisa ter <code>[COMMENTARY]</code> e <code>[AKITA]</code> — sem eles, a newsletter assembly não sabe onde cortar.</li>
<li><strong>Dados específicos?</strong> Market recap precisa de pelo menos 5 ticker rows.</li>
</ul>
<p>O resultado é um status por seção: <code>pass</code>, <code>degraded</code>, <code>fail</code>, ou <code>skip</code>. O pipeline usa isso pra decidir se a newsletter pode ser montada automaticamente ou se precisa de intervenção humana:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/frankmd/2026/02/screenshot-2026-02-20_12-36-19.jpg" alt="preflight"  loading="lazy" /></p>
<p>Em produção, esse resultado vai pro Discord como um embed. No pipeline de integração, é printado no terminal. A lógica é a mesma — o que muda é o canal de notificação.</p>
<h2>Camada 7: Cross-App — Newsletter Assembly<span class="hx:absolute hx:-mt-20" id="camada-7-cross-app--newsletter-assembly"></span>
    <a href="#camada-7-cross-app--newsletter-assembly" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Aqui está onde o monorepo paga dividendos. O marvin-bot precisa invocar o newsletter pra montar a newsletter final. Em produção, são servidores diferentes. No pipeline de integração, é um <code>system()</code> call:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="n">env_vars</span> <span class="o">=</span> <span class="s2">&#34;RAILS_ENV=integration CONTENT_DIR=</span><span class="si">#{</span><span class="no">Shellwords</span><span class="o">.</span><span class="n">escape</span><span class="p">(</span><span class="n">content_dir</span><span class="p">)</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">cmd</span> <span class="o">=</span> <span class="s2">&#34;cd </span><span class="si">#{</span><span class="n">newsletter_dir</span><span class="si">}</span><span class="s2"> &amp;&amp; </span><span class="si">#{</span><span class="n">env_vars</span><span class="si">}</span><span class="s2"> bin/rails integration:generate_all&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">system</span><span class="p">(</span><span class="n">cmd</span><span class="p">)</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/frankmd/2026/02/screenshot-2026-02-20_12-38-17.jpg" alt="assembly"  loading="lazy" /></p>
<p>O newsletter lê os arquivos que o marvin-bot acabou de gerar em <code>content/</code>, monta a newsletter, e salva o resultado em <code>content/newsletters/</code>. O CONTENT_DIR é passado explicitamente — os dois apps apontam pro mesmo diretório.</p>
<p>Se o formato do frontmatter mudou e o newsletter não consegue parsear, o erro aparece aqui. Se o <code>SectionParser</code> do newsletter divergiu do <code>SectionParser</code> do marvin-bot (são cópias idênticas, mas manuais), aqui é onde você descobre.</p>
<p>Depois da newsletter, o podcast: o pipeline invoca <code>podcast:integration</code>, que gera o script de diálogo a partir da newsletter montada, sintetiza o áudio via TTS, e monta o MP3 final. É o pipeline mais longo — de newsletter Markdown a MP3 pronto pro Spotify, passando por LLM de duas passadas e síntese de voz por turn.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/frankmd/2026/02/screenshot-2026-02-20_12-47-52.jpg" alt="tts"  loading="lazy" /></p>
<h2>O Valor de Testar com Dados de Produção<span class="hx:absolute hx:-mt-20" id="o-valor-de-testar-com-dados-de-produção"></span>
    <a href="#o-valor-de-testar-com-dados-de-produ%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Vou dar exemplos concretos de bugs que só apareceram com dados reais:</p>
<p><strong>1. Títulos de anime em japonês quebravam o slugify.</strong>
O <code>ContentWriter.slugify</code> usava <code>parameterize</code> do Rails, que strip caracteres non-ASCII. Título: &ldquo;進撃の巨人 Season 4&rdquo; → slug: &ldquo;season-4&rdquo;. Dois animes com subtítulo &ldquo;Season 4&rdquo; collidiam no filesystem. Nunca apareceu em teste porque os fixtures usavam títulos em inglês.</p>
<p><strong>2. O parser de HackerNews assumia RSS, mas o feed mudou pra Atom.</strong>
<code>rss/channel/item</code> virou <code>feed/entry</code>. Testes unitários mockavam o XML. O parser em si nunca foi testado contra o feed real. Na integração com rsync do feed real, o parser retornou zero itens — detectado pelo preflight como <code>fail</code>.</p>
<p><strong>3. Yahoo Finance retornava 429 depois do 5º ticker.</strong>
O rate limiting não existia em teste (HTTP era mockado). Na integração real, os primeiros 5 tickers passavam, depois tudo falhava. A solução — sleep entre requests — nunca seria implementada sem dados reais revelando o problema.</p>
<p><strong>4. Imagens com URL válida mas Content-Type errado.</strong>
Uma CDN retornava 200 para URLs de imagem, mas com body HTML (Cloudflare error page). O <code>UrlValidator.reachable?</code> retornava <code>true</code>. O <code>ImageProcessor.download_image</code> baixava o HTML e tentava redimensionar. O mini_magick crashava com um erro obscuro. O fix: validar Content-Type no HEAD response — mas esse cenário nunca apareceria com URLs mockadas.</p>
<p><strong>5. O newsletter assembly falhava com stories que tinham <code>score: null</code>.</strong>
Stories antigas, criadas antes do campo <code>score</code> ter um default, tinham <code>nil</code> no frontmatter. O assembly tentava fazer <code>sort_by { |s| s[:frontmatter][&quot;score&quot;] }</code> — <code>nil &lt;=&gt; &quot;high&quot;</code> levanta <code>ArgumentError</code>. Só apareceu quando rsynquei dados de produção que tinham 3 meses de stories acumuladas.</p>
<p>Nenhum desses bugs seria pego por teste unitário. Todos foram pegos pelo pipeline de integração com dados reais.</p>
<h2>Dicas Práticas<span class="hx:absolute hx:-mt-20" id="dicas-práticas"></span>
    <a href="#dicas-pr%c3%a1ticas" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><h3>1. Separe Custo de Fidelidade<span class="hx:absolute hx:-mt-20" id="1-separe-custo-de-fidelidade"></span>
    <a href="#1-separe-custo-de-fidelidade" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>O pipeline de integração completo custa ~$0.40 em API calls. Não é muito, mas se você roda 10 vezes num dia iterando, são $4. O DevCache resolve isso: primeira execução paga, as seguintes são grátis.</p>
<p>Mas tem cenários onde você <strong>quer</strong> pagar de novo — quando muda um prompt e precisa ver o resultado real. O <code>FORCE=1</code> busta o cache seletivamente. E o <code>SKIP_EXISTING=1</code> pula seções que já foram geradas, economizando tempo quando você só quer re-rodar uma seção específica.</p>
<h3>2. O Integration Environment Não É Staging<span class="hx:absolute hx:-mt-20" id="2-o-integration-environment-não-é-staging"></span>
    <a href="#2-o-integration-environment-n%c3%a3o-%c3%a9-staging" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Staging é um servidor que roda 24/7 simulando produção. O integration environment é um <strong>modo de execução local</strong> que você liga quando precisa e desliga quando terminou. Não precisa de infraestrutura dedicada. Não precisa de database separado. É o mesmo código, na mesma máquina, com flags diferentes.</p>
<p>A diferença é filosófica: staging testa &ldquo;o sistema funciona no servidor de staging?&rdquo;. Integration testa &ldquo;o sistema funciona <strong>com esses dados específicos</strong>?&rdquo;. O primeiro é environment-dependent. O segundo é data-dependent. E bugs de dados são mais comuns que bugs de environment.</p>
<h3>3. Clean Antes de Rsync, Não Depois<span class="hx:absolute hx:-mt-20" id="3-clean-antes-de-rsync-não-depois"></span>
    <a href="#3-clean-antes-de-rsync-n%c3%a3o-depois" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>A ordem importa: limpe o conteúdo gerado <strong>antes</strong> de sincronizar de produção. Se fizer o contrário — rsync primeiro, clean depois — você perde os dados de produção que acabou de baixar.</p>
<p>O <code>integration:clean</code> é cirúrgico por design. Remove anime/, hacker_news/, newsletters/ (gerados), mas preserva stories/ e images/ (produção). Isso permite um workflow iterativo: rsync uma vez, roda o pipeline, ajusta um prompt, roda de novo — sem re-baixar 500MB de content.</p>
<h3>4. Preflight É Seu Smoke Test<span class="hx:absolute hx:-mt-20" id="4-preflight-é-seu-smoke-test"></span>
    <a href="#4-preflight-%c3%a9-seu-smoke-test" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Não confie que &ldquo;rodou sem exceção = está correto&rdquo;. Um job de geração pode rodar, produzir um Markdown com 2 itens ao invés de 10, e retornar sucesso. O preflight detecta isso verificando contagens mínimas, markers obrigatórios, e estrutura esperada.</p>
<p>Na prática, todo bug de LLM que encontrei foi detectado pelo preflight: respostas truncadas, formato errado, seções faltando. O GPT-5.2 é bom, mas não é determinístico — e quando erra, erra de formas criativas que nenhum schema validation pegaria.</p>
<h3>5. Billing Summary Não É Opcional<span class="hx:absolute hx:-mt-20" id="5-billing-summary-não-é-opcional"></span>
    <a href="#5-billing-summary-n%c3%a3o-%c3%a9-opcional" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Se você está usando LLM em produção, <strong>todo</strong> pipeline de teste precisa reportar custo. Não por contabilidade — por engenharia. Um prompt que funciona mas custa 3x mais que o anterior é um bug de performance. Tokens de input e output por provider, custo por job, custo total — tudo visível a cada execução.</p>
<h3>6. Monorepo Facilita, Mas Não Resolve<span class="hx:absolute hx:-mt-20" id="6-monorepo-facilita-mas-não-resolve"></span>
    <a href="#6-monorepo-facilita-mas-n%c3%a3o-resolve" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Ter os três apps no mesmo repositório facilita: um <code>git bisect</code> cobre mudanças em ambos os lados do contrato. Um PR que muda o formato do frontmatter no marvin-bot <strong>pode</strong> também atualizar o parser no newsletter — no mesmo commit.</p>
<p>Mas &ldquo;pode&rdquo; não é &ldquo;garante&rdquo;. O contrato entre os apps é file-based e implícito. Não tem tipo compartilhado, não tem interface comum. O <code>SectionParser</code> é copiado manualmente entre os dois apps. Se alguém edita um e esquece do outro, divergem. O teste de integração é a <strong>única</strong> verificação de que os dois lados concordam.</p>
<h3>7. Preview Antes de Enviar<span class="hx:absolute hx:-mt-20" id="7-preview-antes-de-enviar"></span>
    <a href="#7-preview-antes-de-enviar" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>O pipeline não termina na geração. O newsletter tem um <code>newsletter:preview</code> que renderiza o resultado final em HTML light e dark:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">cd</span> newsletter
</span></span><span class="line"><span class="cl"><span class="nv">FILE</span><span class="o">=</span>../content/newsletters/2026-02-16.md bin/rails newsletter:preview
</span></span><span class="line"><span class="cl"><span class="c1"># → tmp/preview/newsletter_light.html</span>
</span></span><span class="line"><span class="cl"><span class="c1"># → tmp/preview/newsletter_dark.html</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Abrir esses HTMLs no browser é o teste de integração visual. O Markdown pode estar perfeito, o frontmatter correto, todos os campos presentes — mas a imagem de um anime aparece esticada porque o aspect ratio mudou. Ou o bloco de comentário do Marvin não tem contraste suficiente no dark mode. Esses bugs são visuais — nenhum teste automatizado pega.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/frankmd/2026/02/screenshot-2026-02-20_12-48-32.jpg" alt="final assembly"  loading="lazy" /></p>
<h3>8. O Pipeline de CI É Diferente do Pipeline de Integração<span class="hx:absolute hx:-mt-20" id="8-o-pipeline-de-ci-é-diferente-do-pipeline-de-integração"></span>
    <a href="#8-o-pipeline-de-ci-%c3%a9-diferente-do-pipeline-de-integra%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>São coisas diferentes. CI roda em todo commit:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">bin/ci  <span class="c1"># rubocop + bundler-audit + brakeman + tests (~22s)</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Integração roda quando você quer validar o pipeline end-to-end — antes de um deploy, depois de mudar prompts, ou depois de rsync de dados novos de produção. CI é rápido e barato. Integração é lento e custa dinheiro. Os dois são necessários.</p>
<h2>O Custo de Não Ter Integração<span class="hx:absolute hx:-mt-20" id="o-custo-de-não-ter-integração"></span>
    <a href="#o-custo-de-n%c3%a3o-ter-integra%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Vou ser direto: se esse projeto não tivesse o pipeline de integração, eu teria enviado pelo menos 3 newsletters quebradas.</p>
<p>Uma com seção de anime faltando porque o parser de XML assumia RSS e o feed era Atom. Uma com todas as imagens de YouTube apontando pra 404 porque o padrão de URL de thumbnail mudou. E uma com o market recap mostrando tickers do mês passado porque o Yahoo Finance bloqueou as requests e o job falhou silenciosamente.</p>
<p>Testes unitários teriam passado em todos esses cenários. O CI teria dado verde. O deploy teria ido pro ar. E às 7 da manhã de segunda-feira, 300 pessoas teriam recebido uma newsletter com buracos.</p>
<p>O pipeline de integração é caro — em tempo de setup, em custo de API, em complexidade de manutenção. Mas é ordens de magnitude mais barato que enviar conteúdo quebrado pra assinantes reais. Especialmente quando você só tem uma chance por semana.</p>
<h2>Conclusão<span class="hx:absolute hx:-mt-20" id="conclusão"></span>
    <a href="#conclus%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A hierarquia de testes nesse projeto é:</p>
<ol>
<li><strong>Testes unitários</strong> (1.330 nos dois apps, 7 segundos em paralelo, $0): prova que cada peça funciona isolada</li>
<li><strong>CI pipeline</strong> (rubocop + audit + brakeman + tests, ~22 segundos, $0): prova que o código está saudável</li>
<li><strong>Pipeline de integração</strong> (dados reais, APIs reais, ~3 minutos, ~$0.40): prova que o <strong>sistema</strong> funciona</li>
<li><strong>Preview visual</strong> (HTML no browser, manual, $0): prova que o resultado final é apresentável</li>
</ol>
<p>Cada camada pega um tipo diferente de bug. Nenhuma sozinha é suficiente. E a que mais surpreende — a que pega os bugs que você jurava que não existiam — é a terceira: dados reais, pipeline real, sem mocks.</p>
<p>A confiança que você tem no seu sistema é proporcional ao quão reais são os dados nos seus testes. Mocka tudo e você tem 100% de coverage e zero de confiança. Testa com dados de produção e você tem a verdade — por mais inconveniente que seja.</p>
]]></content:encoded><category>the-m-akita-chronicles</category><category>testes</category><category>engenharia-de-software</category></item><item><title>Vibe Code: Eu fiz um appzinho 100% com GLM 4.7 (TV Clipboard)</title><link>https://akitaonrails.github.io/2026/01/28/vibe-code-eu-fiz-um-appzinho-100-com-glm-4-7-tv-clipboard/</link><guid isPermaLink="true">https://akitaonrails.github.io/2026/01/28/vibe-code-eu-fiz-um-appzinho-100-com-glm-4-7-tv-clipboard/</guid><pubDate>Wed, 28 Jan 2026 08:41:52 -0300</pubDate><description>&lt;p&gt;Ontem eu postei o seguinte no X:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://x.com/AkitaOnRails/status/2016175111414452636"target="_blank" rel="noopener"&gt;&lt;img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260128084349_screenshot-2026-01-28_08-43-38.png" alt="tweet" loading="lazy" /&gt;&lt;/a&gt;
Isso é um conceito que falei múltiplas vezes nos vídeos do meu canal e em palestras. Tudo em programação acontece mais ou menos na proporção de Pareto: 80/20:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;80% do código é &amp;ldquo;fácil&amp;rdquo; e normalmente feito em 20% do tempo. Os 20% mais importantes vão ocupar a maioria dos 80% do tempo total.&lt;/li&gt;
&lt;li&gt;Bugs e problemas como performance ou segurança, se consertar os top 20%, vai resolver 80% dos problemas gerais.&lt;/li&gt;
&lt;li&gt;20% do escopo é realmente importante, por isso sempre dá pra simplificar, substituir, mudar, ou até cortar 80% - e é assim que se ajusta um projeto pra caber em orçamento/prazo.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Tudo é baseado em Top X. &lt;a href="https://akitaonrails.com/2018/09/18/akitando-11-projetos-aprendendo-a-priorizar/"target="_blank" rel="noopener"&gt;Aprender a priorizar&lt;/a&gt; é aprender a identificar os 20%. A diferença de alguém sênior/experiente vs alguém amador/iniciante, é que iniciantes acham que 100% é importante e não conseguem decidir os 20%. O que a experiência traz é a capacidade de cada vez separar mais rápido esses 20%.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Ontem eu postei o seguinte no X:</p>
<p><a href="https://x.com/AkitaOnRails/status/2016175111414452636"target="_blank" rel="noopener"><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260128084349_screenshot-2026-01-28_08-43-38.png" alt="tweet"  loading="lazy" /></a>
Isso é um conceito que falei múltiplas vezes nos vídeos do meu canal e em palestras. Tudo em programação acontece mais ou menos na proporção de Pareto: 80/20:</p>
<ul>
<li>80% do código é &ldquo;fácil&rdquo; e normalmente feito em 20% do tempo. Os 20% mais importantes vão ocupar a maioria dos 80% do tempo total.</li>
<li>Bugs e problemas como performance ou segurança, se consertar os top 20%, vai resolver 80% dos problemas gerais.</li>
<li>20% do escopo é realmente importante, por isso sempre dá pra simplificar, substituir, mudar, ou até cortar 80% - e é assim que se ajusta um projeto pra caber em orçamento/prazo.</li>
</ul>
<p>Tudo é baseado em Top X. <a href="https://akitaonrails.com/2018/09/18/akitando-11-projetos-aprendendo-a-priorizar/"target="_blank" rel="noopener">Aprender a priorizar</a> é aprender a identificar os 20%. A diferença de alguém sênior/experiente vs alguém amador/iniciante, é que iniciantes acham que 100% é importante e não conseguem decidir os 20%. O que a experiência traz é a capacidade de cada vez separar mais rápido esses 20%.</p>
<p><strong>PORÉM</strong>, é muito fácil só dizer isso. Todo mundo já ouviu isso pelo menos uma vez na vida, mas provavelmente ainda não consegue entender o que significa. Por isso resolvi fazer este (LONGO) artigo: vou mostrar <strong>na prática</strong> o que são os 80% fáceis e os 20% difíceis e como isso realmente afeta a qualidade do código, o tempo gasto e o custo.</p>
<p>Este artigo é para iniciantes, principalmente, mas também pra você: sênior que tem júniors pra mentorar ou professores com alunos. Usem como material de discussão e estudo com seus aprendizes. Esse é o tipo de coisa que se deve ensinar.</p>
<p>Como vai ser longo, lembrem-se que na versão desktop, do lado direito 👉 tem um menu com as seções pra pular direto pra cada assunto e estudar aos poucos.</p>
<h2>O App: TV Clipboard<span class="hx:absolute hx:-mt-20" id="o-app-tv-clipboard"></span>
    <a href="#o-app-tv-clipboard" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Escolhi um appzinho que eu queria faz tempo pro meu uso pessoal. É mais simples que um to-do list, não precisa de banco de dados nem nenhum outro serviço externo. Na prática é um comunicador peer-to-peer (p2p) via websockets.</p>
<p>O caso de uso é o seguinte: eu tenho um mini-PC gamer que conecto na TV da sala. Normalmente deixo um mouse do lado da poltrona pra navegar nele (é um maldito Windows 11). Mas eventualmente eu preciso digitar alguma coisa (senhas, preencher algum formulário). E eu não quero deixar minhas contas importantes logadas nesse PC (não confio em PC gamer).</p>
<p>Ou eu tenho que pegar meu teclado bluetooth, ou usar o teclado virtual do Windows. Ambas as opções são inconvenientes pra uma sala. MAS, e se eu pudesse abrir um site (que já vai estar no bookmark), aparece um QR Code que eu abro via meu smartphone e dali posso digitar ou colar o que está no meu clipboard mobile e transferir pro clipboard do mini-PC imediatamente? Esse é o app:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260128090208_20260127_192137.jpg" alt="tvclipboard host screen"  loading="lazy" /></p>
<p>Daí eu abro a câmera do meu celular, escaneio esse QR Code e ele vai abrir esta página:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260128090700_Screenshot_20260128_090600_Brave.jpg" alt="tvclipboard client screen"  loading="lazy" /></p>
<p>Pronto, agora posso digitar qualquer coisa ou colar a senha do meu gerenciador de senhas (clicando em &ldquo;paste&rdquo;) e quando enviar, na TV vou ver o seguinte:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260128090907_20260127_195954.jpg" alt="tvclipboard host received screen"  loading="lazy" /></p>
<p>Vai aparecer que recebi, e automaticamente já vai pro clipboard da TV. Ele mostra &ldquo;blurred&rdquo; porque se for uma senha não quero que fique legível grande na TV - e sim, o mouse é gigante porque é mais fácil de eu ver na TV.</p>
<p>Isso é útil não só pra TV, mas pra qualquer situação onde eu queira mandar textos do meu celular pra um dos meus PCs também. Muita gente acaba usando WhatsApp ou outros comunicadores pra isso. Eu, por exemplo, tenho um grupo &ldquo;Só eu&rdquo; que só tem eu nele, pra ficar mandando links e coisas bobas do meu celular. Daí eu sempre deixo o WhatsApp Web aberto numa aba do meu PC e posso pegar de lá. WhatsApp pra mim é um clipboard remoto.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260128091222_screenshot-2026-01-28_09-12-13.png" alt="whatsapp só eu"  loading="lazy" /></p>
<p>Mas isso não é seguro pra mandar coisas como senhas, endereços de cripto, ou qualquer outra mensagem mais sensível. WhatsApp é uma empresa sem nenhuma transparência. A propaganda &ldquo;diz&rdquo; que eles têm encriptação de ponta a ponta, mas eu não acredito nisso. É igualmente provável que eles abram tudo no meio do caminho e deixem registrado - são dados que valem dinheiro, ainda mais nesta era de treinamento de LLMs.</p>
<blockquote>
  <p>Recomendação: NUNCA COMUNIQUE NADA IMPORTANTE VIA WHATSAPP.</p>

</blockquote>
<p>Pra transferir arquivos eu já uso <a href="https://localsend.org/pt-BR"target="_blank" rel="noopener"><strong>LocalSend</strong></a>:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260128091432_screenshot-2026-01-28_09-00-27.png" alt="localsend"  loading="lazy" /></p>
<p>Daí que veio a inspiração: eu queria um LocalSend pra Clipboard. Eu tenho certeza que já existam dezenas de apps que fazem exatamente isso. Mas aí eu queria aproveitar pra fazer este exercício.</p>
<h2>O Plano: 100% Vibe Code<span class="hx:absolute hx:-mt-20" id="o-plano-100-vibe-code"></span>
    <a href="#o-plano-100-vibe-code" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Honestamente, eu sei o suficiente de front-end, comecei minha carreira sendo &ldquo;web master&rdquo; nos anos 90. Mas eu detesto front-end. É demorado, é trabalhoso, yuck. Em particular, detesto lidar com CSS. Em mais particular, não tenho prazer em fazer Javascript. Por isso, sempre tenho preguiça de começar um web app do zero. Mas com Vibe Coding, essa é uma das partes que eu já posso me livrar, especialmente se eu não me importo com a aparência exata que vai ficar, contanto que não fique torto.</p>
<p>Aproveitando, vou usar uma linguagem que eu sei o básico mas não tenho nem experiência suficiente e muito menos fluência (ou seja, sozinho eu seria lento): <strong>GoLang</strong>. Por que Go:</p>
<ul>
<li>compila binário nativo: eu nem preciso da performance mas ter um compilador vai ajudar a LLM ter feedback de erros óbvios.</li>
<li>sem dependências: depois vou querer fazer deploy no meu home server, e vai ser infinitamente mais fácil fazer o setup de docker com um binário sem dependências, comparado com um Ruby ou Python que tem que instalar muita coisa.</li>
<li>ferramental padrão completo: além de compilador ele já tem formatador, linter, testes e tudo mais que também vai dar bom feedback à LLM</li>
<li>sintaxe simples, curta e pouco ambígua. Gosto como Go é Python-like. Não considero nenhuma das duas &ldquo;bonitas&rdquo; (em termos de estética, eu prefiro muito mais um Swift, Kotlin ou Ruby). Mas diferente de Javascript e até mesmo Rust, é bem menos &ldquo;verbose&rdquo; e bem menos ambígua.</li>
<li>standard library rica. Diferente de Javascript, não precisa ficar instalando 500 libs externas pra coisas básicas.</li>
<li>como vou usar websockets, channels de GoLang vão facilitar minha vida. O mecanismo assíncrono dele é mais simples, robusto e melhor do que reactor de Node.</li>
<li>o mais importante: <strong>porque eu quero</strong>. É um projeto pessoal, que só eu vou usar, eu escolho o que bem entender e ponto final.</li>
</ul>
<p>Aliás, como eu não sou fluente em Go, provavelmente vou deixar passar alguma má prática ou anti-pattern óbvio. Se isso acontecer, você que é sênior de Go, não deixe de comentar abaixo explicando o que acha.</p>
<blockquote>
  <p>Se quiserem já ver como ficou, o código todo está <a href="https://github.com/akitaonrails/tvclipboard"target="_blank" rel="noopener">neste GitHub</a>. Eu vou ficar linkando trechos dele o tempo todo.</p>

</blockquote>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260128093018_screenshot-2026-01-27_19-27-29.png" alt="Crush"  loading="lazy" /></p>
<p>Outro objetivo é testar o quão bom o famoso <a href="https://z.ai/blog/glm-4.7"target="_blank" rel="noopener"><strong>GLM 4.7</strong></a> realmente é. Já escrevi posts e tweets sobre ele antes. Já tentei rodar a versão Flash no meu PC local (é bom, mas BEM lento). No geral, minha impressão é que ele tem qualidade similar a um Claude Opus, GPT Codex, Gemini, mas é BEM mais lento (no mínimo 2x mais lento). Significa que se eu tivesse usado Gemini ou Claude, chegaria no mesmo resultado, mas talvez levasse metade do tempo, porém com um custo maior de tokens (GLM é mais &ldquo;barato&rdquo;).</p>
<blockquote>
  <p>Vamos ao <strong>TL;DR</strong>: ele conseguiu implementar o app como eu queria, mas DEMOROU. Eu levei um dia inteiro, almoçando e jantando na frente do PC enquanto o Crush ficava pensando, um total de mais de <strong>10 HORAS</strong>. E, segundo o OpenRouter, gastei pouco mais de <strong>USD 40</strong> (mais de 200 reais). Não foi nem rápido nem barato, considerando o escopo do app. Lembrando: é mais simples que um To-Do List.</p>

</blockquote>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260128160317_screenshot-2026-01-28_16-02-19.png" alt="openrouter billing"  loading="lazy" /></p>
<p>Em termos de tamanho, mesmo um app simples destes deu <strong>mais de 3.000 linhas de código (LOC)</strong> de GoLang:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="o">===</span> Code <span class="nv">Statistics</span> <span class="o">===</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Total Go code: <span class="m">3493</span> lines
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Production code: <span class="m">1431</span> lines
</span></span><span class="line"><span class="cl">Test code: <span class="m">2062</span> lines
</span></span><span class="line"><span class="cl">Test ratio: 1.44:1
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Top <span class="m">10</span> largest files:
</span></span><span class="line"><span class="cl">  <span class="m">3493</span>  total
</span></span><span class="line"><span class="cl">  <span class="m">602</span>  ./pkg/server/server_test.go
</span></span><span class="line"><span class="cl">  <span class="m">560</span>  ./pkg/hub/hub_test.go
</span></span><span class="line"><span class="cl">  <span class="m">385</span>  ./pkg/token/token_test.go
</span></span><span class="line"><span class="cl">  <span class="m">304</span>  ./pkg/hub/hub.go
</span></span><span class="line"><span class="cl">  <span class="m">283</span>  ./pkg/server/server.go
</span></span><span class="line"><span class="cl">  <span class="m">263</span>  ./i18n/i18n.go
</span></span><span class="line"><span class="cl">  <span class="m">262</span>  ./pkg/config/config_test.go
</span></span><span class="line"><span class="cl">  <span class="m">253</span>  ./pkg/QR Code/QR Code_test.go
</span></span><span class="line"><span class="cl">  <span class="m">243</span>  ./pkg/config/config.go</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>E de Javascript deu <strong>mais de 1.000 LOC</strong>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="o">===</span> JavaScript Code <span class="nv">Statistics</span> <span class="o">===</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Total JavaScript code: <span class="m">1360</span> lines
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Production code: <span class="m">787</span> lines
</span></span><span class="line"><span class="cl">Test code: <span class="m">573</span> lines
</span></span><span class="line"><span class="cl">Test ratio: 0.73:1
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">All JavaScript files:
</span></span><span class="line"><span class="cl">  <span class="m">1360</span>  total
</span></span><span class="line"><span class="cl">  <span class="m">573</span>  static/js/test.js
</span></span><span class="line"><span class="cl">  <span class="m">313</span>  static/js/client.js
</span></span><span class="line"><span class="cl">  <span class="m">249</span>  static/js/host.js
</span></span><span class="line"><span class="cl">  <span class="m">114</span>  static/js/common.js
</span></span><span class="line"><span class="cl">  <span class="m">111</span>  static/js/i18n.js</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Ah sim, de curiosidade, adicionei scripts <code>loc.sh</code> e <code>loc-js.sh</code> pra fazer essa contagem.</p>
<h2>Fase 1: Fazendo &ldquo;Funcionar&rdquo; - o que isso significa?<span class="hx:absolute hx:-mt-20" id="fase-1-fazendo-funcionar---o-que-isso-significa"></span>
    <a href="#fase-1-fazendo-funcionar---o-que-isso-significa" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Diferente do que muitos amadores podem pensar, não basta digitar a descrição da aplicação (como eu fiz na seção anterior), como um prompt, jogar na LLM e ele vai automaticamente sair com um app que funciona: <strong>NÃO VAI</strong>.</p>
<p>É o que eu falava 2 anos atrás e continua sendo assim: não importa quanto mais as LLMs evoluírem. Eles podem ficar um pouco mais rápido, um pouco mais eficientes, mas a arquitetura ainda é a mesma desde 2022: transformers são geradores de texto glorificados, com um fator de sorteio aleatório que sempre vai embutir entropia no processo (nunca vai ser exato, determinístico). SEMPRE vai precisar de intervenção humana (e bastante).</p>
<p>Agora vou demonstrar com um exemplo real o que isso significa.</p>
<p>No final, eu parei este projeto depois de <strong>43 commits</strong>. Eu segui o processo que sempre digo que é o melhor: fazer prompts pequenos, uma funcionalidade de cada vez, checar que funciona e está correto, mandar fazer git commit e partir pra próxima funcionalidade ou requerimento.</p>
<blockquote>
  <p>Numa conta de padeiro, cada commit ficou pronto depois de uma meia dúzia de prompts, em média. Vamos dizer que foi então 43 commits x 6 prompts = quase <strong>258 prompts</strong> ao longo de mais de 12 horas. Alguns prompts foram uma frase simples que resolveu em 2 segundos. A maioria levava minutos e múltiplas iterações do agente (Crush).</p>

</blockquote>
<p>A janela de contexto do GLM 4.7 é média: uns 200 mil tokens. O Crush tem um mecanismo que quando chegar muito mais de 90% de uso, ele manda resumir o contexto até agora, pra poder resetar e recarregar desse resumo pra continuar. Mas ele ainda tem bugs e às vezes crasheia e perde o contexto:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260128094713_screenshot-2026-01-27_21-45-30.png" alt="crush bug"  loading="lazy" /></p>
<p>Aí eu preciso recuperar o último prompt, às vezes eu mesmo digitar parte do contexto que foi interrompido, pra ele conseguir continuar de onde parou. É trabalhoso e precisa ficar prestando atenção. Esse é um problema que um Gemini tem menos porque a janela de contexto dele é MUITO maior (mas a atenção no meio vai degradando, quanto maior vai ficando, é um trade-off).</p>
<blockquote>
  <p><em>&ldquo;Ah, o Akita só pode ser burro. Eu já fiz um app de Todo e não chegou nem perto de 250 prompts. Ele fez errado.&rdquo;</em></p>

</blockquote>
<p>Agora vamos começar a parte que separamos os meninos dos homens. De fato, pra <em>&ldquo;fazer funcionar&rdquo;</em> não precisa de tudo isso de prompts. Dos 43 commits que levaram 10+ horas, eu já tinha um app que <em>&ldquo;funcionava&rdquo;</em> depois de 10 commits pequenos, que levou cerca de 1 hora.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260128165251_screenshot-2026-01-28_16-52-34.png" alt="tvclipboard v0.1"  loading="lazy" /></p>
<p>Se quiserem ver a versão &ldquo;v0.1&rdquo;, basta fazer assim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">git clone https://github.com/akitaonrails/tvclipboard.git
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> tvclipboard
</span></span><span class="line"><span class="cl">git fetch --tags
</span></span><span class="line"><span class="cl">git checkout v0.1</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Esta versão tem <strong>1.827 LOC</strong> de GO e <strong>255 LOC</strong> de Javascript. Mas o backend Go mesmo tem só <strong>549 LOC</strong> vs <strong>1.431 LOC</strong> no final. E isso porque nesta versão mínima eu já adicionei testes unitários de backend (1.278 LOC), que a maioria dos iniciantes nunca coloca. Então daria pra &ldquo;resolver&rdquo; meu problema em pouco mais de 800 LOC, menos de 1 hora e meia dúzia de prompts.</p>
<p>A estrutura do projeto ficou assim. Guardem esta imagem pra comparar como vai ficar no final:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260128100103_screenshot-2026-01-28_09-53-39.png" alt="v0.1 tree"  loading="lazy" /></p>
<p>Nesta versão já abre o que eu chamo de página &ldquo;host&rdquo; que é a página que abriria na minha TV, mostrando o QR Code pra conectar. Já tem a página &ldquo;client&rdquo;, que é o que o QR Code vai abrir no meu celular. E já consegue colar texto no cliente, mandar pro host e copiar no clipboard dele. Bem simples.</p>
<blockquote>
  <p>É aqui que 99% das pessoas iriam parar e dar por completo.</p>

</blockquote>
<h2>Fase 2: Indo além de &ldquo;só funcionar&rdquo;<span class="hx:absolute hx:-mt-20" id="fase-2-indo-além-de-só-funcionar"></span>
    <a href="#fase-2-indo-al%c3%a9m-de-s%c3%b3-funcionar" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Vou repetir: este projeto é mais simples que um todo list e é feito exclusivamente pra somente eu usar, em casa, na minha rede local. Qualquer um que pensar <em>&ldquo;ah, isso tudo é desnecessário pra esse app&rdquo;</em> - <strong>EU SEI!</strong>.</p>
<p>A ideia é demonstrar o mínimo que se precisa pensar num <strong>projeto de verdade</strong>. Se estiver fazendo um brinquedo só pra você sozinho, tanto faz a qualidade.</p>
<p>Pra quem for sênior de Go, ou Javascript (porque vou usar no front), eu sei que vocês vão pensar <em>&ldquo;ah, ele deveria ter usado framework X ou biblioteca Y&rdquo;</em> - <strong>EU SEI!!</strong> 😅 No final vai ter uma seção onde vou discutir um pouco dessas outras opções, esperem antes de sair comentando!!</p>
<p>Voltando ao conceito de Pareto. Eu falei que 20% do trabalho mais importante custa 80% do tempo, mas isso é só uma ordem de grandeza. No meu exemplo, o projeto todo levou mais de 10 horas e &ldquo;pra funcionar&rdquo; levou só 1 hora. Então está mais pra 90/10 em vez de 80/20.</p>
<blockquote>
  <p>O que diabos custou 90% do tempo se em 10% &ldquo;já funcionava&rdquo;??</p>

</blockquote>
<h3>1. Gerenciamento de Tokens<span class="hx:absolute hx:-mt-20" id="1-gerenciamento-de-tokens"></span>
    <a href="#1-gerenciamento-de-tokens" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>A primeira coisa que eu penso quando vejo um QR Code é que o link dentro dela seja descartável e volátil. Não é uma regra e obviamente depende do app. Pro meu appzinho é sim &ldquo;overkill&rdquo; mas vou fazer pra dar de exemplo. (não vou ficar repetindo toda hora <em>&ldquo;sim, pro meu app não precisava&rdquo;</em>, esta é a última vez).</p>
<p>Eu não quero que uma visita que use meu app em casa consiga bookmarkar o link e conseguir usar fora daqui (eu vou expor meu serviço na internet pra conseguir usar de qualquer lugar depois). Eu quero que cada uso seja único e que expire depois de alguns minutos, exigindo um novo QR Code.</p>
<blockquote>
  <p>Portanto eu preciso de algum sistema de tokens que expira.</p>

</blockquote>
<p>Este artigo já vai ser muito longo, então não vou ficar copiando o código inteiro de cada funcionalidade. Vou sempre indicar o <a href="https://github.com/akitaonrails/tvclipboard/commit/05dd60290e1d2419855e2f79ed48326415641da8"target="_blank" rel="noopener">commit</a> onde implementei pra vocês pesquisarem depois e mostrar só trechos pra ilustrar.</p>
<p>Enfim, o objetivo vai ser ter uma URL como <code>http://clip.example.com/?token=blablabla</code>. Nada de outro mundo.</p>
<p>Sim, poderia ser um JWT, mas meu uso é muito simples então mandei fazer do zero e o GLM 4.7 inventou uma estrutura JSON com uma chave privada aleatória e um timestamp, que ele resolveu encriptar com AES (não precisava mesmo) e encodar em hexadecimal pra ser o token (fica hiper longo, mais de 100 caracteres).</p>
<p>Ficou um monstrinho assim:</p>
<p><a href="https://github.com/akitaonrails/tvclipboard/commit/05dd60290e1d2419855e2f79ed48326415641da8"target="_blank" rel="noopener"><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260128101314_screenshot-2026-01-28_10-13-04.png" alt="encrypt token"  loading="lazy" /></a></p>
<p>Eu não gostei mas resolvi deixar assim porque está funcionando. Eu posso mexer nisso mais tarde - inclusive, muita coisa foi feita &ldquo;fora de ordem&rdquo; porque eu fui fazendo à medida que ia lembrando. Não tinha um planejamento passo-a-passo escrito antes. Literalmente tirei da cabeça em tempo real mesmo.</p>
<blockquote>
  <p>O objetivo disso é lembrar que Gerenciamento de Sessão é uma preocupação que todo dev tem que ter na cabeça num sistema de verdade.</p>

</blockquote>
<h3>2. Primeiro Refatoramento<span class="hx:absolute hx:-mt-20" id="2-primeiro-refatoramento"></span>
    <a href="#2-primeiro-refatoramento" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>O código principal já estava com mais de 500 LOC, os testes com mais de 1000 LOC. Isso é muito grande pra ficar num arquivo só. Então pedi pro GLM refatorar em pacotes. Esse tipo de coisa eu sei que o Claude Code faz com mais facilidade, mas o GLM se saiu bem também. No final ficou algo assim:</p>
<p><a href="https://github.com/akitaonrails/tvclipboard/commit/dbbee593e99fbc6d8051884b016386289d17816b"target="_blank" rel="noopener"><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260128101636_screenshot-2026-01-28_10-16-29.png" alt="separation of concerns"  loading="lazy" /></a>
Isso é o que chamamos de <strong>&ldquo;Separation of Concerns&rdquo;</strong>. Cada pacote tem um domínio isolado. Um pacote pra lidar só com opções de configuração, outro pra cuidar só do servidor HTTP, outro pra lidar só com a geração de QR Code e outro pra lidar só com gerenciamento de Tokens. Cada um com testes unitários no mesmo pacote.</p>
<p>Pedir pra fazer testes desde o começo foi uma grande ajuda à LLM, porque vira e mexe ele rodava o teste, ficava confuso do porquê não funcionava e caia a ficha que precisava ajustar a implementação. Todo feedback automatizado é importante pra LLM ter contexto pra trabalhar.</p>
<p>E refatoramento não é algo que se faça apenas uma vez. É um processo que tem que ser feito de tempos em tempos pra consolidar e simplificar o código, melhorando a <strong>mantenabilidade</strong>.</p>
<blockquote>
  <p>O objetivo disso é lembrar que &ldquo;só porque funciona&rdquo;, não significa que o código fica congelado e não se mexe mais.</p>

</blockquote>
<h3>3. Suporte a Docker<span class="hx:absolute hx:-mt-20" id="3-suporte-a-docker"></span>
    <a href="#3-suporte-a-docker" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Como eu iria rodar no meu home server, suporte a Docker é obrigatório. Mas independente disso, é uma boa prática manter um <a href="https://github.com/akitaonrails/tvclipboard/blob/master/Dockerfile"target="_blank" rel="noopener"><code>Dockerfile</code></a> que funciona. É outro tipo de &ldquo;teste automatizado&rdquo;: ver se consegue &ldquo;buildar&rdquo; uma imagem e rodar. E documentar pra outro usuário que ele não precisa instalar nada no sistema dele pra rodar, basta rodar o Docker:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker run -d <span class="se">\
</span></span></span><span class="line"><span class="cl">  --name tvclipboard <span class="se">\
</span></span></span><span class="line"><span class="cl">  -p 3333:3333 <span class="se">\
</span></span></span><span class="line"><span class="cl">  akitaonrails/tvclipboard:latest</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Inclusive, o comando acima funciona, caso você queira testar imediatamente. Eu subi a imagem na minha conta no Docker Hub.</p>
<p>E se já não tinha implementado assim, isso também força que você adicione opções de configuração na forma de variáveis de ambiente (como <code>TVCLIPBOARD_SESSION_TIMEOUT</code>) ou via argumentos em linha de comando (como <code>--expires</code>), expondo o que é configurável.</p>
<blockquote>
  <p>O objetivo aqui é lembrar como é importante automatizar build e documentar como usar pra outras pessoas.</p>

</blockquote>
<h3>4. Organizar Javascript e adicionando Cache Busting<span class="hx:absolute hx:-mt-20" id="4-organizar-javascript-e-adicionando-cache-busting"></span>
    <a href="#4-organizar-javascript-e-adicionando-cache-busting" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Pra &ldquo;só funcionar&rdquo;, lá no começo, bastava fazer um &ldquo;index.html&rdquo; e ir escrevendo <code>if host</code> ou <code>if client</code> no meio do HTML e JS. Mas pelo menos o GLM iniciou duplicando um <code>host.html</code> e um <code>client.html</code>. Mas o javascript estava todo inline entre tags <code>&lt;script&gt;...&lt;/script&gt;</code> e duplicado nos dois arquivos, então outro passo de refatoração foi pedir pra ele separar <code>common.js</code>, <code>client.js</code>, <code>host.js</code>.</p>
<p>É o mínimo do mínimo de mantenabilidade. Novamente: refatoração não acaba num passo só.</p>
<p>Mas eu poderia esbarrar num problema. Sendo um sisteminha muito simples, não tenho nada de <strong>ETAGs</strong> implementado e nem asset pipeline como WebPack ou similares.</p>
<p>Num web framework dinâmico, a maioria vai ter suporte a gerar arquivos de CSS e JS dinamicamente mudando os nomes pra coisas como <code>/assets/host-20260128123456.js</code> e toda vez que editarmos algum JS, o pipeline vai regenerar esse arquivo com outro nome.</p>
<p>Quando abrimos num navegador web, ele vai sempre tentar &ldquo;cachear&rdquo; assets estáticos como imagens, JS, CSS, pra não ficar pedindo a mesma coisa toda hora. Se ele já baixou <code>host.js</code>, no próximo &ldquo;reload&rdquo;, se pedir o mesmo arquivo, basta pegar do cache em vez de pedir pro servidor de novo.</p>
<p>O problema disso é se mudarmos o conteúdo do arquivo e manter o mesmo nome. O navegador vai achar que é a mesma coisa e você vai ficar horas coçando a cabeça pensando <em>&ldquo;porra, eu já consertei isso, porque não aparece??&rdquo;</em> - e pode ser cache.</p>
<p>Pra evitar isso, existem técnicas de <strong>Cache Busting</strong>, como cabeçalhos ETAG. Mas o mais comum é só adicionar algum tipo de indicador de timestamp na URL, por exemplo <code>/static/js/host.js?v=20260128120431</code>. Desta forma, sempre que meu servidor reiniciar, o timestamp vai mudar (não é a melhor regra, mas pra agora funciona). A URL vai ser diferente e o navegador vai ser forçado a baixar a versão mais nova, garantindo que eu não perca tempo caçando problemas de cache.</p>
<p>Novamente, qualquer web framework minimamente competente, com suporte a templates de HTML, vai ter isso, mas eu pedi pra fazer do zero:</p>
<p><a href="https://github.com/akitaonrails/tvclipboard/commit/4f98f8364bbe8b4832270c5817e0ee85a4dbc547"target="_blank" rel="noopener"><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260128103739_screenshot-2026-01-28_10-37-00.png" alt="cache busting"  loading="lazy" /></a>
Como eu sirvo páginas estáticas de HTML, o código do meu servidor precisa modificar as URLs antes de mandar pro navegador, e é isso que o commit acima faz.</p>
<p>Ao escrever este post, notei que ele adicionou cache busting pros arquivos &ldquo;.js&rdquo; mas esqueceu do &ldquo;style.css&rdquo;, que ficou sem. Eu não notei porque não mexi quase nada no CSS original que ele fez. Mas novamente, pra demonstrar que LLMs nunca são perfeitas e tem que ficar constantemente checando se ele não esqueceu nada ou deixou sobrar coisas. Mandei ele consertar <a href="https://github.com/akitaonrails/tvclipboard/commit/2338999c505f1466c4913f41c8c7cbea72b369c9"target="_blank" rel="noopener">neste último commit</a></p>
<blockquote>
  <p>O objetivo aqui é lembrar que não basta só jogar arquivos no servidor sem saber como eles são servidos. Todo front-end precisa saber como um navegador funciona. Não basta &ldquo;saber HTML&rdquo;.</p>

</blockquote>
<h3>5. Adicionando Argumentos de Linha de Comando e fazendo mais limpeza<span class="hx:absolute hx:-mt-20" id="5-adicionando-argumentos-de-linha-de-comando-e-fazendo-mais-limpeza"></span>
    <a href="#5-adicionando-argumentos-de-linha-de-comando-e-fazendo-mais-limpeza" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Os <a href="https://github.com/akitaonrails/tvclipboard/commit/278604425edf52ae682a0e11e2952780f2783fd7"target="_blank" rel="noopener">próximos</a> <a href="https://github.com/akitaonrails/tvclipboard/commit/59de9fb135c4b9e0f38343f7296527f0b1c5a31c"target="_blank" rel="noopener">três</a> <a href="https://github.com/akitaonrails/tvclipboard/commit/ce0c25f37284f923568417c2543c66923fe449ec"target="_blank" rel="noopener">commits</a> são besteiras que eu deveria ter feito squash num único commit.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260128104202_screenshot-2026-01-28_10-40-53.png" alt="commits limpeza"  loading="lazy" /></p>
<p>Aqui é mais pra lembrar que não é inteiramente ruim deixar um agente como Crush fazer git commits automaticamente, mas precisa prestar atenção pra talvez ter que mandar desfazer (git tem como refazer commits, com opções como <code>-amend</code>).</p>
<p>Eu só adicionei opções de linha de comando. Agora o binário tem este suporte:</p>
<p><a href="https://github.com/akitaonrails/tvclipboard/commit/278604425edf52ae682a0e11e2952780f2783fd7"target="_blank" rel="noopener"><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260128104735_screenshot-2026-01-28_10-47-27.png" alt="cli args"  loading="lazy" /></a></p>
<p>E como ele esqueceu de documentar no README, o outro commit é pra isso. Por isso falei que o certo era dar squash num commit só, porque são a mesma tarefa.</p>
<h3>6. Configuração de ambiente de Dev vs Produção<span class="hx:absolute hx:-mt-20" id="6-configuração-de-ambiente-de-dev-vs-produção"></span>
    <a href="#6-configura%c3%a7%c3%a3o-de-ambiente-de-dev-vs-produ%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Este é outro ponto que todo iniciante ignora. O famoso <em>&ldquo;ah, mas na minha máquina funciona&rdquo;</em>.</p>
<p>Em web, principalmente, a &ldquo;sua máquina&rdquo;, sempre vai ser um <code>localhost</code>, ou <code>127.0.0.1</code> ou <code>0.0.0.0</code> (assista à minha <a href="https://www.youtube.com/watch?v=0TndL-Nh6Ok&amp;list=PLdsnXVqbHDUcTGjNZuRYCVj3AZtdt6oG7"target="_blank" rel="noopener">playlist sobre Redes</a>) pra entender a diferença.</p>
<p>O problema: se subir esta app localmente no meu PC, eu acesso por <code>http://localhost:3333</code>. Quando o QR Code for gerado, ele vai usar &ldquo;localhost&rdquo;. Agora imagine seu celular tentando carregar um link de &ldquo;localhost&rdquo;. <strong>Obviamente, não vai funcionar.</strong> Porque no seu celular não tem o aplicativo rodando nessa porta em localhost. Eu preciso do IP do meu PC. Então, a primeira coisa que preciso pedir pra corrigir é que, caso seja localhost, que ele procure o IP do meu PC - que vai ser algo como <code>192.168.0.xxx</code>. Estando meu PC e meu celular no mesmo DHCP, na mesma rede, eles conseguem se achar por esse IP privado.</p>
<p>Mas e quando eu subir num Docker? O IP interno de um Docker é diferente do IP externo (o container sempre está ou em NAT ou em Bridge). O IP &ldquo;externo&rdquo; do container vai ser algo como <code>192.168.xxx</code>, mas o IP interno vai ser algo como <code>172.xxx</code>. Novamente, se o QR Code usar o IP interno, vai dar problema.</p>
<p>Então eu preciso de uma nova configuração, que normalmente se chama <strong>PUBLIC URL</strong> ou <strong>PUBLIC HOST</strong> ou só <strong>HOST</strong>. Onde eu <strong>declaro explicitamente</strong>.</p>
<p>Por exemplo, quando terminar, como falei, vou deixar meu serviço exposto na internet usando um domínio válido pessoal. Algo como <code>https://clip.example.com</code> com suporte a TLS e tudo mais. Então eu preciso que no <code>docker-compose.yml</code> eu consiga ter uma opção assim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="w">  </span>- <span class="l">TVCLIPBOARD_PUBLIC_URL = https://clip.example.com</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>E assim o QR Code é gerado com este nome em vez de ter que tentar adivinhar. Mas ao mesmo tempo, se não passar nada, assume &ldquo;localhost&rdquo;.</p>
<p>Neste <a href="https://github.com/akitaonrails/tvclipboard/commit/b129e728101fd9fca400d48c0082b2f3dd679cf3"target="_blank" rel="noopener">primeiro commit</a> ele ainda não faz tudo isso - eu fui fazendo aos poucos. Mas é como se começa esse tipo de funcionalidade.</p>
<blockquote>
  <p>O objetivo aqui é lembrar que &ldquo;rodar na minha máquina&rdquo; (localhost) não significa nada. Não vamos colocar &ldquo;sua máquina&rdquo; em produção. &ldquo;Funcionar&rdquo; significa &ldquo;funcionar FORA da sua máquina&rdquo;.</p>

</blockquote>
<h3>7. Mais limpeza de código<span class="hx:absolute hx:-mt-20" id="7-mais-limpeza-de-código"></span>
    <a href="#7-mais-limpeza-de-c%c3%b3digo" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Estou de propósito mencionando &ldquo;limpeza de código&rdquo; o tempo todo pra que fique bem claro que uma parte considerável do trabalho de programação é &ldquo;limpar&rdquo; código que já foi feito.</p>
<p>Os <a href="https://github.com/akitaonrails/tvclipboard/commit/c9505acd840bbcbead456e3823ecd4a8d6e022a6"target="_blank" rel="noopener">próximos</a> <a href="https://github.com/akitaonrails/tvclipboard/commit/67c5a01f4791257c8f4b19388c9c39bf1ccabb33"target="_blank" rel="noopener">quatro</a> <a href="https://github.com/akitaonrails/tvclipboard/commit/899fef6232c5b8f7081c0ad8681014a681de78ce"target="_blank" rel="noopener">commits</a> <a href="https://github.com/akitaonrails/tvclipboard/commit/63d7fbfaca798dec1eca48ff214561e01b22e670"target="_blank" rel="noopener">são</a> só manutenção.</p>
<p>Por exemplo, sem querer a LLM largou um trecho duplicado dentro do código. Não quebrou nada porque foi na configuração de Docker Compose:</p>
<p><a href="https://github.com/akitaonrails/tvclipboard/commit/67c5a01f4791257c8f4b19388c9c39bf1ccabb33"target="_blank" rel="noopener"><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260128151806_screenshot-2026-01-28_10-59-40.png" alt="duplicate"  loading="lazy" /></a>
Além disso, tem um comportamento <strong>acidental</strong> na forma como este app funciona que resolvi deixar como &ldquo;feature&rdquo;. Sempre precisa ter um navegador que abre primeiro que automaticamente se torna o Host e exibe um QR Code. O próximo navegador a abrir precisa do link desse QR Code e vira o &ldquo;client&rdquo;.</p>
<p>Mas quando o host fecha, o client perde a conexão e automaticamente é <strong>promovido</strong> a host. Eu não pedi pra ser assim mas acabou ficando, então <a href="https://github.com/akitaonrails/tvclipboard/commit/63d7fbfaca798dec1eca48ff214561e01b22e670"target="_blank" rel="noopener">pedi pra deixar e documentar</a>.</p>
<blockquote>
  <p>O objetivo aqui é lembrar que LLMs não são perfeitas, vão deixar sobras pra trás, e você precisa ficar o tempo todo monitorando.</p>

</blockquote>
<h3>8. Otimizando Javascript<span class="hx:absolute hx:-mt-20" id="8-otimizando-javascript"></span>
    <a href="#8-otimizando-javascript" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Os <a href="https://github.com/akitaonrails/tvclipboard/commit/8db01bb053f8e045708b60293f569655a4cf2311"target="_blank" rel="noopener">próximos</a> <a href="https://github.com/akitaonrails/tvclipboard/commit/8f7080cfce86257d5fc0e594f8098c115858a963"target="_blank" rel="noopener">três</a> <a href="https://github.com/akitaonrails/tvclipboard/commit/97df6c5b125de522c4ca65d276df353a97670ae6"target="_blank" rel="noopener">commits</a> são pra dar uma limpeza no Javascript.</p>
<p>Da última vez que mexemos, eu só tinha pedido pra ele tirar os Javascript inline do HTML e separar em arquivos &ldquo;.js&rdquo; reusáveis. Mas chegou a hora de dar uma olhada neles.</p>
<p>De cara, deu pra ver que tinha duplicação entre client e host, então pedi <a href="https://github.com/akitaonrails/tvclipboard/commit/8db01bb053f8e045708b60293f569655a4cf2311"target="_blank" rel="noopener">pra deduplicar</a> e jogar no &ldquo;common.js&rdquo;.</p>
<p>Além disso tinha vários pequenos probleminhas:</p>
<ul>
<li>um monte de variáveis e funções no escopo global (poluição de global: má prática)</li>
<li>websockets que abrem mas sem nada checando o fechamento</li>
<li>timers sendo ativados mas nunca desativados (leaks)</li>
</ul>
<p>O código Javascript &ldquo;que funciona&rdquo; sempre é assim: tudo global, tudo aberto, nada checado, vários leaks. Isso é normal e toda LLM vai fazer assim.</p>
<p>Também não acho que precisa fazer prompts desde o começo exigindo SOLID e tudo mais. Primeiro faz funcionar, depois faz funcionar direito, finalmente faz funcionar rápido. É sempre nessa ordem, especialmente num escopo simples com este.</p>
<p>Por isso agora é hora de pedir pra refatorar. E a primeira coisa a fazer é sempre isolar o escopo, por exemplo, num bloco assim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="s1">&#39;use strict&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">...</span>
</span></span><span class="line"><span class="cl"><span class="p">})();</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>O problema disso é que toda função que o HTML pedia, como &ldquo;onclick&rdquo;, vai falhar porque agora não tem mais nada no escopo global. Uma vez tudo escondido, agora tem que <a href="https://github.com/akitaonrails/tvclipboard/commit/97df6c5b125de522c4ca65d276df353a97670ae7"target="_blank" rel="noopener">ir expondo</a> somente o que realmente precisa público.</p>
<p>Isso se chama <strong>IIFE Encapsulation</strong> (<em>Immediately Invoked Function Expression</em>). Tem milhares de práticas como essa que Javascript precisa pra ficar &ldquo;mais limpo&rdquo;. Eu sei, eu deveria estar usando módulos, Typescript, bla bla, mas esse é um exemplo simples mesmo.</p>
<blockquote>
  <p>O objetivo aqui é lembrar que, só porque &ldquo;funciona&rdquo;, não significa que &ldquo;está bom&rdquo;, principalmente com Javascript.</p>

</blockquote>
<h3>9. Otimizando o Golang<span class="hx:absolute hx:-mt-20" id="9-otimizando-o-golang"></span>
    <a href="#9-otimizando-o-golang" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Esta é a seção mais longa. O código Golang já &ldquo;funciona&rdquo;, mas ele não está bom ainda. Eu sei que tem race conditions em channels, eu sei que o tratamento de erros está ruim, eu sei que ainda tem micro problemas de segurança, então quero consertar o que puder.</p>
<p>Os próximos 6 commits lidam com:</p>
<ul>
<li><a href="https://github.com/akitaonrails/tvclipboard/commit/8d28a12569bcf49fc5f4816b5c964299ff0dbc71"target="_blank" rel="noopener">Refactor: Improve error handling, race conditions, and graceful shutdown</a></li>
<li><a href="https://github.com/akitaonrails/tvclipboard/commit/5bd7e0a8f1c14a9a3c59cbddd1437cfd193f9b6b"target="_blank" rel="noopener">Fix: Critical race conditions, memory leaks, and security issues</a></li>
<li><a href="https://github.com/akitaonrails/tvclipboard/commit/480cc36f93f30369044dfe291477329174566e38"target="_blank" rel="noopener">Security: Add message size validation and rate limiting to prevent abuse</a></li>
<li><a href="https://github.com/akitaonrails/tvclipboard/commit/0c456a203903167182722138c2c11ee63b09ddf3"target="_blank" rel="noopener">Config: Tighten security limits and add origin validation</a></li>
<li><a href="https://github.com/akitaonrails/tvclipboard/commit/5678b0a1768db27bb802a56c13c1498ab4f82040"target="_blank" rel="noopener">Fix: CORS origins, Web Crypto API fallback, and clipboard issues</a></li>
<li><a href="https://github.com/akitaonrails/tvclipboard/commit/5dd813d9ca58324a12b8e6ebf8fcaf8c7be99e9b"target="_blank" rel="noopener">Fix: QR code uses correct port from PublicURL and document Web Crypto API HTTPS requirement</a></li>
</ul>
<p><a href="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260128164221_screenshot-2026-01-28_16-41-43.png"target="_blank" rel="noopener">6 commits</a></p>
<p>O próprio GoLang tem ferramenta pra checar <strong>race conditions</strong>, o <a href="https://go.dev/doc/articles/race_detector"target="_blank" rel="noopener"><strong>Data Race Detector</strong></a>. Basta colocar a opção <code>--race</code> em comandos como <code>go build</code> ou <code>go test</code>. E felizmente o GLM foi esperto e imediatamente usou essa ferramenta quando pedi pra checar esses problemas.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260128112743_screenshot-2026-01-28_11-24-16.png" alt="race condition"  loading="lazy" /></p>
<p><strong>Race conditions</strong> acontecem quando duas tarefas assíncronas tentam modificar a mesma estrutura de dados, por exemplo. Uma das formas de &ldquo;consertar&rdquo; é colocando Locks ou Mutexes em estruturas que só podem ser modificadas sincronamente. Qualquer aplicação que tenha qualquer coisa assíncrona, eventualmente vai ter problemas de condição de corrida. Não é &ldquo;talvez&rdquo;, é &ldquo;quando&rdquo;.</p>
<p>Um servidor precisa ser &ldquo;bem comportado&rdquo;, não pode simplesmente &ldquo;crashear&rdquo;, dar &ldquo;panic&rdquo;. Mas o primeiro código &ldquo;que funciona&rdquo; que o GLM fez tinha vários trechos assim:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260128112136_screenshot-2026-01-28_11-21-28.png" alt="panic"  loading="lazy" /></p>
<p>Isso está errado. Além disso precisamos que o servidor aceite corretamente sinais de sistema como SIGINT, SIGTERM, etc. É quando damos &ldquo;Ctrl-C&rdquo;, por exemplo, ou o Docker manda desligar o container. Ele não vai simplesmente crashear o programa, primeiro ele vai pedir pro programa se desligar sozinho, dando chance dele fazer limpeza, como dar flush em arquivos, fechar portas e coisas assim.</p>
<p>Isso se chama <strong>Graceful Shutdown</strong>.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260128112344_screenshot-2026-01-28_11-23-37.png" alt="graceful shutdown"  loading="lazy" /></p>
<p>Não parei pra checar o quão certo o GLM estava mas segundo ele mesmo, alguns dos problemas que ele mesmo encontrou, no código que ele mesmo fez, incluem coisas assim:</p>
<p><a href="https://github.com/akitaonrails/tvclipboard/commit/5bd7e0a8f1c14a9a3c59cbddd1437cfd193f9b6b"target="_blank" rel="noopener"><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260128113944_screenshot-2026-01-28_11-39-23.png" alt="fixing errors 1"  loading="lazy" /></a></p>
<p><a href="https://github.com/akitaonrails/tvclipboard/commit/5bd7e0a8f1c14a9a3c59cbddd1437cfd193f9b6b"target="_blank" rel="noopener"><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260128114028_screenshot-2026-01-28_11-39-38.png" alt="fixing errors 2"  loading="lazy" /></a></p>
<p>Como podem ver, só porque &ldquo;compila&rdquo;, não quer dizer que está ok. Só porque &ldquo;roda&rdquo;, não quer dizer que está ok. Mesmo pedindo pra checar <strong>MÚLTIPLAS VEZES</strong> a LLM não acha todos os erros de uma só vez. Cada um desses commits levou horas pra conseguir resolver e eu tive que intervir múltiplas vezes, e ainda assim eu ainda não tenho certeza que ele pegou tudo (precisaria revisar com mais calma - mas eu queria publicar este artigo logo 😂).</p>
<h3>10. Adicionando Sistemas de Segurança<span class="hx:absolute hx:-mt-20" id="10-adicionando-sistemas-de-segurança"></span>
    <a href="#10-adicionando-sistemas-de-seguran%c3%a7a" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Novamente, nada disso é necessário num sistema que somente eu vou usar na minha rede local, mas você como desenvolvedor precisa se responsabilizar.</p>
<blockquote>
  <p>SEMPRE considere que todo usuário do seu sistema é MALICIOSO! Essa é a REGRA, não a exceção.</p>

</blockquote>
<p>Um exemplo bobo: o usuário pode colar e transmitir qualquer texto via websockets pro meu servidor. As 3 coisas mais óbvias que imediatamente passaram na minha cabeça foram:</p>
<p><strong>a) Quando o host recebe o texto, ele renderiza no HTML na caixa de &ldquo;Recebido&rdquo;</strong></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260128090907_20260127_195954.jpg" alt="tvclipboard host received screen"  loading="lazy" />
E se o usuário mandar um <code>&lt;script&gt;....&lt;/script&gt;</code>? Isso vai renderizar no HTML e o navegador vai EXECUTAR. É assim que funciona <strong>Code Injection</strong>. É assim que funciona <strong>XSS</strong> (<em>Cross-Site Scripting</em>). Isso era muito comum em antigos fóruns ou sistemas de comentários. Pra evitar isso se deve <strong>SANITIZAR</strong> tudo que vem do usuário.</p>
<p>Felizmente, o jeito que o GLM fez já é sanitizado porque ele escreve o conteúdo com <code>textContent</code> em vez de <code>innerHTML</code>, então o texto é escrito literalmente sem executar:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260128140317_screenshot-2026-01-28_14-03-09.png" alt="textContent"  loading="lazy" />
Por acaso ele fez certo de primeira, mas precisa checar porque ele poderia ter feito errado.</p>
<p><strong>b) Não tinha checagem de tamanho da mensagem</strong></p>
<p>Nunca um usuário pode conseguir enviar um texto de tamanho qualquer. Ele sempre pode tentar diretamente dar POST com um arquivo de gigabyte pra ver se estoura algum erro de <strong>Overflow</strong> no servidor, expondo algum exploit de segurança.</p>
<p>TODO campo de usuário precisa de limites e precisa checar não só no cliente/front-end, mas mais importante, no backend:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260128140558_screenshot-2026-01-28_14-05-51.png" alt="message max size"  loading="lazy" />
<strong>c) Tem que rejeitar Spammers!!</strong></p>
<p>Novamente, não pode assumir que todo mundo vai usar seu web app bonitinho. A regra é achar que todo mundo vai tentar derrubar ou invadir. E uma forma de fazer isso é criar um script pra ficar fazendo milhares de POST por segundo pra tentar algum tipo de <strong>Denial of Service</strong>, onde o servidor enfileira tanta requisição que vai estourar.</p>
<p>O certo é configurar isso num outro serviço que vai ficar na frente do seu, como <a href="https://www.cloudflare.com/ddos/"target="_blank" rel="noopener"><strong>Cloudflare</strong></a>.</p>
<p>Mas não custa implementar um <em>fallback</em> na sua aplicação mesmo. Um jeito de configurar quantas requests um mesmo usuário pode fazer de cada vez (ex. 4 requisições por segundo - ninguém vai colar texto tantas vezes por segundo numa app dessas).</p>
<p>Se tentar mais que isso, o app tem que imediatamente <strong>REJEITAR</strong> e dropar a conexão, sem gastar tempo processando mais, liberando recursos pra outras requisições de verdade. Isso se chama <strong>RATE LIMITING</strong>.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260128141010_screenshot-2026-01-28_14-10-02.png" alt="rate limiting"  loading="lazy" />
<strong>d) Outro problema que iniciantes não param pra pensar é em CORS e Origin Check.</strong></p>
<p>Como falei antes, temos Javascripts como <code>/static/js/common.js</code>. Não é nenhum grande problema outra pessoa usar porque não tem nenhum grande segredo neles. Mas no mínimo eu não quero que algum site &ldquo;<a href="http://malware.pk/index.html"target="_blank" rel="noopener">http://malware.pk/index.html</a>&rdquo; da vida inclua dentro dele um <code>https://clip.example.com/static/js/common.js</code> e eu fique pagando pelo tráfego dele.</p>
<p>Eu quero que somente a <strong>MESMA ORIGEM</strong>, no caso &ldquo;clip.example.com&rdquo;, seja capaz de carregar arquivos no mesmo servidor. Ninguém de fora é bem-vindo e isso é a <strong>BOA PRÁTICA</strong>. Estude <strong>CORS</strong> (Cross-Origin Resource Sharing). Isso é mais importante se seu sistema são múltiplos domínios onde um depende do outro, daí você quer - controladamente - permitir somente determinados outros domínios que estão sob seu controle.</p>
<blockquote>
  <p>Regra de tudo em rede é <strong>DENY ALL</strong> e depois <strong>ALLOW [específico]</strong>. NUNCA deve ser <strong>ALLOW ALL</strong>.</p>

</blockquote>
<p>Pra implementar isso demorou um bocado, porque o GLM ficou se enrolando de como permitir &ldquo;localhost&rdquo;, mas também &ldquo;192.168.xxx:3333&rdquo;, mas também &ldquo;clip.example.com&rdquo; (via porta 443), etc. Não é difícil, só o GLM que se complicou todo e eu tive que intervir várias vezes com prompts pra colocar ele na direção certa. Acabou dando múltiplos commits até ele acertar.</p>
<p><strong>e) Outro probleminha que iniciante não pensa: PERMISSÕES de recursos do navegador.</strong></p>
<p>Toda vez que carregar esse sistema em &ldquo;localhost&rdquo; e ele receber a mensagem pra jogar no clipboard, vai aparecer este alerta pedindo permissão:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260128114848_screenshot-2026-01-28_11-48-38.png" alt="clipboard permission"  loading="lazy" /></p>
<p>E isso é normal e correto: nada deveria ter acesso a coisas fora do navegador. Por isso o Javascript pede <em>&ldquo;manda pro clipboard&rdquo;</em>, daí o navegador intercepta, checa a permissão e, se não tem ele pede. Toda vez vai pedir. Mas se usar um domínio de verdade (ex. clip.example.com), ele vai perguntar uma vez e depois lembrar pra cada domínio. É um dos motivos pelos quais vou expor na internet: pra ter um domínio de verdade.</p>
<blockquote>
  <p>Expor serviços na internet é PERIGOSO. Por isso eu fiz <a href="https://akitaonrails.com/2025/09/09/acessando-meu-home-server-com-dominio-de-verdade/"target="_blank" rel="noopener">este artigo explicando como usar domínios de verdade</a> e <a href="https://akitaonrails.com/2025/09/10/protegendo-seu-home-server-com-cloudflare-zero-trust/"target="_blank" rel="noopener">este outro artigo sobre como usar Cloudflare Zero Trust</a>.</p>

</blockquote>
<p><strong>f) Tinha outro fator de segurança que é &ldquo;overkill&rdquo; mas eu quis implementar mesmo assim.</strong></p>
<p>Digamos que eu queira rodar somente em localhost. Digamos que seja uma rede privada, mas compartilhada (visitas, companheiro de quarto, escritório, etc). Ao rodar em localhost não vai ter TLS, ou seja, os pacotes HTTP vão trafegar em texto aberto.</p>
<p>Qualquer um com um <a href="https://www.wireshark.org/"target="_blank" rel="noopener"><strong>Wireshark</strong></a> pode ficar &ldquo;escutando&rdquo; (&ldquo;sniffing&rdquo;) os pacotes na rede e interceptar os meus. E se justo eu estiver passando dados sensíveis, como uma senha, vai dar pra ver aberto.</p>
<p>O certo é rodar com TLS (HTTPS). Mas só pra um &ldquo;quebra-galho&rdquo;, pedi pro GLM implementar uma obfuscação simples (não é um processo totalmente seguro, mas usa AES-GCM), mas já serve pra não ficar óbvio com um sniffer. Pra isso ele vai usar <a href="https://w3c.github.io/webcrypto/"target="_blank" rel="noopener"><strong>Web Crypto API</strong></a>.</p>
<p>Mas tem um porém: Web Crypto API está disponível somente se o site abrir com HTTPS ou se for localhost. Mas se eu tentar <code>http://192.168.xxx:3333</code>, não vai estar disponível. Pra isso tem <a href="https://github.com/akitaonrails/tvclipboard/commit/5dd813d9ca58324a12b8e6ebf8fcaf8c7be99e9b"target="_blank" rel="noopener">este commit</a> pra lidar com isso e documentar.</p>
<blockquote>
  <p>O objetivo aqui é mostrar como aspectos de segurança, otimização, mantenabilidade são muito mais do que um iniciante pensa. Aliás, nunca vai pensar, porque precisa ter estudado antes pra saber que existe.</p>

</blockquote>
<h3>11. Licenças Open Source<span class="hx:absolute hx:-mt-20" id="11-licenças-open-source"></span>
    <a href="#11-licen%c3%a7as-open-source" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Esse tema sozinho seria assunto pra um longo artigo, mas na prática eu tendo a pensar simples:</p>
<ul>
<li>se for um projeto que eu não me importo se alguém vai contribuir ou não, basta abrir com licenças PERMISSIVAS, como BSD, MIT</li>
<li>se for um projeto que eu gostaria de ter contribuição e que ninguém use comercialmente, basta colocar uma licença RESTRITIVA, como GPL</li>
<li>se for restritivo e for um app que poderia virar um SaaS (daí o código não é distribuído, então não precisaria contribuir), daí adiciona AGPL (Affero)</li>
</ul>
<p>Foi o que eu fiz neste: coloquei licença <a href="https://github.com/akitaonrails/tvclipboard/blob/master/LICENSE"target="_blank" rel="noopener">AGPL 3.0</a>.</p>
<p>O aviso é pra não deixar LLMs escreverem o arquivo de licença. Sempre pegue textos sobre leis, regulamentos e regras do site oficial. A LLM sempre produz uma versão resumida ou incompleta ou até errada mesmo. Documentos legais precisam ser EXATOS, não pode ter palavras erradas e sentidos ambíguos ou afirmações incompletas.</p>
<blockquote>
  <p>LLMs não são boas pra gerar textos legais corretos de primeira, sempre vai ter erros. Sempre assuma que textos assim estão errados: não existe &ldquo;compilador&rdquo; de leis.</p>

</blockquote>
<h3>12. Resolvendo o problema dos tokens longos demais<span class="hx:absolute hx:-mt-20" id="12-resolvendo-o-problema-dos-tokens-longos-demais"></span>
    <a href="#12-resolvendo-o-problema-dos-tokens-longos-demais" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Lá atrás eu falei que os tokens que o GLM gerou pra mim são grandes demais (mais de 100 caracteres). Isso resulta em links super gigantes.</p>
<p>Não é um problema porque ninguém vai ter que digitar isso e nem é pra bookmarkar. Aqui é mais uma escolha pessoal mesmo: eu gosto de tokens curtos em URL.</p>
<p>A vantagem do token longo é que eu não preciso implementar nenhum tipo de &ldquo;banco de dados&rdquo; (key-value store, ou KV Store - Memcached, Redis). Isso porque toda a informação da sessão (ID e timestamp de expiração), estão encodados dentro desse token, por isso ele é longo. É uma struct json, encriptada com AES, convertida em Hex.</p>
<p>Tentando manter o mesmo conceito, <a href="https://github.com/akitaonrails/tvclipboard/commit/eb274968d8ec83c28abce7ffd7352ad6eebd86bc"target="_blank" rel="noopener">neste primeiro commit</a> eu pedi só pra ele tentar otimizar o tamanho da estrutura. Então o GLM sozinho escolheu tentar mudar de UUID (36 chars) pra um Hex ID aleatório de 24 chars. Trocar de timestamp padrão ISO (24 chars) pra UNIX (10 chars). Isso desceu dos 130 a 140 chars pra uns 112 chars. Uma redução na faixa de 20% a 25%.</p>
<p>Não foi uma tentativa ruim. Mas no final eu realmente não estava engolindo tokens grandes assim (poderia ser cookie também, eu sei, mas queria manter tudo na URL).</p>
<p>No final decidi que queria tokens realmente curtos (de 8 chars, base62) e aí precisaria guardar a Sessão em algum &ldquo;storage&rdquo;. Decidi que ia ser &ldquo;in-memory&rdquo; (afinidade ao processo, mas eu só vou rodar 1, sem load balancer, então tá ótimo). E isso seria um FIFO com rotação (chaves mais velhas vão sendo descartadas pra dar espaço pra chaves mais novas e pronto, elas expiram mesmo).</p>
<p><a href="https://github.com/akitaonrails/tvclipboard/commit/a34b265b585a5661c2595fe474b4613a5aba13c0"target="_blank" rel="noopener">Este é o commit dessa funcionalidade</a> e ainda tive que intervir várias vezes. Por alguma razão ele achou que seria uma boa idéia ter goroutine em background pra ficar limpando os tokens expirados desse storage. Mas isso é completamente desnecessário se for um FIFO. Ele fez, eu tive que mandar desfazer. Essa é a rotina.</p>
<p><a href="https://github.com/akitaonrails/tvclipboard/commit/a34b265b585a5661c2595fe474b4613a5aba13c0"target="_blank" rel="noopener"><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260128131103_screenshot-2026-01-28_13-10-53.png" alt="FIFO"  loading="lazy" /></a></p>
<h3>13. Mais refatoramento e limpeza (quase acabando!)<span class="hx:absolute hx:-mt-20" id="13-mais-refatoramento-e-limpeza-quase-acabando"></span>
    <a href="#13-mais-refatoramento-e-limpeza-quase-acabando" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Os últimos <strong>6 commits</strong> são <strong>MAIS MANUTENÇÃO!!</strong></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260128162905_screenshot-2026-01-28_16-28-52.png" alt="6 commits"  loading="lazy" /></p>
<p>Parece zoeira, mas isso que eu fiz de manutenção é até pouco. Num projeto de verdade isso faz parte da rotina. Toda vez que você adiciona alguma coisa nova, vai estragar alguma coisa que já tinha, e vai precisar ajustar pra não acumular <strong>débito técnico</strong>.</p>
<p>Lembram que rodamos checagem de <strong>race condition</strong>? Adicionamos código novo, tem que checar de novo. E ele achou mais problemas corrigidos <a href="https://github.com/akitaonrails/tvclipboard/commit/df348dbe170451c38b9c9fdf703b57ce6c253578"target="_blank" rel="noopener">neste commit</a>. Não lembro agora se já tinha lá atrás e ele pulou sem corrigir, ou se nas últimas mexidas acabou gerando esses novos bugs.</p>
<p>Depois de tanto adicionar coisas e refatorar, resolvi aumentar mais um pouco a cobertura de código do Go. O comando <code>go test</code> tem a opção <code>-coverprofile</code> pra ajudar a checar quais partes do seu código não foram testadas ainda. Então pedi pro GLM adicionar testes pras novas funcionalidades como Rate Limiting, checagem de tamanho da mensagem, check origin e <a href="https://github.com/akitaonrails/tvclipboard/commit/fc32a575c53d61b7fce5ab941d069dd45d66fc81"target="_blank" rel="noopener">outras coisas</a>.</p>
<p>Mandei adicionar uma besteira que é um <a href="https://github.com/akitaonrails/tvclipboard/commit/2867f8df052f89febc095644ed28aaaefd0b198a"target="_blank" rel="noopener">botão de &ldquo;Fechar&rdquo;</a> no lado cliente, pra não ficar acumulando tabs no meu smartphone.</p>
<p>Depois que mandei trocar o sistema de tokens, não precisa mais encriptar a estrutura de timestamp. Mas ele deixou pra trás testes unitários sobre isso. Então <a href="https://github.com/akitaonrails/tvclipboard/commit/9b5d9f5d3b6504788e73426cc3dc2c6a2a9fe358"target="_blank" rel="noopener">mandei tirar</a>. Novamente: LLMs vão deixar coisas incompletas pra trás. Muitas vezes ele não sabe se mantém um código pra não quebrar o teste, ou se é pra tirar o teste porque o código não é mais necessário.</p>
<p>Depois pedi pro Go rodar <a href="https://github.com/akitaonrails/tvclipboard/commit/1b0e2efd0dfaedf96b2c54eea62438cc7b081924"target="_blank" rel="noopener">linter</a> e suporte a <a href="https://github.com/akitaonrails/tvclipboard/commit/128cf14feff3f1d36a2568c9af8b9665c6b6377a"target="_blank" rel="noopener">golangci-lint</a> pra últimas checagens. Um Linter é tipo uma checagem de formatação, sintaxe e boas práticas de codificação numa linguagem em particular. Mas a maior parte dos ajustes foi espaços sobrando, poucas indentações erradas e coisas desse tipo. Nada de mais.</p>
<p>Uma última coisa que foi negligência minha mesmo, é que estava esquecendo de adicionar testes de Javascript. Uma parte considerável do código é front-end pra lidar com WebSockets e tudo mais. Precisa adicionar, e isso foi <a href="https://github.com/akitaonrails/tvclipboard/commit/bb0d4895f1cfb5b62c0133930b017c93db5d60a8"target="_blank" rel="noopener">neste commit</a>.</p>
<p>Como fiz tudo de uma vez só, aí já pedi pra adicionar ESLint também, e priorizar testar tudo só unitariamente, com mocks e stubs pra ser tudo headless e sem precisar carregar Chromium. Só testar as funções publicamente expostas mesmo. Isso elevou a cobertura de testes de front-end de zero pra 73%, o que é uma ótima cobertura. Veja o <a href="https://github.com/akitaonrails/tvclipboard/commit/bb0d4895f1cfb5b62c0133930b017c93db5d60a8"target="_blank" rel="noopener">commit</a> pra ver como ficou.</p>
<h3>14. Última coisa: I18n<span class="hx:absolute hx:-mt-20" id="14-última-coisa-i18n"></span>
    <a href="#14-%c3%baltima-coisa-i18n" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Isso foi uma coisa que lembrei enquanto já estava escrevendo este artigo. Completamente desnecessário, mas eu queria ver se o GLM conseguiria fazer. E <a href="https://github.com/akitaonrails/tvclipboard/commit/065c52046551b2d8ff426a7206366455e19638c4"target="_blank" rel="noopener">&ldquo;conseguiu&rdquo;</a>. Eu não detalhei como eu queria e deixei ele pensar na solução. Eu teria feito o servidor em Go fazer a troca dos strings antes de enviar o HTML pro client.</p>
<p>Mas o GLM preferiu adicionar isso no lado do front-end e trocar as strings via Javascript. Não está errado, mas não é o melhor jeito.</p>
<p>Justamente tradução de linguagens é uma coisa que IAs foram feitas originalmente pra serem boas: Processamento de Linguagem Natural (NLP). Mandei extrair todos os textos em inglês e depois fazer uma versão em Português do Brasil, e posso dizer que ele fez direitinho:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260128153748_screenshot-2026-01-28_15-36-56.png" alt="pt-BR"  loading="lazy" /></p>
<p>Num web app de verdade é uma coisa que sempre precisamos ficar preocupados: de não deixar mensagens pra usuário &ldquo;hardcoded&rdquo; e sempre ficar extraindo e testando. O que me leva à última parte:</p>
<h2>Não era Melhor usar Framework X ou Biblioteca Y?<span class="hx:absolute hx:-mt-20" id="não-era-melhor-usar-framework-x-ou-biblioteca-y"></span>
    <a href="#n%c3%a3o-era-melhor-usar-framework-x-ou-biblioteca-y" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Povo de Go talvez não goste que eu não tenha usado Gin, Fiber ou outro web framework. Mas realmente neste caso o app é simples demais. Não tem mais que 3 endpoints. A parte mais complicada seria o WebSockets, que não ficaria muito diferente usando um framework. Ou checagens maiores como de CORS, que também não seria muito menos LOC.</p>
<p>No lado do Javascript, talvez I18n valesse a pena eu ter importado algum pacote pronto, mas novamente, é muito simples. Não tinha nenhuma grande funcionalidade que tive que reinventar a roda.</p>
<p>Claro, isso porque este app é miseravelmente pequeno, como falei no começo. Um app maior de verdade, eu recomendaria mesmo usar um framework popular com bom suporte da comunidade, bem documentado e tudo mais. Mas coisas do tamanho de um ToDo List realmente não faz diferença a menos que o exercício fosse aprender a usar determinado framework.</p>
<p>Pensando nisso, tem que tomar cuidado porque nenhuma LLM vai escolher pra você. Se começar com prompts pequenos, uma funcionalidade de cada vez (que é o jeito certo), ele tende a escrever as coisas tudo do zero, sem importar nenhuma biblioteca.</p>
<blockquote>
  <p>Você tem que saber de antemão que biblioteca vai pedir pra cada coisa!</p>

</blockquote>
<p>Novamente, um iniciante não saberia, então acabaria reinventando a roda dezenas de vezes em vez de usar bibliotecas populares.</p>
<p>Lembram que falei, lá no começo, pra guardar como era a estrutura do projeto na versão <strong>v0.1</strong> que &ldquo;já funcionava&rdquo;? Eis como fica no final num projeto de verdade:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260128162157_screenshot-2026-01-28_16-20-40.png" alt="final tree"  loading="lazy" /></p>
<h2>Conclusão<span class="hx:absolute hx:-mt-20" id="conclusão"></span>
    <a href="#conclus%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Ufa! Foi Longo! Parabéns se chegou até aqui!</p>
<p>Minha experiência neste projetinho foi de ter um <strong>estagiário super motivado</strong> que eu precisei ficar o <strong>dia inteiro</strong> olhando atrás do ombro e toda hora falando:</p>
<p><em>&ldquo;Opa! Para tudo, tá errado!&rdquo;</em>
<em>&ldquo;Opa! Desfaz e faz de novo mas deste outro jeito!&rdquo;</em>
<em>&ldquo;Opa! Não, você já tinha feito isso errado antes e tá repetindo!&rdquo;</em></p>
<p>Não estou brincando quando falei que foram mais de 250 prompts. E isso é uma estimativa por baixo, eu acho que escrevi MUITO mais que isso.</p>
<p>Tão logo terminei o processo de Vibe Coding, já fiz push no GitHub e comecei a escrever este artigo, então ainda faltam horas de <strong>REVISÃO</strong> do código todo, do começo ao fim, pra ver se não deixei passar nada. Não daria pra colocar em produção sem fazer isso! Se alguém ver coisas estranhas no código, fiquem à vontade pra mandar nos comentários.</p>
<p>Foi realmente como se eu estivesse mentorando um estagiário. Mas com um problema: diferente de um estagiário de verdade, a LLM já se esqueceu de tudo que eu ensinei pra ele.</p>
<p>Quando for fazer um novo projeto com o GLM, ele vai cometer praticamente TODOS os mesmos erros e equívocos. É como se eu estivesse mentorando um estagiário cego e com memória de peixe dourado.</p>
<p><strong>É extremamente cansativo!!</strong></p>
<blockquote>
  <p>No final levou umas 12 horas pra codificar tudo, e eu tenho a impressão que um desenvolvedor sênior de Go teria feito sozinho na metade do tempo. Um júnior teria levado esse tempo, ao longo de uns 2 ou 3 dias (parando pra pesquisar).</p>

</blockquote>
<p>Eu já sabia disso, já repeti dezenas de vezes, mas a noção de:</p>
<p><em>&ldquo;Não preciso mais contratar programador, a IA faz tudo sozinha.&rdquo;</em> - é uma <strong>GRANDE FALÁCIA</strong>.</p>
<p>E não vai melhorar muito mais do que isso. Já estamos no topo da curva em S que eu expliquei em todo podcast que participei e nos videos do meu canal. Custa ordens de grandeza mais energia pra treinar a próxima versão do que levou todas as versões anteriores, pra ter uma evolução <strong>incremental</strong>.</p>
<p>Enquanto a arquitetura for a mesma, não vai sair disso. Precisa de alguma NOVA DESCOBERTA (que não aconteceu até hoje, desde 2021 quando saiu Transformers).</p>
<p>Um Claude Code vai ser um pouco mais rápido que GLM. A próxima versão do GLM vai ser um pouco mais rápido. Talvez o tempo de 12 horas que eu levei, vire 6 horas (pra este app miserável). Mas o <strong>PROCESSO</strong> vai ser o mesmo: ele faz errado, eu mando consertar, e faz isso <em>ad eternum</em>.</p>
<p>Não vai existir fazer um único prompt e no final sair um app perfeito, seguro, otimizado, etc. SEMPRE vai sair com bugs na primeira vez. Por isso que alguém que não é programador não deve fazer software pra colocar em produção só com Vibe Coding: <strong>precisa</strong> passar por revisão de um programador experiente de verdade.</p>
<p>Isso não é opcional.</p>
<h2>Post-Mortem<span class="hx:absolute hx:-mt-20" id="post-mortem"></span>
    <a href="#post-mortem" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Esta seção foi escrita no dia seguinte à publicação do artigo original. Depois de terminado, pedi ao <strong>Claude Code</strong> pra fazer uma análise profunda da qualidade, focando em segurança e testes. E ele achou <strong>VÁRIOS</strong> erros. Lembram que falei que não dava pra colocar em produção sem revisar com calma antes?</p>
<p><a href="https://github.com/akitaonrails/tvclipboard/commit/d3e2b1b8dcbe1f0451995623df17b38ad236dbb7"target="_blank" rel="noopener"><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260129095637_screenshot-2026-01-29_09-56-25.png" alt="claude code analysis"  loading="lazy" /></a></p>
<p><a href="https://github.com/akitaonrails/tvclipboard/commit/d3e2b1b8dcbe1f0451995623df17b38ad236dbb7"target="_blank" rel="noopener">Este é o commit</a> com os consertos, dêem uma olhada.</p>
<p>Então ele &ldquo;Já funcionava&rdquo; na Fase 1, com um monte de problemas. Eu intervi e gastei 90% do tempo na Fase 2 adicionando a fundação. Não revisei propriamente e publiquei o arquivo, agora retornei e ainda tem problemas.</p>
<blockquote>
  <p>Software NUNCA está &ldquo;finalizado&rdquo;.</p>

</blockquote>
<p>Mesmo isso que o Claude Code encontrou, não significa que corrige TUDO. Significa que corrige ALGUMAS COISAS. Nenhum software nunca tem &ldquo;garantia&rdquo; que está perfeito. Isso não existe.</p>
<p>Mesmo se tivesse começado com Claude Code, como falei antes, teria sim, sido mais rápido. Mas tudo depende do que você vai pedir pra ele. Se você não souber exatamente os requerimentos e especificações de segurança, ou performance, ou escalabilidade, ou mantenabilidade ANTES de pedir, ele vai fazer ALGUMAS COISAS. Não necessariamente as COISAS PERFEITAS, mas só ALGUMAS COISAS.</p>
<p>Daí alguém pode dizer <em>&ldquo;Tá vendo? Agora que revisou com Claude Code, vai estar perfeito&rdquo;</em></p>
<p>Então, depois eu ainda pedi pro <a href="https://github.com/akitaonrails/tvclipboard/commit/78dcfb11e58d026e2bc34476d849561724879fa8"target="_blank" rel="noopener"><strong>GPT 5.2 Codex</strong></a> fazer a mesma análise extensiva e adivinha: ele também encontrou mais probleminhas. Muito menos, claro. Mas veja bem, depois do GLM 4.7, do Opus 4.5, o GPT 5.2 ainda achou mais coisas. NUNCA ACABA!</p>
<p>Em particular, lembram como lá atrás eu tinha feito tokens serem encriptados, depois mudei o requerimento pedindo pra não ser e deixar in-memory no servidor? Ainda sobrou código antigo dessa funcionalidade. O GPT 5.2 achou que era pra terminar de implementar a encriptação e começou a colocar de volta. Tive que interromper e mandar ele parar e remover. Nem o Opus 4.5 removeu esse <strong>dead code</strong>.</p>
<p><a href="https://github.com/akitaonrails/tvclipboard/commit/78dcfb11e58d026e2bc34476d849561724879fa8"target="_blank" rel="noopener"><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260129102239_screenshot-2026-01-29_10-22-30.png" alt="GPT 5.2"  loading="lazy" /></a></p>
<p>Sempre, você que pede é o responsável por pedir exatamente e checar depois.</p>
]]></content:encoded><category>vibe-coding</category><category>engenharia-de-software</category></item><item><title>RANT - LLMs são LOOT BOXES!</title><link>https://akitaonrails.github.io/2025/05/02/rant-llms-sao-loot-boxes/</link><guid isPermaLink="true">https://akitaonrails.github.io/2025/05/02/rant-llms-sao-loot-boxes/</guid><pubDate>Fri, 02 May 2025 19:20:00 -0300</pubDate><description>&lt;p&gt;Eu sei que vai soar negativo demais, e de novo, vou repetir que eu não sou anti-I.A., anti-LLM nem nada disso, pelo contrário, eu gosto TANTO, mas TANTO, que venho dedicando TODAS as minhas horas em pesquisar a fundo a respeito.&lt;/p&gt;
&lt;p&gt;Tem sido muito útil pra mim especialmente pra resumir paper, conciliar pesquisas em vários sites, resumir tópicos e coisas do tipo.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&amp;ldquo;MAS ..&amp;rdquo;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;E é um enorme MAS, ele tem sido BEM inútil em programação de verdade. Não vou repetir todos os problemas que já encontrei: eu detalhei bastante nos posts anteriores. Mas minha conclusão é simples: ele pode ajudar em código, em tarefas pequenas, focadas, isoladas, com bastante prompt pra ajudar e você - programador - precisa estar atento em o que escolher usar e o que vai rejeitar (e vai ser a maior parte).&lt;/p&gt;</description><content:encoded><![CDATA[<p>Eu sei que vai soar negativo demais, e de novo, vou repetir que eu não sou anti-I.A., anti-LLM nem nada disso, pelo contrário, eu gosto TANTO, mas TANTO, que venho dedicando TODAS as minhas horas em pesquisar a fundo a respeito.</p>
<p>Tem sido muito útil pra mim especialmente pra resumir paper, conciliar pesquisas em vários sites, resumir tópicos e coisas do tipo.</p>
<p><strong>&ldquo;MAS ..&rdquo;</strong></p>
<p>E é um enorme MAS, ele tem sido BEM inútil em programação de verdade. Não vou repetir todos os problemas que já encontrei: eu detalhei bastante nos posts anteriores. Mas minha conclusão é simples: ele pode ajudar em código, em tarefas pequenas, focadas, isoladas, com bastante prompt pra ajudar e você - programador - precisa estar atento em o que escolher usar e o que vai rejeitar (e vai ser a maior parte).</p>
<p>Prompts melhores tem limites. RAGs tem limites. Loras tem limites. Janela de contexto maior tem limite. Usar agentes que devolver stacktrace e pedir pra fazer deep thinking, tem limites. Eu já consegui esbarrar em TODOS os limites e não achei nenhum &ldquo;workaround&rdquo; que consiga fazer ele funcionar 100% bem em 100% do tempo - que é a promessa que a propaganda faz.</p>
<p><em>&ldquo;Mas a Microsoft, Google, Meta, NVIDIA já afirmaram que 30% do código deles já é feito com I.A. e ano que vem vai substituir programadores&rdquo;</em></p>
<p>Essa é a grande meia-verdade, meia-mentira (interprete como quiser).</p>
<h2>&ldquo;Que 30%??&rdquo;<span class="hx:absolute hx:-mt-20" id="que-30"></span>
    <a href="#que-30" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Você, que não é programador, sabia que documentação de projetos (que é extenso), arquivos de tradução de línguas (que é extenso, sabe quantas línguas uma Microsoft ou Google suportam globalmente?), páginas HTML que duplicam essa documentação extensa, tudo isso é &ldquo;considerado&rdquo; parte do código e fica no mesmo repositório &ldquo;de código&rdquo; como GitHub?</p>
<p>Você, que não é programador, sabia que o VOLUME em caracteres/bytes desse material, muitas vezes quase iguala ou até pode superar o volume de bytes do código em si?</p>
<p>Esse é só um pequeno exemplo que me vem à cabeça. Páginas de lançamento de produtos novos, os &ldquo;hot-sites&rdquo; que são sites DESCARTÁVEIS e feitos pra jogar fora. Isso também é volume de código. Tem MUITO &ldquo;código&rdquo; que não é &ldquo;O código&rdquo;. Todo programador que trabalha numa grande empresa sabe disso.</p>
<p>O seu projetinho caseiro não tem documentação, não tem testes automatizados, não tem scripts de build, não tem automação de deploy ou empacotamento, não tem arquivos de línguas separado, não tem hot-site, não tem site de produto em múltiplas línguas. É só um &ldquo;hello.py&rdquo; e esse é TODO o seu código. Entendo porque você extrapola que projeto grande é a mesma coisa.</p>
<p>PARTE dos &ldquo;30%&rdquo; que tanto se fala é isso. Claro que tem algum código de verdade, mas não é nem perto do que você pensa.</p>
<h3>Conflito de Interesses<span class="hx:absolute hx:-mt-20" id="conflito-de-interesses"></span>
    <a href="#conflito-de-interesses" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Eu fico pasmo. Se um &ldquo;vendedor de entorpecentes&rdquo; te dá uma amostra grátis e você pergunta &ldquo;mas é seguro&rdquo;. O que você acha que ele vai responder?</p>
<p>O dono da Meta tem produtos de I.A. O dono do Google, o dono da Microsoft, ALUGAM GPUs pra I.A.. O dono da NVIDIA VENDE GPUs pros datacenters de I.A. O dono da OpenAI, Anthropic, todos ALUGAM essa infra e te REVENDEM, <strong>CRÉDITOS DE TOKENS</strong>.</p>
<p>Qual você acha que é o incentivo deles? <strong>VENDER USO TOKENS</strong>.</p>
<p>Vocês viram meu relato nos posts anteriores. Em menos de 1 semana de testes eu gastei quase USD 150 de créditos. Seriam mais de 850 BRL, em uma semana, e depois de fazer uma CENTENA de tentativas, eu obtive refatoramentos meraramente &ldquo;razoáveis&rdquo; METADE das vezes, e eu obtive bons testes unitários que passam, MENOS DA METADE das vezes (na verdade, quase NENHUMA vez). Mas eu gastei token, MUITOS TOKENS.</p>
<p>Funcionalidades que a propaganda te fala que melhoram como DEEP THINKING/REASONING, só &ldquo;às vezes&rdquo; dão respostas de código melhor. Eles de fato são melhores pra compilar papers ou pesquisas de texto. Mas pra código, na MAIORIA das tentativas, eu não vi tanta diferença. Só que demorou MUITO mais e gastou MUITO mais tokens. Sabe o que Deep Thinking faz? Ele adiciona mais passos até a resposta e enche o contexto com tokens. Esses tokens extras: VOCÊ PAGA A MAIS.</p>
<p>Funcionalidades que a propaganda também te fala que melhorar como soluções baseadas em RAG, no fundo é só mais &ldquo;injeção de prompt&rdquo; - que sempre gasta contexto e GASTA MAIS TOKENS. Funciona, claro, mas o incentivo é gastar mais tokens.</p>
<p>Funcionalidades que a propaganda agora tenta te empurrar como MCP, agentes e automação de LLMs, somado com RAGs e tudo mais. Os Devin, n8n, e tudo mais são uma forma mais automatizada de GASTAR MAIS TOKENS.</p>
<p>Todo o incentivo, de todo mundo, é gastar mais tokens, não menos. E nos meus testes, em muitos modelos (não vou dizer todos), eu obtive respostas melhores de código <strong>DESLIGANDO DEEP THINKING</strong>. Dá pra configurar isso em ferramentas como Aider ou direto na API da OpenAI. Diminuir <code>thinking_tokens</code> ou fazer <code>reasoning_effort</code> ser &ldquo;Low&rdquo; ou melhor, &ldquo;NONE&rdquo;.</p>
<h3>LOOT BOXES<span class="hx:absolute hx:-mt-20" id="loot-boxes"></span>
    <a href="#loot-boxes" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Também expliquei no <a href="https://www.akitaonrails.com/2025/04/29/dissecando-um-modelfile-de-ollama-ajustando-qwen3-pra-codigo"target="_blank" rel="noopener">artigo sobre como fazer seu próprio Modelfile de Ollama</a> que, essencialmente, o processo de geração de textos (engula, LLMs são geradores de próxima palavra), tem componentes aleatórios. Temperatura, Top_P, Top_K. Mais: o treinamento tem componentes não-lineares (ex. ReLU). Não é determinístico, é um SORTEIO numa distribuição de probabilidades.</p>
<p>Significa que, fundamentalmente, não tem como uma LLM estar 100%, 100% do tempo. É matematicamente impossível. Ele sempre pode estar &ldquo;quase certo&rdquo; ou &ldquo;parecendo que está certo&rdquo;. Mas se você diligentemente rechecar tudo, o tempo todo, vai começar a encontrar pequenos equívocos. No caso de código, é bem mais aparente. Ele está BEM errado, MUITAS vezes.</p>
<p>E o processo todo se assemelha muito a jogos online &ldquo;gratuitos&rdquo; com LOOT BOXES ou sistemas de GATCHA, sabe? Tipo Genshin Impact da vida.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/my994es2wx2rj3mfkyu9i6h4s9ik" alt="Loot Box"  loading="lazy" /></p>
<p>O quê??? Você é um boomer e não sabe o que são Loot Boxes? &hellip;</p>
<p>EU SOU BOOMER E EU SEI, não tem desculpa. Vai se atualizar (e é a principal razão de porque eu escolho não jogar esse tipo de jogo online).</p>
<p>A economia desses games funciona assim: você não tem a opção de comprar ítens específicos que quer. Em vez disso, você paga, digamos 20 créditos pela chance de participar de um sorteio (que acontece em datas e horas pré-programadas, não o tempo todo). Nesse sorteio você tem a (ALTA) probabilidade de só ganhar um ítem de 10 créditos OU, a <strong>incrível</strong> (BAIXÍSSIMA) probabilidade de ganhar um ítem exclusivo de 1000 créditos!!!!</p>
<p>Parece um negócio da China né??? (LITERALMENTE É!!!)</p>
<p>Você sempre ganha o item mais barato no sorteio. E de vez em quando ele te dá um item MÉDIO pra você não desistir de continuar e achar que tem alguma chance real. Só se você gastar MUITO (e nesse ponto você já gastou mais de 1000 créditos mesmo), só aí talvez ele te dê um item grande, pra te injetar de mais dopamina e aumentar seu <strong>vício</strong>.</p>
<p>É exatamente isso que acontece com LLMs. As respostas deles tem chances parecidas com de Loot Box. Às vezes ele te surpreende com uma excelente respostas, mas na maior parte do tempo, você fica pedindo &ldquo;cara, você tem certeza dessas resposta?&rdquo;, ou &ldquo;cara, não tá errada essa segunda linha?&rdquo;, ou &ldquo;cara, reveja o que eu perguntei e tenta de novo&rdquo;. e assim vai o seu dia inteiro.</p>
<p>Você não fica olhando, mas por baixo dos panos, cada vez que tem que corrigir, ele continua gastando os mesmos créditos. No final do dia, lá se foram USD 50. Parece pouco, mas faça isso todo dia e veja quanto acumula.</p>
<p>Só que seu <strong>VIÉS DE CONFIRMAÇÃO</strong> faz você se lembrar bem de quando ele acertou, mas vai &ldquo;esquecendo&rdquo; todas as outras vezes que ele errou. E sua percepção é que <em>&ldquo;Sim, ele funciona.&rdquo;</em></p>
<p>Pior, sua baixa auto-estima e necessidade de se fazer parte de um grupo, de se <strong>CONFORMAR</strong>. Corroborado com o que lê diariamente nas notícias, como:</p>
<ul>
<li>30% de todo código da Microsoft já é feita por I.A.</li>
<li>CEO da Anthropic diz que ano que vem programadores serão substituídos por virtual workers</li>
<li>CEO da NVIDIA diz que não recomendaria seu filho a estudar mais programação</li>
</ul>
<p>E tudo isso AUMENTA O VIÉS: você acha que eles estão certos, as vezes que você mesmo experimentou a LLM errando <em>&ldquo;deve ter sido uma pequena exceção, eu que sou burro mesmo&rdquo;</em> e ACREDITA na MENTIRA.</p>
<p>Quem lembra das minhas palestras de 15 anos atrás onde eu mostrava este video?</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/iRh5qy09nNw"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Isso é um fenômeno bem conhecido, hoje em dia mais amplificado pelas redes sociais e a burrice de jornalista, que só repete o que ouve como papagaio e não faz mais perguntas críticas, do tipo: EXISTE CONFLITO DE INTERESSES??</p>
<h3>&ldquo;OpenAI usa seus chats pra treinar?¨<span class="hx:absolute hx:-mt-20" id="openai-usa-seus-chats-pra-treinar"></span>
    <a href="#openai-usa-seus-chats-pra-treinar" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Aqui vou ter que consertar uma mentira que eu venho contando pra vocês. Eu sempre repeti que não. Sua conversa não é usada pra treinamento, porque iria poluir o material de treinamento com lixo que no final não iria melhorar as respostas.</p>
<p>É meia-verdade. De fato, eu duvido muito e boto minha mão no fogo: nenhum provedor quer se arriscar a alguém encontrar um texto com copyright e levar processo. Isso já acontece, o New York Time processou porque o ChatGPT conseguiu reproduzir um texto publicado por eles. E isso meio que &ldquo;prova&rdquo; que fazia parte do material de treinamento.</p>
<p>Tem gente que coloca coisas privadas como condições de saúde, situação financeira, e até mesmo dados críticos como senhas, endereço, coisas que não deveriam mas acabam publicando porque não tem noção sobre cyber-segurança. Todo mundo cai num golpe todo dia por causa disso. A OpenAI ou Meta ou Alibaba não fazem questão de aparecer isso uma hora no chat e viralizar notícia internacional falando como eles foram irresponsáveis.</p>
<p><strong>MAS</strong></p>
<p>E é um GRANDE &ldquo;MAS&rdquo;, eles usam sim seu chat. De todo mundo. Sem copiar nenhum dado seu. Eles só precisam dos METADADOS, os dados que descrevem seu chat.</p>
<p>De cabeça aqui, sendo ingênuo e amador em treinamento, eu vejo pelo menos 2 informações importantes que você dá pra eles: o comprimento do seu chat e o sentimento das suas respostas no chat.</p>
<p>Determinar sentimento a partir de texto é um problema bem resolvido, tem algoritmos com ou sem redes neurais que conseguem determinar se o texto parece feliz, triste, bravo, angustiado ou coisas assim. Eles não precisam do conteúdo do seu texto, só precisam do SENTIMENTO que você teve na hora.</p>
<p>Somado ao COMPRIMENTO do seu Chat e como eu falei <a href="https://www.akitaonrails.com/2025/05/02/rant-llms-sao-loot-boxes"target="_blank" rel="noopener">no post anterior</a>, que o incentivo é fazer você gastar MAIS TOKENS (chat MAIS longos). NO PRÓXIMO POST vou ensinar vocês como eles fazer alinhamento, o &ldquo;fine-tuning&rdquo; do modelo. Uma OpenAI usa milhares de linhas de pares de prompts/completion pra &ldquo;forçar&rdquo; o modelo a responder de uma determinada forma. Pensa um Excel cheio de perguntas e respostas pré-prontas, que segundo seus metadados, sabemos que são as respostas mais POPULARES.</p>
<p>O objetivo não é fazer o modelo responder mais certo, porque às vezes a resposta certa é muito dura ou inconveniente pra algumas pessoas. Eu tenho quase certeza que os dados extraídos dos chats de milhões de pessoas, só isso: sentimento e comprimento. Deve ajudar a criar prompts que forçam o modelo a responder &ldquo;menos certo&rdquo; mas &ldquo;mais agradável&rdquo;, incentivando o usuário a CONTINUAR falando no chat e GASTANDO MAIS TOKENS.</p>
<p>É o comportamento mais antigo do mundo. Todo lojista sabe disso. Todo vendedor sabe disso. Todo mundo que trabalha em serviços sabe disso. Se você for certo e direto, vai soar arrogante e o cliente não volta. É melhor soar menos certo, mas mais convidativo, agradável, prestativo, etc. E o cliente volta, porque é assim que a pessoa média funciona.</p>
<p>Portanto, sim: eu acho que seus dados servem pra re-alinhar o modelo depois de treinado, pra responder mais agradável. Eles nem fazem mais questão de esconder isso. Não viram o próprio Sam Altman quando falou poucos dias trás que fizeram o ChatGPT 4 responder mais amigável, com mais personalidade?</p>
<p>É isso que eu acho que eles estão fazendo. Tornar o modelo mais inteligente está sendo um desafio. Porque - como já venho dizendo faz 1 ano - estamos batendo no teto da curva em S. Pra continuar vendendo tokens, fazendo você voltar e se viciar em falar, não precisa ser mais inteligente, só precisa ser mais agradável.</p>
<h3>Conclusão<span class="hx:absolute hx:-mt-20" id="conclusão"></span>
    <a href="#conclus%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Não existe LLM que vai estar 100% certo, 100% do tempo, a arquitetura fundamental IMPEDE que isso aconteça, não importa quanto mais façamos otimizações. Existe agora e sempre vai continuar existindo um componente de ENTROPIA. É essa aleatoriedade que produz texto que parece um humano falando e não um robô.</p>
<p>Automatizações longas e complexas demais usando essa fundação fŕagil é um ENORME erro. Claro, pra tarefas simples, curtas, focadas, ele tem uma TAXA DE ACERTO mais alta. Pra código de verdade? É SUPER baixo.</p>
<p>Nunca deixe um MCP fazer commits direto no seu repositório Git. Ferramentas como o Aider trazem &ldquo;autocommit = true&rdquo; por padrão e isso é uma enorme estupidez! Não faça isso.</p>
<p>Eu avisei.</p>
<p>Mas não tem como melhorar o código de LLMs? Talvez. 100% nunca, mas aumentar a taxa acho que dá. E pra provar que eu não sou anti-LLM nem nada disso, no próximo artigo vou tentar ensinar COMO melhorar uma LLM pra programação (com média probabilidade, não é milagre!).</p>
]]></content:encoded><category>llms</category><category>agentes-de-codigo</category><category>engenharia-de-software</category><category>off-topic</category></item><item><title>[Akitando] #144 - Modelagem de Software é Difícil? | "Ver" vs "Enxergar"</title><link>https://akitaonrails.github.io/2023/08/11/akitando-144-modelagem-de-software-e-dificil-ver-vs-enxergar/</link><guid isPermaLink="true">https://akitaonrails.github.io/2023/08/11/akitando-144-modelagem-de-software-e-dificil-ver-vs-enxergar/</guid><pubDate>Fri, 11 Aug 2023 15:57:00 -0300</pubDate><description>&lt;div class="embed-container"&gt;
&lt;iframe
src="https://www.youtube.com/embed/SmYQcaP1Jgw"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;Um dos assuntos que mais assusta iniciante é esse negócio de &amp;ldquo;modelagem de software&amp;rdquo; ou &amp;ldquo;design de software&amp;rdquo; ou &amp;ldquo;arquitetura de software&amp;rdquo;. Vários nomes que parecem ser a mesma coisa e ao mesmo tempo não serem coisa nenhuma.&lt;/p&gt;
&lt;p&gt;Hoje quero &amp;ldquo;filosofar&amp;rdquo; um pouco pra dar uma perspectiva diferente de como se deve encarar esses assuntos e talvez uma estratégia de como realmente entender como isso funciona.&lt;/p&gt;</description><content:encoded><![CDATA[

<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/SmYQcaP1Jgw"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Um dos assuntos que mais assusta iniciante é esse negócio de &ldquo;modelagem de software&rdquo; ou &ldquo;design de software&rdquo; ou &ldquo;arquitetura de software&rdquo;. Vários nomes que parecem ser a mesma coisa e ao mesmo tempo não serem coisa nenhuma.</p>
<p>Hoje quero &ldquo;filosofar&rdquo; um pouco pra dar uma perspectiva diferente de como se deve encarar esses assuntos e talvez uma estratégia de como realmente entender como isso funciona.</p>
<h2>CAPÍTULOS<span class="hx:absolute hx:-mt-20" id="capítulos"></span>
    <a href="#cap%c3%adtulos" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><ul>
<li>00:00 - Intro</li>
<li>02:08 - CAP 1 - Livros de Modelagem e Arquitetura - Devo Estudar Todos?</li>
<li>04:14 - CAP 2 - O Problema dos Tutoriais - Modelando Objetos Reais?</li>
<li>13:07 - CAP 3 - Modelando o Mundo Real - Um Exemplo</li>
<li>16:04 - CAP 4 - A diferença de &ldquo;VER&rdquo; e &ldquo;ENXERGAR&rdquo; - Michelângelo e Arte</li>
<li>21:30 - CAP 5 - Mentoria do Mundo Real - Cuidados</li>
<li>24:44 - CAP 6 - Analisando o Mundo Real - Aprendendo Ecommerce</li>
<li>33:11 - CAP 7 - Teoria e Prática - A História do Magento</li>
<li>41:07 - CAP 8 - Recomendação de Livros - Aprendendo com Especialistas</li>
<li>49:17 - Bloopers</li>
</ul>
<h2>Links<span class="hx:absolute hx:-mt-20" id="links"></span>
    <a href="#links" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><ul>
<li><a href="https://github.com/magento/magento2"target="_blank" rel="noopener">Magento 2</a></li>
<li><a href="https://github.com/spree/spree"target="_blank" rel="noopener">Spree</a></li>
<li><a href="https://github.com/morinoko/agile-dev-rails6"target="_blank" rel="noopener">Agile Web Development with Rails - GitHub</a></li>
<li><a href="https://pragprog.com/titles/rails7/agile-web-development-with-rails-7/"target="_blank" rel="noopener">Agile Web Development with Rails</a></li>
<li><a href="https://aosabook.org/en/"target="_blank" rel="noopener">The Architecture of Open Source Applications</a></li>
<li><a href="">Rails Summit 2009 - Ilya Grigorik</a></li>
<li><a href="https://www.akitaonrails.com/2009/11/18/conversando-com-luke-kanies"target="_blank" rel="noopener">Chatting with Luke Kanies</a></li>
<li><a href="https://www.akitaonrails.com/2009/05/08/railsconf-09-entrevistas-exclusivas-em-audio/"target="_blank" rel="noopener">RailsConf 09 - Exclusive Audio Interviews | AkitaOnRails.com</a></li>
</ul>
<h2>SCRIPT<span class="hx:absolute hx:-mt-20" id="script"></span>
    <a href="#script" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Olá pessoal, Fabio Akita</p>
<p>No último video resolvi falar mais sobre bancos de dados. Já tinha feito dois videos antes sobre isso e em todos fui pelo caminho mais fácil: explicar como funcionam por baixo. As engrenagens que possibilitam existir armazéns de dados. Mas explicar implementação não é tão difícil, porque eles já existem e funcionam bem.</p>
<p>O problema que eu venho me esquivando desde o começo do canal é explicar o que a maioria de nós, programadores, considera o problema mais difícil da programação: dar nomes pras coisas. Isso mesmo, não é piada. Em particular, como modelar um problema de negócios em código? O que é um design de software &ldquo;feito direito&rdquo;? O que significa &ldquo;fazer direito&rdquo;? Significa seguir Domain Driven Development? Significa usar a maioria dos Design Patterns? Significa seguir algum framework? Tem algum livro que se possa ler e aprender o que significa isso de &ldquo;modelar&rdquo;?</p>
<p>Durante toda a vida deste canal eu vim flertando com esse assunto, por exemplo quando falei do Livro The Mythical-Man Month, que afirmei ser o mais importante pra se ler. O video de hoje vai ser uma filosofada super longa e provavelmente super frustrante. Frustrante porque eu não vou dar copy e paste de material que já tem online. É só procurar que você acha tudo de patterns, arquitetura, modelagem. O objetivo do video é explicar porque muitos acham &ldquo;difícil&rdquo;, mesmo tendo todo esse material. E no final vou até recomendar outros materiais, então assistam tudo.</p>
<p>O spoiler é que não existe o &ldquo;jeito certo&rdquo; de se fazer software, mas por outro lado, o processo não é aleatório. Existe um balanço fino entre teoria e prática que é onde se encontra nossa profissão. A razão de existir programadores é justamente porque é nossa função decidir o que é &ldquo;melhor&rdquo; pra determinada circunstância.</p>
<p>Lembram do video de Não Terceirize Suas Decisões? O pior programador é aquele que é incapaz de tomar decisões. O melhor programador não é aquele que toma todas ou a maioria das decisões corretas, mas sim aquele que toma decisões possíveis no momento em que precisam ser tomadas, nem antes, e nem depois. E o que vou tentar fazer hoje é ilustrar esses conceitos. Então vamos lá.</p>
<p>(&hellip;.)</p>
<p>Como primeira opinião controversa do dia, vou afirmar o seguinte. A maioria dos livros de modelagem e design, como o Clean Code do Bob Martin, o Domain Driven Development do Eric Evans, o Design Patterns do Gang of Four, o Patterns of Enterprise Application Architecture do Martin Fowler; todos livros excelentes, mas eu acho que são totalmente inúteis no seu primeiro ano pós faculdade. Entenda: você acabou de se formar, ainda tem pouca ou nenhuma experiência em projetos reais ou em projetos pessoais ou open source. Esses livros são perda de tempo.</p>
<p>Pra ficar muito claro: eu não estou dizendo que os livros são inúteis. Muito pelo contrário, eu acho todos eles excelentes e que precisam ser estudados. Mas todos tem um pré-requisito: que você já tenha quilometragem em código. Tanto em fazer seu próprio código quanto lidar com código dos outros, especialmente código legado.</p>
<p>A estratégia é assim: nenhum desses livros você deve tentar ler de cabo a rabo de uma só vez. Folheie alguns capítulos, os iniciais. Veja os temas de cada um pelo índice, leia a primeira página de cada capítulo. Guarde. Vá trabalhar ou treinar com projetos open source. Volte daqui um ou dois meses. Folheie de novo, avance um capítulo a mais, pule pra um capítulo no meio que tem assunto que chamou sua atenção porque é compatível com o que está mexendo no momento. Guarde de novo.</p>
<p>Depois do primeiro ano trabalhando tempo integral com programação, retorne. Leia com um pouco mais de esforço. Releia os primeiros capítulos. Repita. É um processo que deveria te custar os primeiros 3, talvez 5 anos iniciais de carreira. Se fizer direito, talvez comece a entender o que esses autores queriam dizer quando estiver lá pelo quarto ano.</p>
<p>Um dos sinais que você conseguiu mesmo pular de nível junior pra pleno, é quando começa a entender o que os autores queriam dizer, e não está tentando seguir ao pé da letra o que está escrito, sem saber porque. Mas no primeiro ano, esses livros são inúteis. Você ainda não lidou com problemas suficiente pra entender esses porquês. E o importante é o porquê. Agora deixa eu dar uns passos pra trás e explicar porque.</p>
<p>Qualquer um que já tenha tido curso ou lido livro sobre modelagem de objetos já deve ter esbarrado no famoso exemplo dos animais ou veículos. Por exemplo, ambos cachorro e gato são animais. Animal é uma abstração. Portanto, parece óbvio que deveríamos fazer uma classe abstrata chamada Animal, daí podemos derivar sub-classes Cachorro e Gato que herdem de Animal, ou em linguagens mais modernas, que tenham o &ldquo;trait&rdquo; ou protocolo de Animal.</p>
<p>Ou então temos Carro e Caminhão, ambos são veículos, poderia ser essa a classe pai abstrata. Carro e Caminhão herdam de veículo. O problema com todos esses exemplos, primeiro é que eu nunca vi ninguém fazer uma classe realmente chamada Animal. Talvez quem já trabalhou em projetos de biologia ou zoológico. Mesmo se fizer um sistema de uma fábrica ou concessionária de carros, provavelmente vamos ter uma tabela ou classe mais genérica, mais abstrata ainda, como &ldquo;Produto&rdquo;.</p>
<p>O problema de sistemas de verdade é que praticamente todos os conceitos mais importantes são abstratos, não concretos. Por exemplo, o caso mais óbvio, que são os usuários de um sistema. Usuários não são pessoas? Acho que é por isso que todo iniciante começa um sistema pela tabela de usuários, porque é a única coisa que consegue se identificar, é familiar. Ou seja, tem alguma experiência. Mesmo um iniciante sabe que um usuário deve ter atributos como nome, email, telefone, endereço, RG ou CPF e coisas assim.</p>
<p>Mas rapidamente isso complica. Estamos falando dos dados de identificação de um usuário? Ou estamos falando dos dados de autenticação, como login? Nesse caso precisamos de atributos como &ldquo;username&rdquo; e &ldquo;password&rdquo;. E já começa o primeiro erro. Já expliquei nos episódios de segurança e criptografia que não gravamos senha numa tabela. Precisamos de atributos abstratos como &ldquo;salt&rdquo; e &ldquo;hash&rdquo;. Mas e two-factor authentication? Precisamos de um seed pro algoritmo de Time-based One-Time Password ou TOTP. Só se você estudou segurança vai saber disso.</p>
<p>Dá pra complicar mais. Enviar link pra redefinir uma nova senha, caso tenha esquecido. O ideal é fazer uma tabela secundária, ou no banco de dados, ou num servidor de cache como Redis. Com um ID único que só pode ser usado uma vez, e aí o ideal é logar o endereço IP da pessoa que clicar no link, pra fazermos auditoria e ver se parece suspeito. Novamente, estratégias de segurança.</p>
<p>Se deixarmos segurança de lado. Usuário é usuário, certo? Tendo nome, email e coisas assim, tá tudo certo? Não. Digamos que o cadastro é pra parte de logística de um ecommerce. Logística precisa de um endereço. Ótimo, basta pedir o endereço. Mas cuidado, uma coisa é endereço de entrega, outra coisa é endereço de cobrança. Pra você, que é iniciante, só deve conhecer o conceito que uma pessoa só tem um endereço, certo?</p>
<p>Mas não. Uma coisa é o endereço de cobrança, pra mandar nota fiscal, outra coisa diferente é o endereço de entrega, pra onde enviar o produto. Eu posso ter endereço residencial, mas posso querer que a entrega seja feita no meu endereço comercial. Mas e se você se mudar de residência? E se você mudar de emprego? Ambos vão mudar. Ou, e se eu quiser comprar e pagar no meu cartão de crédito, mas mandar entregar como presente pros meus pais? Então preciso conseguir cadastrar endereço dos meus pais. Eu deveria criar um usuário separado pros pais? Como faz?</p>
<p>À primeira vista, endereço parecia ser só meia dúzia de campos na tabela usuário. Mas agora deve começar a ficar mais claro que pode ser uma tabela separada de endereços que precisa de uma chave-estrangeira apontando pra chave-primária do usuário. Mas não é só isso. E se meu ecommerce oferece coisas como pontos por fidelidade? Quanto mais eu comprar, mais pontos eu ganho e com isso posso usar como desconto nas compras? Pontos do usuário, ficam na tabela de usuários? Não? Então onde coloca?</p>
<p>Num sistema empresarial maior, usuários podem ter vários perfis, várias visões. Usuário pode ser funcionário da empresa, e aí vai precisar de atributos como número de PIS/PASEP pra coisas como fundo de garantia.  Usuário pode ser um fornecedor ou funcionário de um fornecedor. Fornecedor tem um cadastro separado, CNPJ, número interno de fornecedor. Usuário pode ser consumidor mesmo, daí vai ter pedidos, entregas, suporte. Usuário é um conceito muito mais complicado do que se pensa e num sistema de verdade, raramente é só uma tabela. Vai ser uma coleção de tabelas e classes. Talvez um sub-sistema inteiro separado.</p>
<p>Só pra dar outro exemplo. Falei de carro. Se você é um iniciante fazendo um ecommerce pra uma concessionária ou um concorrente de webmotors da vida, poderia pensar em fazer uma tabela chamada &ldquo;Carro&rdquo;. Daí coloca atributos como &ldquo;marca&rdquo; tipo Volks ou Fiat, modelo tipo Nivus ou Corsa. Ano, combustível, chassi e coisas assim. É o que você conhece vendo o carro dos seus pais. Mas claro, isso tá longe de completo.</p>
<p>E se quiser vender caminhonetes, ou motos, ou vãs? Melhor criar uma tabela mais genérica chamada &ldquo;Produto&rdquo; então? Os atributos vão ser mais ou menos os mesmos mas podemos colocar uma coluna de &ldquo;tipo&rdquo; pra dizer se é um carro ou moto ou outra coisa. Daí é só ter colunas como preço e já era, certo? Não tá errado, mas não é só isso nem de longe.</p>
<p>Só pra dar um pequeno exemplo: em ecommerces e varejo em geral, existe o conceito de SKUs. Stock Keeping Unit, que é um item distinto de venda, seja de produto ou serviço. É um código alfanumérico. Esse código é importantíssimo pro gerenciamento de inventário, de estoque. Faz de conta, o produto Volks Nivus, tem a versão Comfortline e Highline. A Highline tem 4 cores especiais, 2 cores metálicas, 3 cores sólidas como Preto Ninja ou Branco Cristal ou Cinza Moonstone.</p>
<p>Então o Volks Nivus Highline 2023 Cinza Moonstone tem um SKU único e diferente do Volks Nivus Highline 2023 Preto Ninja. Entende porque? Se você vai na loja, não quer saber se tem o Nivus, quer saber se tem exatamente o Highline 2023 Branco Cristal. Não adianta ter estoque do Preto Ninja, não é ele que você quer. E não adianta ter o Branco do Comfortline, você quer o Highline. O SKU reflete o exato item que você quer.</p>
<p>Mesma coisa com roupa. Ah, tem a camiseta com estampa do Iron Maiden, mas só tem o tamanho M, mas você queria o G. Camiseta Iron Maiden, tamanho M é um SKU e tamanho G é outro SKU diferente. É assim que se modela produtos numa loja. Então, numa tabela de produtos o item que você cadastra não é &ldquo;Volks Nivus&rdquo; ou &ldquo;Camiseta Iron Maiden&rdquo; e sim &ldquo;Volks Nivus Comfortline 2023 Vermelho Sunset&rdquo; ou &ldquo;Camiseta Iron Maiden tamanho PP&rdquo;.</p>
<p>Mas os problemas só começaram. Porque se você é a Volkswagen, vai ter um sub-sistema separado, a da fábrica, com outro cadastro de Volks Nivus Comfortline 2023 totalmente diferente. Pra manufatura vai ter outros atributos como o BOM ou &ldquo;Bill of Materials&rdquo;. Precisa de quais peças pra montar uma unidade? Transmissão, injeção, computador de bordo, disco de freio, etc. Cada um desses itens tem estoque, tem fornecedor, tem leilão reverso no setor de compras, tem tempo de entrega pra receber essas peças.</p>
<p>Com tudo isso temos um custo de fabricação. Isso pode, ou não, estar ligado ao sistema de vendas. Primeiro, isso influi no estoque e disponibilidade. E também influi no sistema de precificação. Preço não é um valor único na tabela de produtos, como muitos iniciantes podem pensar. É o resultado de diversos cálculos. Custo de fabricação é só um dos fatores. Tem coisas com impostos. ICMS que é o Imposto sobre Operações relativas à Circulação de Mercadorias e sobre Prestações de Serviços de Transporte Interestadual e Intermunicipal e de Comunicação.</p>
<p>Faz diferença onde o carro é fabricado, pra onde precisa ser transportado, especialmente se atravessa estados. Existem impostos federais, estaduais, municipais. Tem todo um cálculo de impostos que influi no preço final. Por isso costumava ser mais barato comprar carro em Minas Gerais do que em São Paulo, por exemplo, não sei se ainda é, mas lembro que me falaram que por isso muito carro de empresa que aluga, tem placa de Minas. O preço varia por região. Mas não é só isso, tem cálculo de custo de oportunidade, depende da estratégia da empresa. O importante é lembrar que preços não são estáticos, tem diversos fatores.</p>
<p>Beleza, temos o carro fabricado, temos o preço pro consumidor final, a venda foi feita, agora o carro precisa transitar entre a fábrica de São Bernardo Campo até a concessionária em Belo Horizonte. Pra trafegar precisa da nota fiscal. Pra colocar o caminhão na rua, precisa de rotas. De onde eu puxo informação pra rota? Google Maps? Maplink? Sistema proprietário, já que eu sou grande como uma Volks?</p>
<p>E não é só isso. Se queremos implementar sistemas de pagamentos, que lidam com dados sensitivos como números de cartão de crédito e coisas assim, nos Estados Unidos, temos o PCI DSS, Payment Card Industry Data Security Standard que dita como empresas devem proteger esse tipo de informação. E estou falando &ldquo;Estados Unidos&rdquo; daí parece que não é seu problema. Mas não se esqueça que hoje empresas são multinacionais. Pode ter empresa que começou no Brasil e agora atua internacionalmente, daí precisa implementar essas normas.</p>
<p>No caso específico de privacidade, segurança de dados de consumidores, na Europa temos o GDPR que é o General Data Protection Regulation da União Européia e no Brasil temos o LGPD, a Lei Geral de Proteção de Dados, que é similar. Enfim, o ponto é que não basta só sair modelando tabelas e jogando em qualquer lugar. Cada indústria tem seus padrões e cada país tem suas regulamentações. Precisa seguir. E pior: não é um checklist simples. Algumas coisas você é obrigado, algumas coisas dá um jeitinho, depende de como lidar com o auditor. Muitas nuances não documentadas.</p>
<p>O mundo real é muito mais complicado do que simplesmente pensar em modelagem de dados da forma acadêmica, onde nos preocupamos com coisas como normalização, se queremos terceira forma normal, ou no caso de DDD se estamos falando de Bounded Context, aggregates, domain events. Ou no caso de Design Patterns, se queremos chain-of-command ou mediator. O que eu falei até agora é parte do que chamamos das tais &ldquo;regras de negócio&rdquo; e patterns, arquiteturas, DDD da vida é a &ldquo;descrição&rdquo; da implementação dessas regras.</p>
<p>O problema é que se você não entende a regra de negócio, não interessa discutir se vai escolher um Adapter ou um Proxy, se vai organizar na terceira ou quarta forma normal. Se a regra estiver errada, a implementação vai estar errada, independente se seguiu o livro do Eric Evans ou pé da letra. E falando no livro de DDD, logo na introdução ele dá um exemplo interessante de um sisteminha de entrega de mercadorias.</p>
<p>Digamos que temos as entidades Voyage e Cargo, tipo viagem e mercadoria, onde uma viagem tem muitas mercadorias. O Eric descreve um sistema que tem responsabilidade de associar cada mercadoria com uma viagem, gravar e rastrear esse relacionamento. Até aqui tudo bem. Em algum lugar do código vamos ter um método como esse:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>public int makeBooking(Cargo cargo, Voyage voyage) {
	int confirmation = orderConfirmationSequence.next();
	voyage.addCargo(cargo, confirmation);
	return confirmation;
}</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Mas porque existem cancelamentos de última hora, uma prática padrão da indústria de entrega é aceitar mais mercadorias do que é possível numa única viagem. É o que se chama de &ldquo;overbooking&rdquo;. Algumas vezes é usado um percentual simples, como 110% da capacidade, em outros casos tem regras mais complexas.</p>
<p>Isso é uma estratégia básica no domínio de entregas que é conhecido de qualquer empresário dessa indústria, mas normalmente nós, programadores, não sabemos disso. O requerimento que vem pra nós poderia ser algo como &ldquo;Permitir 10% de overbooking&rdquo;, o diagrama de classes poderia ficar parecido com isto e o código seria atualizado da seguinte forma:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>public int makeBooking(Cargo cargo, Voyage voyage) {
	double maxBooking = voyage.capacity() * 1.1;
	if ((voyage.bookedCargoSize() &#43; cargo.size()) &gt; maxBooking)
		return -1;
		
	int confirmation = orderConfirmationSequence.next();
	voyage.addCargo(cargo, confirmation);
	return confirmation;
}</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Ou seja, no código determinamos quanto é o novo máximo com 10% a mais de overbooking e vemos se a mercadoria que queremos adicionar ultrapassa esse máximo. Mas isso cria um problema: agora temos uma regra de negócio escondida, como uma cláusula de guarda, no meio do método da aplicação.</p>
<p>Segundo o Eric, essa regra de overbooking é uma política. Política é outro nome pra um design pattern conhecido como Strategy. Em resumo, esse novo código poderia ser refatorado pra ter uma classe separada de OverbookingPolicy e no método de adicionar a mercadoria na viagem, chamar o método &ldquo;isAllowed&rdquo; dessa nova classes, e assim separar a política numa entidade separada, que documenta melhor essa regra em vez de deixar misturada e escondida com o código anterior.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>public int makeBooking(Cargo cargo, Voyage voyage) {
	if (!overbookingPolicy.isAllowed(cargo, voyage))
		return -1;
	int confirmation = orderConfirmationSequence.next();
	voyage.addCargo(cargo, confirmation);
	return confirmation;
}

class OverbookingPolicy {
	public static double OVERBOOKING = 1.1;
	public boolean isAllowed(Cargo cargo, Voyage voyage) {
		double maxBooking = voyage.capacity() * OVERBOOKING;
		return ((voyage.bookedCargoSize() &#43; cargo.size()) &lt;= maxBooking;
	}
}</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Agora que eu descrevi dessa forma, deve ter ficado óbvio. &ldquo;Puts, claro, porque eu não pensei nisso antes&rdquo;. Mas o que quero expor aqui é justamente isso: pra nenhum iniciante é óbvio que isso poderia ser um strategy pattern, provavelmente não era óbvio que isso era uma &ldquo;Política&rdquo;. Todo mundo ia ter implementado do primeiro jeito e nunca ia pensar nisso. Até o dia que alguém pedisse pra mexer na regra e mudar de 10% pra 5% por exemplo. Daí iam gastar o dia inteiro tentando achar &ldquo;onde que tá definido isso no código???&rdquo;</p>
<p>Deixa eu dar outro exemplo pra ilustrar mais esse ponto. Eu gosto de quadrinhos, comics, mangá, até já me arrisquei a desenhar como hobby no passado. Todo mundo que fica empolgado com um One Piece ou Naruto da vida já rascunhou seus personagens preferidos em algum pedaço de papel e, se não for completamente iludido, sabe que saiu uma porcaria. Mas tudo bem, o objetivo era passatempo.</p>
<p>Já percebeu como todo iniciante em arte faz as mesmas coisas? Ou é paisagem de casinha com uma árvore, um sol e uma montanha. Ah sim, com uma chaminé, não pode esquecer a chaminé. Ou é close-up de rosto de anime. Agora, tenta desenhar um quarteirão de uma cidade, com ângulo olhando de cima. Ou tenta desenhar uma personagem de anime mesmo, sentada numa mesa com as pernas cruzadas e tomando um café. Vai sair a coisa mais torta do mundo, se sair.</p>
<p>Desenhar prédios pode parecer fácil, só retângulos, mas tente fazer um. Não vai conseguir. Convivemos a vida toda do lado de prédios, andamos todos os dias na frente de vários, por anos. Mas nunca paramos pra realmente olhar, observar, absorver os detalhes e, mais importante, nunca pensamos porque determinados aspectos de um prédio são tão particulares. Nunca tivemos treinamento formal de urbanismo. Não paramos pra pensar em zoneamento, por exemplo. Certas áreas não podem ter prédios comerciais, certas áreas tem limite na quantidade de andares. Quem mora perto do aeroporto de Congonhas sabe disso.</p>
<p>Por isso quando você tenta desenhar uma cidade, sai parecendo desenho infantil de casinha com sol. Pra ficar realista, precisaríamos ter experiência com urbanismo e arquitetura. Mesma coisa a personagem sentada de pernas cruzadas. A parte que mais chama a atenção de iniciantes são rostos. Por isso perde-se muito tempo só desenhando olhos, e com rostos sempre em posições parecidas, em 3/4.</p>
<p>Pra desenhar um corpo direito precisa estudar anatomia. Todo estudante de medicina no primeiro ano sabe isso, mas pra gente que não é médico, talvez nem fôssemos pensar nisso. Vemos pessoas na nossa frente todos os dias, em todas as posições. Mas quando você parou pra realmente observar uma pessoa? Como o tecido da calça interage com o material da cadeira, como o peso da perna cria dobras, como músculos como o biceps femoral e o soleus se mexem quando dobramos a perna?</p>
<p>Quando falamos de arte, imediatamente pensamos em coisas como a Capela Sistina, o magnum opus de Michelangelo Buonarroti. Contém cenas super detalhadas e difíceis como o Último Julgamento ou a Criação de Adão. É um trabalho de mais de 500 metros quadrados. Sabe quanto tempo levou pra pintar aquele monstro? Quatro anos inteiros, de 1508 a 1512, usando tecnologia do século XVI.</p>
<p>Entenda, quando Michelangelo começou o projeto da Capela Sistina ele tinha 33 anos. Mas começou a estudar arte desde muito cedo, provavelmente pelos 13 anos de idade e já como discípulo de Domenico Ghirlandaio. Depois estudou escultura sob a tutelagem de Lorenzo de&rsquo;Medici. Por anos, estudou e produziu pinturas, esculturas e já tinha entregado nada menos que a Pieta e a escultura de David antes da Capela.</p>
<p>Naquela época, a arte não era estruturada e bem dividida como hoje. A maioria dos grandes nomes como Michelangelo, chamamos de polimatas. Mas eles mesmos não se chamavam de &ldquo;polimatas&rdquo;, isso é um termo moderno. Só hoje que dividimos que anatomia é mais coisa de médico, lentes e ótica é mais coisa de fotógrafo, urbanismo é mais coisa de arquiteto, pincel é mais coisa de artista. Antigamente não existia essa divisão. Existia o problema e que conhecimentos a pessoa achava que precisava pra resolver o problema. Ponto.</p>
<p>Um artista estudava seja lá o que precisava pra melhorar sua arte. Um bom artista é crítico do seu próprio trabalho. Se ele nota que toda escultura que faz não se parece em nada com uma pessoa de verdade, que escolha ele tem? Vamos lá dissecar corpos de pessoas mortas pra investigar como a pele realmente funciona, como os órgãos influenciam o movimento e assim por diante.</p>
<p>Não existe isso que um artista só precisa estudar cores e pincel. Não existe isso que um programador só precisa estudar algoritmos e código. Um bom profissional estuda o que for necessário pra ser a melhor versão dele mesmo. Pra finalizar. Eu estava refletindo sobre animes outro dia. Já notaram como é muito comum ter várias histórias que se passam no colégio? Romance sempre é romance entre estudantes no colégio. Aventuras sempre são com adolescentes.</p>
<p>Tirando o cinismo de achar que tudo é fetiche, a resposta pode ser  mais simples do que isso. É só um chute, mas a maioria dos desenhistas de mangá começa a trabalhar logo depois do colégio, ou até abandona o colégio. E esses desenhistas fazem tudo: inventam a história e desenham. O que é a única experiência de vida que eles tiveram até esse momento? O colégio.</p>
<p>Você, iniciante que ainda não entrou na faculdade, ou mesmo recém formado, é a mesma coisa. O que você conhece sobre a vida e o mundo? Nada. Sua única experiência foi o colégio, seus únicos amigos foram do colégio, os únicos problemas que teve que resolver eram relacionados ao colégio. Festas, trabalhos, tudo. Aos 20 e poucos anos, seu conhecimento sobre o mundo é minúsculo.</p>
<p>Parece coisa de boomer dizer isso, mas é verdade: até começar a pagar seus próprios boletos em dia, você ainda é uma criança. Eu já disse isso em outros videos e vou repetir: é impossível ser um empreendedor que vai inovar o ecommerce aos 20 anos. Você nunca trabalhou num ecommerce. É impossível inovar o setor hospilar com 20 anos, você nunca trabalhou como médico. É impossível inovar o setor agrícola com 20 anos, você nunca sequer levantou uma enxada na vida. É impossível inovar qualquer setor com 20 anos, você nunca produziu nada com 20 anos.</p>
<p>E eu volto a esse ponto porque, pra programadores, temos exatamente esse problema quando discutimos modelagem de bancos de dados, modelagem de orientação a objetos, modelagem de arquiteturas. O que significa modelar? Modelar é representar alguma coisa do mundo real de uma forma abstrata. Mas eis o problema: o que você conhece do mundo real? Quase nada. Não tem como modelar alguma coisa que não se conhece.</p>
<p>Antes que alguém vá nos comentários discordar. Óbvio, eu sei que existem exceções. É por isso que se chamam exceções. Com esse disclaimer feito, vale relembrar porque estou cagando regra nesse assunto. Vamos lá, eu trabalhei em projetos de software de vários tipos de negócios diferentes. Telecomunicações, varejo, manufatura, RH, infraestrutura, agências, grandes corporações, startups. Em 30 anos passei por várias indústrias diferentes e por isso consigo comparar o que cada uma faz de diferente. E mesmo assim não posso dizer que sei tudo. Por isso aviso pra desconfiar de qualquer um que queira ensinar sem nunca ter tido experiências similares.</p>
<p>Professores de faculdade, a maioria, não tiveram essa experiência, mas eles estudaram pra profissão de ensino, fizeram pedagogia, psicologia. Eles foram treinados pra ensinar. Alguns melhores que outros, não importa, mas essa é a carreira. Porém, a grande maioria dos que criam cursos online não tem nem perto da minha experiência e nem perto do treinamento de um professor. Portanto o que tem a oferecer? Quase nada. Eles dependem de caçar material na internet, empacotar como se fossem deles e vender pra você com um discurso que parece convincente e promessas que nunca vão ser cumpridas.</p>
<p>Veja o exemplo do Michelangelo que falei. Seu primeiro mentor foi Domenico Ghirlandaio. Quem foi ele? Foi um pintor renascentista de terceira geração, especializado em frescos e fez diversos trabalhos importantes, embora não do calibre do seu aluno. Porém, ele reconheceu esse talento e foi ele quem recomendou Michelangelo pra academia de Medici. Parece ter sido um bom professor, que teve ele próprio uma boa carreira, suficiente pra catapultar seu aluno prodígio.</p>
<p>O ideal é se fosse possível todo aluno ter a possibilidade de ser mentorado por alguém experiente assim. Infelizmente isso não é possível. Não existem mentores suficientes pra todo mundo. Por isso eu digo que o correto, antes de tentar empreender qualquer coisa por conta própria, é iniciar a carreira em empresas de verdade, que tem problemas e soluções de verdade e aprender as outras áreas que não é possível ensinar numa faculdade.</p>
<p>Eu tive vários mentores que nem sabiam que estavam me mentorando. Quando eu tinha que ajudar a resolver um problema de marketing, tive a oportunidade de trabalhar com pessoas treinadas em marketing e entender o básico de como eles pensam. Quando tive que resolver problemas financeiros, tive a oportunidade de trabalhar com pessoas treinadas em contabilidade e finalmente entender coisas cabeludas como impostos. Quando tive que resolver problemas de varejo, tive a oportunidade de trabalhar com pessoas com experiência real em vendas e ver como de fato fechavam negócios. Nenhum curso ensina essas coisas.</p>
<p>O problema de todo programador é que ele assume que a parte mais difícil e mais importante é só a programação, e que todo mundo que não é programador é mais burro que ele. Por isso tem tanta dificuldade de entregar valor. Óbvio, o cliente deveria ter te explicado melhor. Basta o cara do marketing deixar de ser burro e escrever uma especificação melhor que você, o gênio, não precisa perder tempo pensando e pode só escrever seu maravilhoso código em paz.</p>
<p>Falando em ecommerces. Deixa eu dar um exemplo mais concreto. Vou falar de Ruby on Rails porque ainda é a área que eu lembro de mais referências, mas o mesmo exemplo vale pra qualquer outro framework da vida. Um dos primeiros livros que todo mundo que quer aprender Rails usa  é o Agile Web Development with Rails. Originalmente escrito pelo lendário Dave Thomas, mantido atualmente por Sam Ruby. Aliás, excelente nome pro autor de um livro de Rails.</p>
<p>Enfim, o livro é um grande tutorial pra desenvolver um mini-ecommerce à medida que explica como funciona o framework Rails. No fim, temos uma aplicação web que mais ou menos se parece com um ecommerce. Mas lembrem-se, o livro não é sobre como fazer o melhor ecommerce, só em como dá pra usar Rails pra implementar uma versão simples de um. Resolvi procurar no Github e achei o código do que é mostrado no livro, pro Rails versão 6.</p>
<p>Usando a ferramenta Tokei, podemos ver que no final do livro, seu projeto vai ter mais de 100 arquivos de Ruby, quase 2.700 linhas de código. Além de 17 arquivos de javascript que dá mais de 1.300 linhas de código. Fora outras coisas como stylesheets em Sass e um monte de arquivos JSON. Parece bastante coisa né?</p>
<p>Por acaso, no ecossistema Rails existe uma plataforma aberta de ecommerce chamada Spree Commerce. Muito boa por sinal. Eu trabalhei com ela anos atrás e até conheci o autor original Sean Schofield. Na época era um projeto monolítico, mas em anos recentes dividiram em sub-projetos. Inclusive acho que a interface web agora é feita em Next.js e o projeto principal virou mais um servidor de APIs. Vamos ver só esse repositório principal com o Tokei e olha só a diferença: temos mais de 1.300 arquivos de Ruby, mais de 92 mil linhas de código Ruby.</p>
<p>Comparado com o projetinho do livro de Rails, estamos falando de uma diferença de 34 vezes o volume de código Ruby. E isso porque não tem nenhuma lógica de front-end, só a lógica de backend mesmo. Se pegarmos só um arquivo, o da ordem de venda propriamente dita, que ambos chamam de &ldquo;Order.rb&rdquo;. O do livro é super curto, pouco mais de 50 linhas. No Spree tem mais de 700 linhas e isso porque tem um sub-diretório com outros arquivos que sub-dividem ainda mais a lógica como &ldquo;address_book.rb&rdquo; ou &ldquo;checkout.rb&rdquo; ou &ldquo;payments.rb&rdquo;. É ordens de grandeza mais complexo.</p>
<p>Agora vamos fazer uma conta de padeiro. O livro Agile Web Development with Rails tem mais de 600 páginas. Se consideramos que o produto final dele é 34 vezes menos complexo que o backend do Spree. Pra explicar o Spree do zero, o livro talvez tivesse que ter então 20 mil páginas. Tem idéia do que isso significa? Coloca em perspectiva, os 5 livros de A Song of Ice and Fire, que deu origem ao Game of Thrones, male male tem umas 4 mil páginas. Ou seja, precisaria de 5 vezes o volume de Game of Thrones, uns 20 volumes, pra descrever um ecommerce como o Spree do zero.</p>
<p>Deixa eu complicar mais: um Spree é um ecommerce muito bom, mas nem de longe é o mais completo. Um dos mais antigos e populares ecommerces de código aberto é o Magento. Hoje existe o Magento 2. Ele é feito em PHP e rodando a ferramenta tokei, olha só: são 2 MILHÕES de linhas de código PHP. Mais de 200 mil linhas de Javascript. O Magento sozinho, só no javascript, tem o dobro de linhas de código do que Ruby no Spree que, por sua vez, já era 34 vezes maior do que o ecommerce do livro que ensina Rails.</p>
<p>Se em 600 páginas o livro Agile Web Development with Rails conseguiu explicar uma versão simples de ecommerce que dá 2.700 linhas de código de Ruby, sabemos que PHP e Ruby não são equivalentes, mas só por diversão, o Magento, só em PHP é mais de 700 vezes maior. Seriam 700 livros. Seriam 100 coleções de Game of Thrones pra descrever do zero, no mínimo. Conseguem entender porque eu fico tão puto quando alguém me pergunta se tem algum livro que explica tudo? Não tem, é inviável de ter.</p>
<p>E eu vou piorar a vida de vocês. Mesmo um Magento ainda é pequeno se desse pra comparar os repositórios de código de uma Amazon da vida, com todos os seus sub-sistemas internos. O que eu estou dizendo? Entenda essa verdades: você nunca vai saber tudo. É impossível. E isso que eu descrevi é só ecommerce. Vejam meu episódio sobre SAP e seu ERP que tem meia década de idade e roda no coração de toda grande corporação no S&amp;P 500. Lembram? Só no banco de dados são dezenas de milhares de tabelas. Repetindo, dezenas de milhares de tabelas. É impossível saber tudo.</p>
<p>Se alguém ficou desesperado com esses números deixa eu contar o grande segredo: eu, Fabio Akita, nunca li o código do Spree, muito menos do Magento. Já trabalhei em projetos com eles e com outras plataformas proprietárias. Mas nunca li todo o código deles e esse é o ponto: não precisa ler tudo.</p>
<p>Posso estar enganado, mas me dá impressão que muitos iniciantes pensam que quando fazem um curso ou lêem um livro, ou um tutorial, &ldquo;como fazer seu próprio instagram&rdquo; ou &ldquo;como fazer seu próprio Facebook&rdquo;, acham que o código que sai no final já é quase a mesma coisa que o Instagram ou Facebook de verdade, faltando pouquinha coisa.</p>
<p>Ou, que o ecommerce que fez no fim do curso já é quase o Mercado Livre. Ou seja, muitos tem a noção bem errada que existe um curso ou livro que vai te ensinar 100% do que precisa saber pra fazer um produto de verdade do começo ao fim. Eu estou afirmando que não tem, não existe, e não seria prático ter. Seriam literalmente 700 livros de 600 páginas e nem isso seria tudo. Se você não consegue visualizar 700 livros, se colocados de pé um do lado do outro daria mais de 2 metros. Eu duvido que você vá ler uma fração disso na sua vida inteira.</p>
<p>Durante todos os videos do canal vim tentando explicar esse conceito. Deixa eu tentar repetir. Quando você faz faculdade de ciências da computação, em nenhum momento vai ter nenhum curso explicando como se faz um ecommerce, ou como se faz um rede social, ou como se faz um aplicativo de fintech, ou de edutech, ou de saúde, nada disso. Você aprende matérias esquisitas, como algoritmos e estruturas de dados, álgebra linear, cálculo, estatística e probabilidade. Mas onde que ensina como fazer um carrinho de compras ou lista de produtos?</p>
<p>No outro lado do espectro, você pula tudo isso e faz cursos numa Udemy da vida &ldquo;como fazer seu próprio ecommerce&rdquo; e sai com uma versão parecida com o do livro Agile Web Development with Rails que eu mostrei. Parece que é melhor, afinal, você fez um carrinho de compras e uma lista de produtos. Só que eu acabei de demonstrar que não é uma fração de projetos de código aberto como Spree ou Magento, na verdade, é de 30 a 100 vezes menor.</p>
<p>Mas eu também disse que ecommerces de verdade, como uma Amazon ou Magazine Luiza da vida, são muito diferentes do que tem num Magento. Então, como faz pra saber? Eis o ponto que eu falei sobre mentoria: você só vai saber como um Magazine Luiza funciona trabalhando dentro do Magazine Luiza. Só tem como saber como um iFood funciona, trabalhando dentro do iFood. Não tem outra forma.</p>
<p>Mas aí não é o problema do ovo e da galinha? Como eu vou conseguir trabalhar num Mercado Livre, se nenhum lugar ensina como eles funcionam? É isso que você também não está entendendo. Quando uma empresa dessas oferece emprego, nenhuma espera que você saiba como elas funcionam. Elas esperam sim, que você tenha um mínimo de ferramentas pra conseguir se adaptar ao sistema deles.</p>
<p>Por isso eu fiz videos analisando os códigos que o Twitter liberou, o código vazado do Twitch ou a arquitetura do Ingresso.com. Se não assistiu, depois assistam. Eu mesmo não trabalhei em nenhuma delas, mas é o tipo de raciocínio que é possível fazer gastando algumas poucas horas, tendo o conhecimento de base. No episódio do Ingresso.com eu falei da arquitetura de filas e salas de espera, que empresas como Amazon e outros utilizam. No episódio do Twitter explico como embeddings de álgebra linear ajudam a resolver o problema de relevância e recomendação de tweets.</p>
<p>Com a base de estatística e probabilidade, dá pra interpretar dados de monitoramento e chegar em conclusões corretas sobre comportamento dos usuários no site, baseado nos dados de navegação e compra. Com cálculo, dá pra saber como o sistema deveria se comportar, coisas com taxa e velocidade de resposta quando se aumenta o tráfego e quais estruturas de dados podem beneficiar mais certas partes do sistema. Com entendimento de sistemas operacionais e compiladores, dependendo do tamanho da empresa, dá pra trabalhar numa nova linguagem que nem existia, como já aconteceu até em empresas nacionais, como a Totus.</p>
<p>Com essa base, dá pra começar a derivar o resto do conhecimento. Uma vez dentro do sistema é que começa realmente a viver o dia a dia de operações da empresa. A burocracia fiscal, a correria de fulfillment de pedidos nos centros de distribuição, a logística de entrega, o tempo de resposta pra suporte ao cliente, as regulamentações e mudanças em leis que precisam ser refletidas no software. Com o tempo você vai aprender o que em DDD se chama de &ldquo;domínio&rdquo;.</p>
<p>O Domain, em Domain Driven Design, só faz sentido se você sabe o que compõe esse domínio. No exemplo que usei no começo do video, saber que SKU faz parte do domínio de inventário, ou saber que checkout faz parte do domínio de pagamento. E isso que eu acabei de falar não é absoluto. Em outra empresa, checkout pode fazer parte de um domínio maior chamado &ldquo;vendas&rdquo;, ou o checkout é tão complexo que pode ser um domínio por si só. Domínio, as tais &ldquo;regras de negócio&rdquo;, varia de empresa pra empresa, de projeto pra projeto. Não é uma coisa estática. É uma referência móvel.</p>
<p>Muitos iniciantes se perguntam se deveriam estudar coisas como Design Patterns e DDD logo de cara. E sim, acho que todo mundo deveria ler pelo menos uma vez, por cima, mas com o entendimento que sem experiência real, essa leitura não vai ter muita utilidade. Arquitetura, patterns, domínios, são conhecimentos que emergem naturalmente com experiência. Não é um checklist que dá pra seguir passo a passo em qualquer projeto. Estude uma vez rápido, e mantenha os livros por perto pra consultar pontos específicos, e assuma que seu entendimento inicial vai mudar na terceira vez que ler, na quarta vez que reler.</p>
<p>Se ler só uma vez ou de forma superficial, vai cometer erros que muitos iniciantes cometem. Por exemplo, achar que Bounded Contexts é só microsserviços e resolver tudo com microsserviços. Microsserviço é um estilo de arquitetura, já bounded context é um conceito de design de estratégia em DDD, que delineia as fronteiras onde um model em particular é definido e aplicável. Você pode ter bounded context num monolito simplesmente usando namespaces e módulos, por exemplo.</p>
<p>Ou então achar que DDD é basicamente só Event Sourcing e CQRS ou Command Query Responsability Segregation. Algumas partes do sistema podem realmente se beneficiar de um sistema de eventos imutáveis ou separação de escritas e leituras nos modelos. Em outros lugares vai ser overengineering. Não se aplica tudo de DDD em todos os lugares. Como diria Jack Sparrow, é mais um guideline.</p>
<p>Mesma coisa com Design Patterns ou qualquer outro livro de arquitetura. Não é pra usar tudo que se estudou em todo lugar. Saber onde usar é mais importante do que saber como usar. Uma vez que se descobre onde, o como é fácil. Muito antes de entrar nesse tipo de discussão, comece pelo básico que já falei antes: quantas vezes você já tentou baixar e rodar um Spree ou Magento ou um simples Wordpress?</p>
<p>&ldquo;Ah, mas eu sou de Python, não mexo com PHP&rdquo;. Então você é só um idiota. Porque fazer um Magento rodar não é só um problema de PHP, é subir banco de dados. Um postgres não é específico de PHP, em Python também precisa. Precisa subir um NGINX ou Apache. Numa aplicação web de Python também. Precisa saber onde e como guardar segredos como credenciais. Precisa saber como subir servidores de cache, como Memcache. Nada disso é específico de PHP. Toda aplicação web, em toda linguagem, usa os mesmos componentes. Porque você está querendo discutir patterns e arquiteturas se sequer consegue subir uma aplicação na sua própria máquina?</p>
<p>Apesar de um Magento da vida não se parecer com um Mercado Livre, os componentes e arquitetura geral é familiar. Não as linhas de código específico, mas os componentes gerais de infraestrutura, os conceitos de protocolos, redes, sistemas operacionais, configuração e tudo mais. Não é perda de tempo fuçar projetos como esses e nem mesmo as versões mais simples de tutoriais ou cursos, o meu ponto é garantir que vocês entendam que nunca vão ensinar tudo, mas como primeiro passo, tá mais que bom.</p>
<p>Outra coisa importante: um Magento tem 2 milhões de linhas de código hoje. Graças ao poder do Git, que mantém o histórico de tudo, posso facilmente voltar ao passado, pra versão 0.1.0 alpha 89, de agosto de 2014, quase 10 anos atrás, com o comando &ldquo;git checkout -b teste 0.1.0-alpha89&rdquo;. Daí podemos rodar a ferramenta Tokei de novo e olha a diferença, ele tinha mais ou menos a metade do tamanho de hoje, menos de 1 milhão de linhas de código PHP.</p>
<p>Podemos voltar pros primeiros commits, do final de 2011, começo de 2012. Não conheço toda a história do projeto. Pelo pouco que puxei no Google, parece que o Magento 1 foi criado em 2007. Uns 4 ou 5 anos depois a comunidade começou o Magento 2, por volta de 2011 a 2012. É o que os primeiros commits indicam, e a primeira versão estável só foi sair mesmo em 2015. Pelo que entendi, o Magento 2 foi um esforço homérico pra modernizar a plataforma.</p>
<p>De qualquer forma, o código inicial que serviria de base pro Magento 2 já tinha nada menos que meio milhão de linhas de código PHP. Comparado com hoje, é &ldquo;só&rdquo; um quarto do tamanho. Mas é pra dar uma noção. Levou de 2007 a 2012 pra chegar nesse meio milhão e depois quase 10 anos mais pra chegar nos 2 milhões de linhas de código de hoje. O projeto tem milhares de contribuidores. Não é um projeto que você vai varar um fim de semana e fazer igual.</p>
<p>Mas o importante é entender que todo projeto tem um dia 1 com zero linhas de código. Todo projeto de código aberto, todo grande site como uma Amazon ou Mercado Livre. No dia 1, todo projeto realmente se parece mais com o nível de código que mencionei dos tutoriais. Mas eles não ficam parados. Vão sendo testados no mundo real, feedback de usuários de verdade vão chegando, o código vai sendo moldado às necessidades do mundo real, 10 linhas se tornam 1000, que se tornam 1 milhão de linhas, ao longo de mais de uma década. E até hoje, o Magento não &ldquo;acabou&rdquo;, toda semana tem atualizações, novos commits.</p>
<p>Ao longo desse caminho, o Magento, que foi originalmente criado por uma empresa chamada Varien Inc depois virou uma entidade própria. Por volta de 2011 parece que o eBay entrou em cena e adquiriu uma parte da empresa, com objetivo de integrar com o Paypal. Mas em 2015, eBay e Paypal se tornaram duas entidades separadas e o Magento também foi separado. Daí entra a Adobe em 2018 que adquire a empresa. Hoje ela faz parte do Adobe Experience Cloud e pra contribuir no projeto você precisa assinar um acordo de Licença de Contribuidor.</p>
<p>Eis outro exemplo de como o software foi sendo adaptado pra responder a essas ações externas. Em 2007, ela não foi planejada pra fazer parte da plataforma da Adobe. O cloud da Adobe nem existia nessa época. Ninguém sabia que no meio do caminho ela iria desviar pra dentro do eBay e Paypal e nem que iria se separar poucos anos depois. O software vai se adaptando a tudo isso. A mesma coisa acontece com a plataforma de toda grande empresa. É assim que aos poucos vai virando um repositório de milhões de linhas de código. Nada disso é planejado com antecedência.</p>
<p>Modelagem é uma das respostas a esse tipo de coisa. Em algum momento, a prioridade talvez tenha sido Paypal. Em outro momento a prioridade passou a ser Adobe Cloud. Prioridades de desenvolvimento também ditam a arquitetura e arquitetura dita a modelagem. Modelagens que faziam sentido em 2011 provavelmente não fazem mais sentido em 2018. Entendam isso: software nunca está &ldquo;pronto&rdquo; ou &ldquo;finalizado&rdquo;. Se ele faz sucesso, é um trabalho constante de adaptação e evolução. Modelagem e arquitetura tem que ser respostas a essas evoluções. Elas emergem do software.</p>
<p>Todo livro, tutorial ou curso, vai simplificar isso. Não é um defeito, é uma limitação do pouco tempo. Como ilustrei até aqui, se tentar documentar tudo, precisaria fácil de centenas de volumes de livros. Ninguém ia conseguir estudar tudo isso. Nenhuma das técnicas de nenhum livro de DDD ou Design Patterns tem as respostas do que fazer em cada um desses grandes episódios. Elas servem de base pra adaptação, mas não tem nenhuma resposta pronta pra nenhum problema de negócios.</p>
<p>Do meu ponto de vista, eu diria que livros DDD ou qualquer outro de modelagem e arquitetura servem pra nos dar um vocabulário pra tentarmos nos comunicar. Tudo é abstrato em software. Não temos parâmetros físicos que todos conseguem concordar, como peso, volume, ou qualquer coisa assim. Software se chama software porque não é &ldquo;hard&quot;ware.</p>
<p>Uma simples classe de pagamento pode significar coisas extremamente diferentes pra programadores com experiências diferentes. Então tentamos racionalizar e normalizar esses conhecimentos via um vocabulário de modelagem e arquitetura pra começarmos a dar passos em busca de algum consenso, em algumas partes.</p>
<p>Pra não ficar só na filosofia, agora eu queria falar especificamente de alguns livros que acho que podem ajudar um pouco. Novamente, não são livros pra ler de cabo a rabo de uma só vez, e nem só uma vez. São livros pra se estudar um capitulo que tenha um assunto que te interessa no momento, voltar quando tiver mais experiência nesse assunto, e durante sua vida profissional ou acadêmica, quando esbarrar nos outros assuntos, vá indo um capítulo de cada vez.</p>
<p>Eu mesmo não conhecia esses livros até pouco tempo atrás, quem me recomendou foi meu sócio Talysson, que é responsável pelo programa de mentoria da minha empresa, ele mesmo um excelente programador. O primeiro livro se chama The Architecture of Open Source Applications. Ele é dividido em dois volumes. Cada capítulo é como se fosse um artigo sobre um projeto de código aberto escrito pelo próprio autor ou alguém bem experiente e reconhecido.</p>
<p>Por exemplo, o capítulo 11 do primeiro volume é sobre LLVM, que eu já expliquei em vários videos aqui do canal, como no video da Apple e GPL. E o autor desse capítulo é ninguém menos que Chris Lattner, um dos melhores engenheiros dos últimos 20 anos. LLVM tá por trás de todos os compiladores e transpilers modernos incluindo shaders de GPUs e programação de tensors pra IA.</p>
<p>O capítulo em si é super introdutório. Se você assistiu meu episódio  e outros como o de compiladores versus interpretadores, a maior parte tá lá. Ele não explica tudo, nem explica em detalhes, mas é um bom capítulo pra quem nunca parou pra ler nada sobre o assunto. A intenção é que cada autor explique porque tomou certas decisões de design do software em que trabalhou. Coisas que hoje achamos óbvio, mas que pra época não era tão óbvio assim.</p>
<p>No volume dois, capítulo 14 temos o projeto NGINX, que eu também já falei várias vezes em episódios como Tornando sua App Web mais Rápida. O autor é Andrey Alexeev, um dos co-fundadores do NGINX. E de novo, é um capítulo bem curto, onde ele fala o óbvio: porque alta concorrência é importante, ou porque não usar Apache. Hoje, é óbvio, mas 20 anos atrás não era e ele explica porque o NGINX foi feito da forma como conhecemos hoje.</p>
<p>No capítulo 18 do volume II encontrei um nome conhecido. Luke Kanies, um dos criadores do Puppet. Hoje em dia, quando falamos de infraestrutura como código, lembramos de Kubernetes, Terraform, ou Ansible, mas Puppet foi um dos precursores, quando codificar infra não era óbvio. Eu entrevistei ele pro meu blog em 2009, vou deixar o link nas descrições.</p>
<p>Já no capítulo 15 do volume 1, outro nome conhecido, Francesco Cesarini. Todo mundo da comunidade Erlang e Elixir conhece esse nome, um excelente educador e evangelista. E foi num workshop dele que eu tive meu primeiro contato com Erlang, também em 2009. Você também pode ter seu primeiro contato com ele nesse capítulo. Enfim, todos os autores desses livros são excepcionais. Eu seria feliz de ser uma fração de qualquer um deles.</p>
<p>O terceiro livro dessa série é o The Performance of Open Source Applications. É o mesmo formato, cada capítulo com um autor que é reconhecido no assunto, mas focado na parte de performance. Logo no primeiro capítulo temos Ilya Grigorik falando sobre alta performance de rede no Chrome. Ilya é outro conhecido de longa data da comunidade Ruby, que eu trouxe pra RailsConf Brasil 2009. Daí ele foi pro Google, hoje está no Shopify e ensinou nossa comunidade sobre métricas, como medir, as melhores ferramentas, quais as prioridades de otimização, e ajudou a definir muito dessa área de performance junto com a W3C. Todo desenvolvedor web deveria ler alguns dos artigos dele sobre performance.</p>
<p>O quarto e último livro é um pouco mais prático e pode servir pra vocês se exercitarem em linguagens diferentes. Se chama &ldquo;500 Lines or Less&rdquo;, cujo objetivo é desenvolver uma mini aplicação em 500 linhas ou menos. Por exemplo, no capítulo 19, Audrey Tang nos ensina a fazer uma mini planilha, tipo Excel, com Angular.js. Ou Allison Kaptur que ensina a fazer um mini interpretador de Python, em Python. Se estava procurando exercícios, vale explorar esses capítulos. De novo, nenhum deles é uma aplicação completa de verdade, só os princípios pra quem nunca parou pra pensar &ldquo;hm, como eu faria um servidor web simples do zero?&rdquo;, esse é o capítulo 22.</p>
<p>Eu não procurei mas acho que nenhum desses livros tem em português. Mas neste site, que vou deixar o link na descrição abaixo, tem tudo gratuito online. Basta abrir seu navegador e começar a explorar. Eu deixaria uma aba permanente só pra ela, pra não se esquecerem de voltar de tempos em tempos. Como disse antes, não é pra ler tudo de uma só vez. Em particular, o &ldquo;500 Lines or Less&rdquo;, é pra abrir um editor de texto e realmente tentar codificar, senão não vai servir pra nada. Alguns capítulos vão usar linguagens que talvez nunca tenham tentado, como Clojure. É uma boa desculpa pra experimentar. E mesmo se não gostar, outro bom exercício é repetir o mesmo exercício em outra linguagem.</p>
<p>Todos os livros eu diria que são adequados pro nível junior até pleno. De pleno pra senior, diria que são textos fáceis. E mesmo assim talvez tenha assuntos que vocês não tenham parado pra estudar ainda. Por exemplo, no volume 1 do The Architecture of Open Source Applications, o Russel Bryant fala do lendário Asterisk. Se nunca trabalhou em projetos de voz sobre IP, antes de existir coisas como Zoom ou Google Meet, talvez nunca tenha ouvido falar. Mas muita gente ainda usa. É tipo um PBX digital. Eu mesmo nunca mexi pessoalmente, mas trabalhei próximo de projetos que usavam, então é um pouco familiar pra mim. Só porque uma pessoa é considerada sênior numa coisa, não quer dizer que é sênior em tudo. Em Asterisk eu não sou mais que um junior.</p>
<p>O maior problema no estágio inicial é que você não sabe o que não sabe. Livros como os que recomendei e projetos de código aberto, como um Magento da vida, são ótimas portas de entrada pra molhar os pés e começar a se familiarizar com código mais complexo e mais real do que tutoriais ou cursos. Não tem nenhum problema aprender via cursos, mas não fique obcecado em achar que quantidade de tutoriais ou cursos vai determinar sua qualidade. Porque não vai. Depois de um certo ponto, sem experiência, você vai estagnar ou pior, só ter a ilusão que está aprendendo. E experiência não é só no trabalho. Você nunca vai parar de estudar e nunca vai saber tudo. Essa é a carreira.</p>
<p>Pra saber se aprendeu mesmo, precisa contribuir código em projetos. Primeiro em exercícios sozinho na sua própria máquina, depois, se possível, em projetos de código aberto mais simples, ou já direto em projetos fechados de empresas. Se puder escolher, escolha empresas que tem desenvolvedores sêniors em quem se espelhar, idealmente que podem te mentorar. Mentorar não é professor e aluno, onde você como aluno fica passivo só esperando alguém te ensinar alguma coisa. É se virar pra fazer e alguém te dar orientação e feedback. A melhor coisa é alguém apontar o que você fez de errado quando achava que não tinha nada errado. Ou seja, apontar o que você não sabia que não sabia.</p>
<p>E tire da cabeça que só tem valor conseguir emprego numa empresa de nome grande como Amazon. Não. Qualquer empresa que tenha software é oportunidade de aprendizado. Não importa se o software é &ldquo;legado&rdquo;, antigo. Você nunca programou nada real. Não importa se é na lojinha da esquina ou no Magazine Luiza. Todo software é software. Basta não ficar 20 anos no mesmo lugar, fazendo a mesma coisa. Mas também, menos de 1 ano não é proveitoso. Tem que ter um período pra aprender tudo que puder aprender, em particular, tudo que você ainda não sabe que não sabe.</p>
<p>Como disse lá no começo, esse episódio poderia ser um pouco frustrante. Porque não tem uma resposta simples pra dizer como aprender a modelar, ou decidir arquiteturas, ou fazer um bom design de software. Sua versão 1.0 de tudo vai ser sempre ruim, e isso não é um defeito, é simples falta de experiência. À medida que se trabalhar em empresas ou participar de projetos de código aberto e se exercitar mais, os gaps de conhecimento vão ficando aparentes. E você vai começar a finalmente entender o que não sabe, pra conseguir ir atrás de saber.</p>
<p>A idéia não era tentar dar uma resposta definitiva, só abrir os conceitos pros iniciantes terem uma noção melhor do que tem pela frente. E o conceito principal é que você nunca vai saber o que é um &ldquo;bom software&rdquo; sem antes fazer muito mau software e lidar com mau software dos outros. Não existe um checklist que define todas as características de um bom software. Bom é relativo ao que se espera daquele software. E tudo que chamamos de modelagem ou design, são meros vocabulários pra tentar descrever essa abstração que chamamos de software. Se ficaram com dúvidas, mandem nos comentários abaixo. Se curtiram o video deixem um joinha. Assinem o canal e não deixem de compartilhar o video com seus amigos. A gente se vê, até mais.</p>
]]></content:encoded><category>arquitetura-de-software</category><category>engenharia-de-software</category><category>aprendizado</category><category>akitando</category></item><item><title>[Akitando] #130 - Rant: Projetos, TESTES e Estimativa??? | Rated-R</title><link>https://akitaonrails.github.io/2022/10/25/akitando-130-rant-projetos-testes-e-estimativa-rated-r/</link><guid isPermaLink="true">https://akitaonrails.github.io/2022/10/25/akitando-130-rant-projetos-testes-e-estimativa-rated-r/</guid><pubDate>Tue, 25 Oct 2022 10:30:00 -0300</pubDate><description>&lt;div class="embed-container"&gt;
&lt;iframe
src="https://www.youtube.com/embed/H_-7o_pLn1s"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;Finalmente vou discutir um pouco sobre Programação Orientada a Testes e o que isso tem a ver com gerenciamento de projetos, equipes, e um pouco sobre como todo mundo ainda encara estimativas da maneira errada.&lt;/p&gt;
&lt;p&gt;Este video é pra você programador, gerente, cliente, empreendedor, que tem dificuldades de entregar projetos de qualidade. Vamos entender tudo que vocês estão fazendo de errado e porque dá errado.&lt;/p&gt;</description><content:encoded><![CDATA[

<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/H_-7o_pLn1s"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Finalmente vou discutir um pouco sobre Programação Orientada a Testes e o que isso tem a ver com gerenciamento de projetos, equipes, e um pouco sobre como todo mundo ainda encara estimativas da maneira errada.</p>
<p>Este video é pra você programador, gerente, cliente, empreendedor, que tem dificuldades de entregar projetos de qualidade. Vamos entender tudo que vocês estão fazendo de errado e porque dá errado.</p>
<p>== Conteúdo</p>
<ul>
<li>00:00 - Intro</li>
<li>01:13 - CAP 01 - Suas Premissas estão Erradas - Esqueça Bullshit</li>
<li>05:33 - Programadores não são Pedreiros!</li>
<li>08:31 - CAP 02 - Provas de Conceito - Comecem a Fazer!</li>
<li>13:01 - CAP 03 - Programação Orientada a Testes - Comecem a Fazer!</li>
<li>17:53 - Demonstração de testes de Firefox</li>
<li>19:02 - Demonstração de testes de React</li>
<li>19:27 - Demonstração de testes de Tailwind</li>
<li>19:57 - Demonstração de testes de Django</li>
<li>20:28 - Demonstração de testes de Laravel</li>
<li>21:06 - Demonstração de testes de VSCode</li>
<li>22:14 - Demonstração de testes de Rust</li>
<li>24:02 - Demonstração de testes de Spring Boot</li>
<li>27:25 - Vocês não SABEM fazer testes!</li>
<li>28:45 - CAP 04 - Como a falta de Testes afeta Produtividade? A Raíz do Ágil</li>
<li>32:27 - Como é um fluxo de trabalho Ágil?</li>
<li>37:01 - CAP 05 - O que significa Estimar? Estimar não é Prever</li>
<li>47:27 - CAP 06 - Removendo Maus Elementos. Não acumule problemas.</li>
<li>50:07 - CAP 07 - Resumindo os Princípios: O Mínimo pra Começar</li>
<li>52:27 - Bloopers</li>
</ul>
<h2>SCRIPT<span class="hx:absolute hx:-mt-20" id="script"></span>
    <a href="#script" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Olá pessoal, Fabio Akita</p>
<p>Vamos dar uma pausa na série de videos técnicos. Se não assistiu ainda, fiz uma minissérie falando sobre redes e logo em seguida começando a falar sobre Linux. Como foi muita coisa técnica, eu me entediei, então resolvi mudar a marcha hoje pra falar sobre gerenciamento de projetos, em particular finalmente quero discutir sobre o famigerado desenvolvimento orientado a testes. É um puta tema cabeludo que daria pra fazer um canal inteiro sobre, mas a idéia é discutir só alguns pontos básicos, pra iniciantes no assunto mesmo. Então vamos lá.</p>
<p>(&hellip;)</p>
<p>Se você já tem experiência, trabalha em grandes empresas e grandes projetos, certamente vai discordar de algumas coisas que vou falar hoje e não está errado. Processos de gerenciamento de projetos de software variam bastante e devem ser customizados especificamente pro seu tipo de empresa, pro seu estilo de trabalho em equipe. Não existe nenhuma metodologia que vai se encaixar magicamente em todos os lugares. Simplesmente não existe, é inútil tentar fazer isso. Eu falei sobre isso no video de Esqueça Metodologias Ágeis. Recomendo assistir esse também depois.</p>
<p>A expectativa é que existe algum conjunto de procedimentos que toda equipe consegue seguir pra manter os projetos estáveis e eficientes. Certamente deve existir algum tipo de PMI, Agile, CMMi, bla bla bla Alguma fórmula que o Spotify, o Netflix, a Microsoft, alguém inventou, que resolve todos os problemas. E não tem. Quanto mais cedo aceitarem isso, menos dor de cabeça vão ter. Se você se ver dizendo &ldquo;a gente segue o modelo Spotify&rdquo; ou segue qualquer modelo, certamente está fazendo errado. Veja no meu video do Guia Definitivo de Organizações.</p>
<p>Além disso, se você é um empreendedor não-técnico, certamente assistiu um monte de palestras motivacionais, bullshit de startups e tá fazendo um monte de coisas erradas. Eu fiz 3 videos pra vocês também, o de Empreendendo Errado com Software e o video em duas partes dos 10 Mitos sobre Tech Startups. Vou tentar não repetir o que já disse lá, então assistam depois também.</p>
<p>Vamos lá, no final do dia, você, como membro de uma equipe de desenvolvimento de software, precisa entregar alguma coisa que seu chefe ou seu cliente precisam no produto deles. Ou mesmo no seu próprio produto. Se for iniciante, é muito mais fácil integrar uma equipe que já existe, que tem membros experientes e processos já em andamento. Um iniciante sempre vai fazer errado da primeira vez, especialmente sozinho. Não tem como acertar de cara sem nunca ter feito, e isso não é um defeito, é natural. São muitas peças móveis que você nunca viu funcionando. É que nem eu dar um carro desmontado e mandar montar tudo e ainda funcionar direito no final. Impossível.</p>
<p>Vai parecer que é simples, só encaixar as peças e apertar os parafusos. Mas não é só encaixar. Precisa monitorar cada pedaço, testar, ver se não tem vazamentos, se tá tudo alinhado, balanceado, etc. Porque se sair só montando tudo sem testar nada, quando terminar e tentar ligar o carro, vai explodir. Ou, o mais provável, nem vai ligar, e ninguém vai saber porque. E agora que tá tudo montado, vai precisar desmontar tudo e ir testando. No mínimo vai ser uma grande perda de tempo.</p>
<p>Antes de mais nada, você precisa de pelo menos um membro da equipe um pouco mais experiente. Nem vou dizer sênior porque não quero ficar tentando definir hoje o que é junior ou sênior, mas alguém que já entregou no mínimo um projeto de sucesso. Porque essa pessoa precisa se responsabilizar pelas decisões técnicas. Decidir qual framework, bibliotecas, módulos, como as coisas vão ficar organizadas, como vai ser feito deployment. E lógico, todo mundo da equipe pode e deve contribuir com idéias, sugestões, mas alguém precisa bater o martelo e todo mundo seguir em frente.</p>
<p>Senão toda hora se perde tempo com discussão inútil. Um grupo cheio de opiniões que leva horas ou dias pra decidir as coisas é ineficiente e o resultado sempre vai ser uma droga. Aliás, se isso acontece, é um bom sinal que o tal sênior responsável é ruim. Nenhuma equipe respeita alguém que só fala mas não faz. Um bom sênior fala menos e mostra mais, ensina como faz na prática. E o melhor é errar cedo, ter evidências de porque a primeira decisão deu errado, e isso servir de input pra uma segunda decisão melhor. Do que ficar horas discutindo o melhor caminho, pra no final dar errado de qualquer jeito.</p>
<p>Isso talvez seja a coisa mais fundamental numa equipe. Errar antes e consertar rápido é infinitamente melhor do que horas e horas de discussão tentando chegar em consenso e bikeshedding. Ninguém tem certeza? Foda-se. Cara ou coroa. Faz um teste. Vê se funciona. Se falhar, agora veja porque falhou, conserta, e segue em frente. Essa é a essência do processo de lidar com o desconhecido. Todo mundo pensa que quando algo é desconhecido o certo é tentar planejar infinitamente até ter todos os passos minuciosamente detalhados. Mas tá errado. É desconhecido, qualquer planejamento que tentar fazer, quanto mais detalhado for, mais errado vai estar.</p>
<p>Acho que esse é o ponto principal da discussão de hoje. Quando você e sua equipe são inexperientes, das duas uma, ou vão andar super lento porque vão tentar planejar em excesso, discutir em excesso, ou vão ser kamikazes retardados que vão começar a fazer e só ir fazendo sem parar pra ver se estão indo na direção certa. Ambos estão errados. Não consigo entender porque o desespero não leva ao mais óbvio, que é errar cedo, consertar rápido e o mais importante: garantir que o que já foi feito e está certo, não quebre à toa, porque isso seria o equivalente a andar pra trás.</p>
<p>Não tem nenhum problema rascunhar o que precisa ser feito. Faça um checklist de funcionalidades. Faça post-its com cada tarefa. Faça uma planilha. Não importa. Todo mundo da equipe precisa ter uma noção geral do que precisa ser feito. Mas não tente detalhar em excesso. Só coloque detalhes no que estiver muito incerto, no momento em que precisa ser feito e não com meses de antecedência. Portanto, qualquer um que tenha estudado engenharia de software ou gerenciamento de projetos tradicional, e viu coisas como requisitos, casos de uso, ou até mesmo stories, pára. Você só precisa de uma lista, curta, com poucas palavras. Não é pra levar dias escrevendo, é pra levar horas, no máximo. Vou voltar nesse ponto mais pro fim.</p>
<p>Não importa quantos diagramas, fluxogramas, photoshops ou words vocês produzam, nada disso é o software. Pra um amador, dá impressão que o ideal é ter o máximo de páginas de requerimentos detalhados quanto possível. Tá errado. Essa noção errada vem pelo seguinte: qualquer projeto de engenharia civil, pra fazer uma casa ou um prédio, precisa de meses de planejamento, várias plantas baixas, diagramas de encanamento, diagrama elétrico e tudo mais, pra garantir que o prédio seja construído perfeitamente dentro das especificações.</p>
<p>Portanto, software deveria ser a mesma coisa. Vamos fazer quinhentas páginas de diagramas UML, que é o equivalente a planta baixa, porque daí, quando for escrever o software propriamente dito, vai sair tudo perfeitamente dentro das especificações. Essa premissa está errada. Todo mundo acha que um programador é um pedreiro. Não querendo desvalorizar o trabalho de pedreiros, mas um programador, na realidade, é o arquiteto. O trabalho de pedreiro, é 100% automático desde sempre. O pedreiro de software é o compilador ou interpretador. A planta baixa É o código fonte do software. Portanto todo programador, quer ele queira ou não, faz trabalho de um arquiteto.</p>
<p>Lógico, se sua linha de trabalho é só instalar Wordpress pra diversos clientes. Não se está produzindo software novo, só copiando e colando o que já existe e esse trabalho, sim, parece mais uma linha de fábrica. Mas estamos falando de fazer software que não existe, quase do zero. Reusando vários componentes como frameworks ou bibliotecas, sim, mas o software final não seria possível fazer numa linha de fábrica. Cada passo no desenvolvimento desse software requer tomadas de decisões de cada programador envolvido. Não existe receita.</p>
<p>O famoso exemplo de fazer um botão com cor na tela. Dá pra fazer de dezenas de jeitos diferentes. Posso fazer todo o CSS e HTML do zero. Posso escolher usar um Tailwind da vida. Mas se escolher isso, não pode ser só pra um botão, o certo é usar em todos os botões e elementos gráficos de todas as telas. Eu quero isso? Posso escolher fazer todo o sistema de eventos do zero ou usar React ou Vue. Mas de novo, isso vai afetar todo o sistema. Qual minha equipe tem mais facilidade pra usar? Já tinha começado como um sistema em Angular? Se eu decidir que quero usar Vue no lugar, quanto custa reescrever tudo? Vale a pena?</p>
<p>Tudo são decisões. Muitas sem grandes consequências, mas algumas podem quebrar seu projeto inteiro se feito de forma irresponsável. Como se toma esse tipo de decisão? Não tem receita pra isso. Na maioria das vezes, seu prazo tá apertado, e o ideal é não escolher decisões que envolvam jogar tudo fora e fazer tudo de novo, então isso já elimina várias escolhas. Mas algumas são incertas, se der certo talvez vocês ganhem produtividade pra frente. Pra isso se fazem provas de conceito.</p>
<p>Todo mundo ignora o poder das provas de conceito. Prova de conceito ou protótipos são pedaços de código, uma pequena parte da aplicação, que deve ser feito com o objetivo de potencialmente jogar fora depois. Portanto não precisa ser integrado ao código principal. Pode ser feito como uma branch do repositório, o que num GitHub chamamos de pull requests ou num GitLab chamamos de merge requests. Tecnicamente é um desvio no repositório de código. Enquanto todo mundo continua trabalhando no tronco principal, a branch <code>main</code>, alguém trabalha nesse desvio, num galho, por alguns poucos dias, pra ver na prática se a mudança sugerida realmente trás benefícios ou não.</p>
<p>Provas de conceito tem que ser um empreendimento curto, um micro-projeto de prazo fixo. Coisa de 2 dias, uma semana no máximo. Mesmo estando incompleto, no final desse período deve dar pra equipe ver na prática como a idéia se materializa em código, os impactos que causa, e se todo mundo está confortável em seguir em frente. Daí pode até jogar fora esse galho e todo mundo voltar pro tronco principal aplicando seja lá qual seja essa mudança técnica. Ou então se prova que a idéia era mais complexa do que se imaginava, e todo mundo descarta essa idéia. Mas isso não foi perda de tempo.</p>
<p>Você tem 10 grandes dúvidas técnicas que podem custar muito tempo, coisas no nível: devemos usar React ou Vue? Devemos ficar no Postgres ou migrar pra Firebase? Devemos ficar só em APIs REST ou já começar tudo em GraphQL? Vamos dar deploy das coisas em Vercel ou criar Terraform pra AWS? Só que ninguém da equipe nunca teve muita experiência em nenhuma dessas coisas. Cada uma pode potencialmente custar 2 a 4 meses. Sua equipe só tem 3 pessoas. Então fácil, se for fazer tudo, não vai sair por menos que 10 meses pra equipe, e com a falta de experiência, fácil vai virar o ano.</p>
<p>Em vez disso, pára tudo, cada um da equipe vai fazer provas de conceito de cada coisa, num prazo máximo de 2 semanas. E esse prazo é fixo, depois de 2 semanas vamos ver o que saiu. No final, mais da metade dessas coisas se provam realmente mais complicadas ou o custo claramente não vai compensar. Em vez de ir em frente com 10 coisas incertas que vai custar pelo menos 1 ano pra fazer, vocês concordam agora em desistir de 7 delas, porque a prova de conceito deu evidências que não vai dar certo. Por outro lado, 3 dessas coisas se provaram boas, e vocês vão seguir em frente.</p>
<p>Ao custo de 2 semanas da equipe, vocês economizaram mais de meio ano de trabalho que ia dar errado, e vão prosseguir com 3 coisas que vão custar um mês da equipe e que todo mundo tem mais certeza que vai dar certo. Esse é o grande truque: não se comprometa com coisas de longo prazo que ninguém tem certeza. Pague um tempo curto pra descobrir se dá pra cobrir essa incerteza. Não é jogar tempo fora, é pagar um pouco pra não jogar muito mais fora. Essa noção deveria ser simples, mas na minha experiência, pouca gente parece entender que mais vale a pena jogar fora 2 semanas do que se comprometer cegamente com um projeto incerto que vai levar um ano.</p>
<p>Na cabeça de muita gente, como 1 ano tá longe, fica aquela sensação de &ldquo;vamos indo, lá na frente a gente vê como faz&rdquo;. Especialmente em tech startups que vivem de dinheiro de investimento, esse tipo de decisão errada acontece muito, porque afinal é muito mais fácil gastar o dinheiro dos outros. E mesmo quem tem que gastar do próprio bolso, fica apreensivo com essa noção de &ldquo;jogar 2 semanas fora&rdquo;. Só que não é &ldquo;jogar fora&rdquo;, é o mesmo que pagar um seguro.</p>
<p>Ninguém gosta de pagar mil reais, dois mil reais, todo ano, que ao final do ano, parece que não serviu pra nada. Só que se durante esse ano tiver um acidente, e você atropelar e machucar alguém, agora não é dois mil reais que vai custar, vai ser 100 mil, 200 mil reais. Quem faz economia porca e fica de bravata achando que &ldquo;não precisa, não vai acontecer&rdquo;, é o primeiro que se envolve em acidentes e depois fica falido. Em projetos é a mesma coisa. Se for coisa que você já faz várias vezes antes, o risco é baixo, já sabe o que tem que fazer, tem noção de quanto vai custar e mais ou menos sabe o que pode ou não dar errado, então consegue ir em frente. Mas se nunca fez, é melhor fazer um teste antes de decidir.</p>
<p>E caindo no dia a dia de programação, é esse o mesmo argumento de porque falamos que todo programador deveria fazer, no mínimo, testes unitários de tudo que está trabalhando. Toda nova funcionalidade, deveria ser coberta de testes. Toda correção de bugs, deveria começar com um teste que simula o bug, pra que já comece falhando, e você sabe que corrigiu quando esse teste passa. Não só isso, esse bug em particular não vai acontecer de novo. Todo teste que você começa escrevendo antes de fazer o código, é como uma mini prova de conceito antes de tentar fazer uma coisa que não tem muita certeza. Se não tem certeza, comece escrevendo um teste.</p>
<p>Muitas pessoas já me pediram pra fazer um video sobre testes, mas eu realmente não tenho vontade, porque testes é um assunto que tem já toneladas de documentação, livros, tutoriais, cursos, blog posts, PDFs gratuitos online, pra cada linguagem diferente, pra cada framework. Testes não é um troço que você aprende em 5 minutos e faz igual pra sempre. É um conjunto de técnicas. O ideal é um junior parear com alguém mais experiente e aprender na prática: quando precisa fazer, e com que nível de detalhes. É muito importante que sua equipe tenha pelo menos uma pessoa mais experiente que entende a importância de ter testes e oriente os demais a fazer.</p>
<p>Deixa eu fazer o sales pitch de 2 minutos de porque todo programador deve fazer testes, de porque nenhum pull request pode ser mergeado sem testes, e porque uma pessoa que se diz sênior e é contra fazer testes, por definição, não deveria se considerar sênior. Toda regressão é tempo e dinheiro jogado fora. E o que é uma regressão?</p>
<p>Regressão é exatamente o que o nome diz. Se até este momento, digamos que alguém de QA testou tudo e tinha zero bugs. Alguém me faz um pull request que ficou trabalhando sem integrar por duas semanas. Sem testar. E dá merge na master. Faz deploy, e o que acontece? Surgem um monte de bugs. Não só na funcionalidade que ele tava trabalhando, mas em outros lugares que antes funcionava. Esse amador regrediu o trabalho de todo mundo. Tudo deu passos pra trás.</p>
<p>Agora o certo é dar revert nesse pull request, reverter mesmo. Só que esse pull request não tem mais como voltar atrás, porque dar deploy, ele alterou o schema do banco de dados e não tem como voltar mais ao schema anterior sem um grande downtime. Um desastre. E, claro, tenha certeza que esse indivíduo fez esse deploy na tarde de sexta-feira. Lógico. Cancela o happy hour porque a noite de sexta vai ser longa, fim de semana adentro, pra consertar essa cagada.</p>
<p>O fluxo é simples: todo programador, seja fazendo testes-antes ou testes-depois, quando diz que concluiu seu pull request, também adicionou um mínimo de testes, fez rebase com a master, e indicou pra equipe que tá tudo pronto. Alguém da equipe sempre deve avaliar esse pull request, normalmente alguém mais experiente. Pelo menos pra bater o olho e ver que não tem nada que parece muito mau feito ou muito fora do lugar e, principalmente, se tem testes. Se não tiver, já rejeita.</p>
<p>Se for uma equipe minimamente bem equipada, está usando repositórios privados de Git seja num GitHub ou GitLab. Ambos tem suporte a rodar testes automatizados num serviço separado. Nesse momento ele já puxou o que está nesse pull request, subiu um container de docker, e executou os testes automatizados do projeto. E quando o avaliador for checar o pull request, já vai saber inclusive se os testes passaram ou não. O GitLab tem a própria ferramenta que é o GitLab CI, de Continuous Integration. Tem diversos serviços externos que integram com GitHub como CircleCI, Travis CI, Semaphore e outros. É super simples configurar no seu projeto e não vejo nenhum motivo pra não usar.</p>
<p>Se o pull request parece que está ok, e o CI diz que os testes passaram, só agora é permitido fazer merge desse código novo na master. No mínimo, sabemos que as funcionalidades que funcionavam antes, cobertas com testes, continuam funcionando depois, mesmo com a inclusão desse código novo. É um bom indicativo pra toda a equipe que as coisas estão andando pra frente, e não ficando com débito técnico acumulado pra trás. Eu vi um tweet alguns dias atrás, de alguém que tava relatando como um idiota da equipe resolveu atualizar a versão do Java, acho que do 16 pro 18 e fez deploy pra produção. Óbvio que deu pau. Óbvio que o pau apareceu na sexta-feira.</p>
<p>Tem idiota que acha que porque usa uma linguagem compilada, com tipagem estática como Java, não tem problema não ter testes, porque se tudo compila, obviamente é porque funciona. Não tem nada que é mais certificado de júnior, do que pensar assim. Ahhnnnn como assim? Voltando ao exemplo de software livre. Vamos ver o projeto do navegador Firefox. Sabe Firefox? Sim, aquele Firefox. Eu baixei o código aqui na minha máquina. Firefox é feito na maior parte em C++, um pouco de Rust, um pouco de Javascript. É um navegador bem estável e quem usa acho que raramente tem algum problema dele renderizar errado, crashear ou coisas estranhas assim.</p>
<p>Se você é desenvolvedor de front-end, certamente já usou o Developer Tools certo? Pra debugar o que está programando. E esse Developer Tools tem uma suite de testes, pra garantir que toda nova versão, antes de lançar pra você baixar na sua máquina, passa todos os testes e não introduz nenhuma regressão. Ou seja, tudo que funcionava numa versão continua funcionando na mais nova. No repositório de código fonte, só rodar <code>mach test devtools/*</code> e olha só, abre a versão que acabei de compilar direto do código fonte e roda uma suite de testes de integração, simulando cada funcionalidade do Developer Tools. É assim que a Mozilla garante que código novo não introduz regressões óbvias.</p>
<p>Se der uma fuçada no código, olha só, cada diretório tem um sub-diretório de testes. E muitos deles tem testes específicos pra bugs que foram reportados. Assim eles garantem que bugs corrigidos também não vão aparecer do nada de novo. Bugs que foram corrigidos e aparecem de novo porque não tinha um teste pra cobrir, se chama &ldquo;jogar dinheiro fora&rdquo;. Porque tem que corrigir mais de uma vez. Ao longo do tempo, você está perdendo tempo, dinheiro, eficiência, e mercado pra outro projeto que vai fazer melhor que você com menos recursos.</p>
<p>Tem gente que acha que porque é programador front-end, não precisa se preocupar com testes. Acho que todo mundo gosta do projeto React do Facebook, quer dizer &ldquo;meta&rdquo;, certo? Eu baixei aqui o código fonte da biblioteca React. E olha só, se rodar <code>yarn test</code>, o React tem uma suite de testes feita em Jest. Pelo mesmo objetivo. Mais de 7 mil testes unitários garantem que quando você atualiza o React, não vai quebrar tudo.</p>
<p>Sabe aquela biblioteca de estilos, o TailwindCSS? Um amador poderia imaginar que é só uma coleção de CSS, obviamente não precisa de testes, certo? Errado. Eu baixei o código fonte do Tailwind e adivinha, se rodar <code>yarn test</code>, mais testes unitários em Jest. Quase 900 testes unitários, fora checagens com eslint que por acaso deu alguns erros. Eu baixei do branch principal, ainda estão mexendo e na próxima versão esses bugs serão corrigidos. Mas está claro o que funciona e o que não funciona pra quem está contribuindo.</p>
<p>Bah. Esse povo de front tá muito fresco. Ficar fazendo testes é coisa de hipster. Certamente povo de Python, mais calejado, mais raíz, não se importa com essas besteiras. Por isso eu baixei aqui o código fonte do framework Django. E olha só, tem um diretório chamado <code>tests</code> e dentro eu posso rodar esse script chamado <code>runtests.py</code>. E lá vai ele rodar centenas de testes pra garantir também que versões novas do Django não tá quebrando nada que já funcionava antes. Mais de 16 mil testes. Passando bonitinho.</p>
<p>Foda-se povo de Javascript e Python. Vamos mudar pra PHP. PHP sempre foi conhecido por ser Quick and Dirty, rápido e sujo. Código raíz. Programador Cowboy que programa orientado a gambiarra. POG-zão na veia. Eu baixei aqui o código fonte do framework Laravel que é um dos mais usados hoje. Só que não. Eu posso rodar <code>composer exec phpunit</code> e olha só, quase 8 mil testes, de novo, pra garantir que a versão mais nova não introduz nenhuma regressão. Por acaso falhou, povo ainda tá mexendo, próxima versão estável certamente já vai ter corrigido esse bug. Mas nós sabemos que tem o bug, porque tem suite de testes.</p>
<p>Aliás, sabe o editor de textos mais usados por programadores hoje? O tal do Visual Studio Code? Provavelmente até você assistindo que não gosta de testes aí usa pra fazer seus códigos porcaria. Eu baixei o código fonte também e tem testes automatizados rodando <code>yarn smoketest</code>, que segundo a documentação deles, é rodado antes de gerar o binário final que você baixa pra instalar. Igual o Firefox, tem testes de integração onde abre o aplicativo e vai testando cada funcionalidade que a gente aceita que simplesmente funciona em toda nova versão. E tudo só funciona, porque tem testes pra garantir isso.</p>
<p>E voltando ao Firefox. Parte dele é feito em Rust. E pra você, seu infeliz, que ainda acha que só porque o código compila, tá tudo bem? Não era o Rust que tem o tal compilador mais inteligente de todos os tempos? Que muita gente acha que é mágica e garante não só binário super performático como se tivesse sido feito em C e sem bugs de gerenciamento de memória e problemas de segurança? Muita gente só falta dizer que o compilador escreve o código pra você, de tão bom que ele é. Certamente, se o código em Rust compila, não precisa de testes, certo?</p>
<p>Bom, eu baixei o código fonte da biblioteca Tokio, que é o framework pra desenvolvimento assíncrono em aplicativos feitos em Rust. Todo projeto Rust acompanha um arquivo <code>Cargo.toml</code>, assim como todo projeto Javascript acompanha um <code>package.json</code>. E assim como existe npm ou yarn, em Rust temos o comando <code>cargo</code>. <code>cargo install</code> é equivalente a um <code>npm install</code>. E adivinha, o próprio cargo, ferramenta padrão que já vem com o Rust, tem essa opção <code>test</code>. E o que isso faz? Vamos ver. Só executar <code>cargo test</code>. Olha só ele rodando a suite de testes da biblioteca Tokio.</p>
<p>Ou seja, nem mesmo um projeto em Rust, que é armado com o compilador que é considerado a obra prima dos compiladores, evita os autores do Tokio de não fazer testes. Aliás, pode ver, ele sai rodando centenas de testes, não é um ou dois. Ahhh mas só de compilar já devia ser suficiente &hellip; não, sua múmia paralítica, os criadores do Rust armaram o Cargo pra rodar testes. Você acha que você, logo você, entende mais do que os criadores do Rust?</p>
<p>E você que é de Java e também detesta testes, que tem essa noção atrasada de porque o Java compila, tem tipos estáticos, então se compila tá tudo certo. Você que acha que só linguagens dinâmicas não compiladas como Ruby ou Javascript que precisam de testes. Sabe onde nasceu o conceito de TDD? Foi com Kent Beck, que fez o primeiro jUnit, em Java. Desde os anos 90 a gente sabe que só porque alguma coisa compila, não quer dizer que funciona. Só porque compila não significa que bugs não foram introduzidos. E por ficarem cansados de toda hora ter que correr atrás do próprio rabo, de ficar corrigindo coisa que já funcionava, que os agilistas originais formalizaram o conceito de testes.</p>
<p>Aliás, falei de Java e não mostrei Java. Só de exemplo, baixei o código fonte de um dos frameworks web mais usados que é o Spring Boot. Rodando o bom e velho <code>gradlew build</code> olha só. Baixa todas as dependências, junto com a internet inteira duas vezes, e roda todos os testes automatizados na sequência. O build só é considerado ok se compila e os testes rodam sem erro até o fim. E são milhares de testes. Ué, mas não era só compilar que já tava garantido que funciona? Obviamente não.</p>
<p>Muito antes de existir o conceito de TDD a gente já fazia testes automatizados de um jeito ou de outro. Toda empresa de software madura faz testes. É por isso que seus programas e seu sistema operacional não quebram o tempo todo, toda hora. E mesmo com tudo isso, ainda assim bugs acontecem. Significa que se não tivessem todos esses testes, teríamos ordens de grandeza mais bugs em tudo. Novas versões iam demorar ordens de grandeza mais pra sair. Ia precisar de ordens de grandeza mais pessoas testando. Mas não. Hoje em dia quase todo dia algum programa que você tem instalado ganha uma versão nova, mas você raramente é incomodado. Bugs acontecem, mas são raros. E a razão disso é que todo software maduro, proprietário ou de código aberto, tem testes.</p>
<p>Veja meu blogzinho feito em Ruby on Rails. Ele é ridiculamente simples. Eu mesmo que fiz em 2012. Não lembro se foi em Rails versão 3 ou 4. De lá pra cá eu atualizei até o Rails 6 rodando em Ruby 3. Toda vez que sai versão nova da linguagem ou do framework, eu atualizo, pra ganhar as correções de segurança principalmente. Eu venho atualizando faz 10 anos. E toda vez atualizo as bibliotecas também. Mas diferente do tweet da pessoa que falou que o cara atualizou o Java e subiu pra produção. Antes eu rodo meus testes em Rspec. Se não passa, obviamente não subo. Faço pequenos ajustes quando precisa, se a API de alguma biblioteca mudou. Mas meus testes pegam a maior parte dos problemas. Uma vez por ano, gasto 30 minutos, atualizo as coisas e subo.</p>
<p>Ter testes não é burocracia, não é perda de tempo. É um seguro. Não fazer testes é a mesma coisa que dirigir sem seguro. Na maior parte do tempo, não parece ter muito valor mesmo. Sempre dá pra fazer tudo rápido, sujo e na gambiarra. Você se sente o herói de entregar as coisas rápido. Mas é inevitável, sua produtividade, e da sua equipe, vão gradativamente caindo. Porque mais e mais se perde tempo corrigindo bugs do que fazendo coisa nova. Em breve, a maior parte do seu tempo é só corrigindo bugs. E o que o amador fala? Ahhh, vamos mudar pro framework mais novo. Vamos mudar pra linguagem mais da hora. Quantos de vocês conseguiram manter e atualizar o mesmo sistema por uma década?</p>
<p>Não existe nenhuma linguagem inventada na história que só pelo fato de compilar garante que não precisa ter testes. Todo mundo que entendia isso já fazia testes de alguma forma. A gente fazia alguns scripts separados do código pra rodar partes que eram mais sensíveis se quebrasse, ou que sabíamos que sempre alguém fazia merda e quebrava. Era uma das coisas que separavam os amadores dos espertos. O que aconteceu foi que as comunidade ágeis deram nomes aos bois e criaram convenções e semânticas pra todo mundo falar a mesma língua. Mas não existiu uma data especial que divide antes, com zero testes, e depois, com testes. Foi gradual, onde décadas atirando no próprio pé naturalmente levaram os programadores mais experientes a chegar na mesma conclusão.</p>
<p>Enfim. O problema é que a maioria de vocês assistindo detesta fazer testes. A desculpa é perda de tempo. Mas a verdade é porque vocês não conseguem fazer. Vocês acham que ninguém percebe. Todo mundo que se sente incapaz de fazer alguma coisa, tenta denegrir esse alguma coisa. E é óbvio, não sabe fazer porque nunca faz. Assim como tudo em programação, fazer testes depende de treino e prática. Não existe nenhum livro ou curso que dá pra ler e automaticamente sair fazendo testes perfeitos.</p>
<p>Você que é front, assistiu um curso e já saiu criando interfaces do nível de complexidade de um Canvas instantaneamente? Ou precisou de semanas e semanas apanhando de CSS obscuro? Ou você que é back, só leu um tutorial e já saiu criando APIs perfeitas em GraphQL integrado com backend de Firebase? Em 5 minutos já saiu codando como se não houvesse amanhã? Duvido.</p>
<p>Não adianta ficar só procurando coisa pra ler. Precisa praticar. Assim como tudo que já fez, todos os seus primeiros testes vão ser uma bosta. Mas é assim que começa. Eu citei vários projetos de código aberto. Dá uma olhada nos testes deles pra se inspirar. Tem centenas de outros projetos mais parecidos com o que estiver trabalhando agora. Baixa e lê os testes deles. Copia. Altera. Testa. Joga fora. Começa de novo. Repete. É assim mesmo.</p>
<p>Outra desculpa é falar que o projeto já tá faz meses ou até anos sem nenhum teste. É o cúmulo da preguiça ouvir isso. Ótimo. Faça você o primeiro teste. Pelo menos essa uma funcionalidade que acabou de entregar, está coberto e vai ser mais difícil de aparecer bug aleatório pela falta de atenção de outro programador depois. E se alguém pisar em cima do seu código, só de rodar esse um teste, dá pra saber que quebrou, quem foi, em qual commit, e corrigir mais fácil. De 1 teste em 1 teste, a cobertura naturalmente aumenta.</p>
<p>Alguém reportou um bug? Abriu um ticket? Faça o teste que simula o bug reportado. Agora corrige. Pronto, esse é 1 bug que dificilmente vai aparecer de novo. E olha só, do nada, você começou a andar pra frente em vez de ficar só olhando pra trás. E total de cobertura? Precisa ser 100%? Isso é outra pergunta idiota que sempre aparece numa discussão de quem é desleixado. Foda-se. Você não fez nem 1% ainda, pra que quer discutir 100%? Não interessa. Faz 50%, faz 500%. Só, faz, a, porra, dos, testes.</p>
<p>O que acontece é o seguinte. Sua equipe tem 3 pessoas. Cada um consegue pegar 2 ou 3 tarefas do backlog por semana. 6 a 9 tarefas entregas toda semana. Se o sistema começa a ser usado por usuários de verdade, rapidamente começam a aparecer bugs e problemas. Surge 1 ticket, 2 tickets. De repente a equipe só consegue entregar 3 a 6 tarefas por semana, porque precisa resolver bugs urgentes. Mas continua entregando coisas. Só que essas coisas novas, causam mais bugs. Na próxima semana a produtividade caiu pra 2 a 4 tarefas. E o número de bugs aumenta em vez de diminuir. Em pouco tempo, a equipe male male entrega 1 ou 2 tarefas novas, o resto do tempo é só resolvendo bugs.</p>
<p>E qual a decisão do gerente do projeto? &ldquo;Ah, é normal, precisa contratar mais programadores.&rdquo; Ele convence a diretoria. Dobra a equipe. E voilá, a equipe volta e entregar 6 a 9 tarefas novas por semana. E todo mundo continua sem se importar com testes ou qualidade em geral, é crunch, só entregar e entregar. O volume de código só aumenta, ninguém joga nada fora, vai só acumulando débito técnico. Mais código novo significa mais bugs. No final acontece a mesma coisa, nas semanas seguintes a produtividade cai pra 3 a 6 tarefas, depois pra 2 a 4 tarefas, e de novo, a nova equipe, com o dobro de integrantes, tá male male entregando 1 ou 2 coisas novas por semana, o resto é só apagando incêndio.</p>
<p>Digamos que todo mundo é ruim em testes. Se lá no começo tivesse decidido entregar tudo com testes, em vez de 6 a 9 tarefas, a equipe estaria entregando só de 4 a 6 coisas, talvez menos. Parece bem ruim. A diferença é que vai ser 4 a 6 TODA semana. Surgiu um bug novo? O programador que pega pra corrigir adiciona testes, e segue todo o processo que descrevi antes. Esse bug em particular não aparece de novo. Entregou coisa nova? A suite de testes garante que o que tinha antes não quebrou por conta disso. E assim, toda semana, de forma sustentável, a equipe entrega 4 a 6 tarefas. Não é o máximo de 9, mas não cai pra 1 ou 2.</p>
<p>Daí a empresa decide contratar mais gente e dobra a equipe. Mas a equipe é diligente e treina os novos integrantes sobre a importância de qualidade. A produtividade quase dobra, de 4 a 6 pra 8 a 10 tarefas. A produtividade só dobra se todo mundo segue o protocolo, ninguém pisa no calo de ninguém, e tudo que já foi feito e testado continua funcionando no futuro. Todo upgrade de bibliotecas e correções de segurança tem garantia que o sistema continua funcionando, porque a suite de testes tá passando. Daí nenhum deploy de upgrade feito na sexta feira causa desastre que vai precisar varar fim de semana corrigindo. Olha só que mágico.</p>
<p>Muita gente vai inventar um monte de desculpas pra não fazer testes, e eu garanto que pra cada desculpa nós já temos soluções. Nenhum programador precisa rodar a suite de testes o tempo todo se essa suite demora muito pra executar. Basta rodar alguns poucos ao redor do trabalho que está fazendo naquele momento. Daí sobe um pull request que vai ser pego por um GitLab CI e esse servidor de CI é quem vai rodar a suite inteira de testes. Não só isso, se a suite passar, esse CI pode fazer CD, que é continuous deployment, e automaticamente subir em ambiente de staging e notificar a equipe de QA.</p>
<p>Obviamente eu não posso mostrar projetos confidenciais dos meus clientes, mas posso mostrar esse projeto interno que nós usamos. Olha um pull request. Se olharmos o que mudou podemos ver que além do código, temos ajustes em specs também, que são testes. Quando o desenvolvedor subiu o código, o CI pegou e iniciou o job pra rodar os testes. Nesse caso levou pouco mais de 5 minutos. Passou com sucesso e, lógico, só porque todos os testes passaram não significa que não tem nenhum bug, só que não tem nenhum bug muito óbvio. Mais do que isso, no nosso caso tem configurado também checagens de segurança. No ecossistema Ruby temos coisas como Brakeman, que avalia o código por buracos de segurança conhecidos como injections.</p>
<p>Essa aplicação sobe no Heroku, que tem uma funcionalidade chamada review apps. Podemos ter um deployment separado de testes pra cada pull request que ainda está aberta. Justamente pra alguém conseguir testar de verdade antes de aprovar. Um review app é um ambiente de staging, só que isolado pra cada pull request. Dá pra ter dezenas de review apps em paralelo. Assim não precisa ficar acumulando e integrando tudo no mesmo ambiente de staging pra testar, o que seria uma zona. Testa tudo isolado. Vai aprovando no ritmo do responsável pelos testes. E no final, quando estiver tudo testado, aprovado e mergeado no branch principal, daí faz um deployment pra produção aqui do lado.</p>
<p>Neste exemplo, no dia que fui tirar foto de tela, não tinha nenhum pull request aberto. Mas eles apareceriam listados aqui. Cada um com uma URL separada de testes. Esse é outro motivo de porque eu sempre recomendo Heroku. Ele não é o mais barato, mas esse tipo de recurso facilita o fluxo de trabalho em ordens de grandeza. Só as horas de desenvolvimento que se economiza de cada desenvolvedor já se paga.</p>
<p>Enfim, uma vez cada pull request de cada desenvolvedor sendo aprovado, tudo vai sendo integrado no branch principal e podemos fazer um deploy de tudo integrado pro ambiente de staging. Agora o pessoal de QA pode fazer o trabalho deles direito, que é testar as coisas novas, e não ficar retestando tudo de novo que já funcionava antes. Todo report de bugs volta pro programador, que faz a correção e ajusta os testes pra cobrir os casos que não tinha pensado.</p>
<p>Com o pull request foi ajustado, os testes passam, QA já viu em staging, o sênior da equipe pode dar a última olhada e fazer o merge na branch principal. E aí alguém de devops ou alguém responsável pela produção pode pegar o que está na branch principal e fechar uma versão pra produção, com a segurança de saber que se está na branch principal, então está funcionando corretamente.</p>
<p>E se estiver usando Heroku, ainda tem uma facilidade extra. Digamos que todo mundo fez tudo direitinho, mas mesmo assim surgiu um bug que só aparecem em produção. Basta ir nesta aba de atividades e clicar em roll back pra voltar pra versão anterior. Heroku é caro, mas é nessas horas que ele se paga. Medo de deploy na sexta-feira só existe em equipes disfuncionais que não fazem esse básico que acabei de falar.</p>
<p>Falando em disfuncional, o maior desafio em toda equipe de projetos, é coordenar a comunicação. Ao ter um repositório de códigos como Git, um processo de testes de integração contínua, pareamento entre sêniors e juniors pra compartilhar conhecimento, e um protocolo como de pull requests, estabelecemos um conjunto simples e objetivo de entendimento nessa equipe. Não seguir esse protocolo é um desrespeito à equipe. Você não programa pra você mesmo, você contribui com sua equipe. O importante não é andar rápido, o importante é não estragar o que já funcionava.</p>
<p>Da mesma forma, ninguém deve sair adicionando coisas no projeto que ninguém está sabendo. Por isso que no mundo ágil se inventou os tais rituais como de planejamento e revisão. Rituais não devem ser obrigações, mas pontos de coordenação. Se os rituais estão sendo meramente pras pessoas aparecerem mas não participar, então não servem pra nada e devem ser eliminados e repensados. Esse é um ponto não-técnico que não quero tentar detalhar demais, mas preciso falar de um ponto específico: estimativas.</p>
<p>Se tem uma coisa que programador odeia fazer mais do que testes é estimar tarefas. Já disse isso em outros videos, mas existem duas palavras que todo mundo não-técnico confunde: estimar e prever. O programador estima, mas os gerentes ou diretores acham que receberam previsões. Estimativas são ordens de grandeza, não está certo nem errado. É uma ordem de grandeza. Previsões sim, é pra serem precisas. Quando um programador diz que pode levar uns 2 ou 4 dias, é isso que pode levar, 2 a 4 dias. Talvez leve 5. E aí o gerente que achava que tinha uma previsão na mão, fica puto, porque tava esperando 2 dias, recebeu em 5 e quer sair chutando tudo. E é isso que eu chamo de um idiota.</p>
<p>Eu acho que todo gerente de projetos deveria gastar um tempo movimentando o próprio dinheiro no mercado financeiro. Comprar e vender ações, ou opções, ou criptomoedas, não importa. Porque todo mundo gostaria de saber pra onde vai o mercado, se vai subir ou se vai cair. É impossível acertar 100% do tempo. Se alguém soubesse prever isso, quebraria o mercado financeiro. O máximo que podemos fazer é dar chutes educados. Estimativas. A gente tenta acertar, comprar na baixa, vender na alta. Ou no mínimo planejar pra alta e se proteger da baixa. Criamos contingências, e sabemos que é impossível ganhar sempre. O máximo que podemos fazer é tentar minimizar perdas. E as perdas nunca vão ser zero.</p>
<p>Gerenciamento de projetos é a mesma coisa. Um gerente inteligente não se interessa em tentar prever cada tarefa individualmente. Ele observa o movimento geral da equipe e do produto. Tá em tendência de alta de produtividade? Baixa de produtividade? Tem como influenciar a baixa? Qual é o obstáculo? Algum diretor deu carteirada e quebrou o planejamento? Alguém ficou doente? Um bom gerente está numa posição que um analista financeiro não tem: de influenciar as tendências.</p>
<p>Lógico, quanto mais um programador ganha experiência e tem mais segurança no que realmente sabe e o que não sabe, mais e mais suas estimativa se aproximam de previsões. Ele já tem uma boa noção de quanto tempo leva a maioria das coisas. Quanto mais inexperiente, mais longe vai ser essa estimativa. Faz parte do crescimento profissional de cada um começar a quantificar suas próprias capacidades. Ninguém tem obrigação de &ldquo;acertar&rdquo; estimativas, mas claro, quanto mais precisas forem, mais todo mundo consegue confiar mais e mais em você. É uma das formas de subir na carreira. Entregar o que promete.</p>
<p>Tarefas, stories ou seja lá como quer chamar, são meras formalidades. Quanto mais curtas, objetivas, direto ao ponto forem, melhor. O objetivo não é um concurso de literatura onde todo mundo tem que fazer uma dissertação. A quantidade de palavras deve ser o suficiente pra que toda a equipe envolvida saiba no que está sendo trabalhado. Só isso. Tem quinhentos blog posts, livros e cursos tentando ensinar &ldquo;a melhor forma&rdquo; de escrever requerimentos. E a maioria é bullshit. Quer dizer, até faz sentido, pode ser usado como inspiração, mas não existe nenhuma receita que dá pra só seguir. Assim como testes e estimativas, escrever requerimentos também depende de prática. Estude o que se sugere, mas não siga ao pé da letra.</p>
<p>User Stories tem aquele formato idiota de &ldquo;eu, como usuário, quero conseguir adicionar um produto no carrinho e ter o total do pedido, para poder pagar minha compra&rdquo; ou algo assim. Pode ser, é bonitinho, tem o objetivo de forçar as pessoas a pensar em pra quem é a funcionalidade sendo feita, qual o objetivo e facilitar pensar na melhor forma de fazer. Tem coisa que precisa de mais detalhe que isso. Um protótipo de tela no Canvas. Um rascunho de conta de imposto. Tem coisa que nem precisa de tanto detalhe assim. Bugs costumam ser mais diretos &ldquo;quando o usuário abre no firefox de mac, o box de items fica em cima do box de cartão e não dá pra digitar o código de segurança do fucking pedido e a fucking compra não finaliza&rdquo;. Tá super claro.</p>
<p>Eu tive um cliente que o imbecil do CTO mandava todo programador descrever em detalhes como ia programar, antes de escrever uma linha de códigos. Tinha que listar que classes novas ia criar, com que métodos, com quais nomes. Era a coisa mais idiota que eu já vi, só perde pra época que povo achava que precisava fazer diagramas de classe UML precisos meses antes de escrever uma linha de código. É idiótico. É da época que falei que se achava que programador era só pedreiro e havia uma forma mágica de descrever tudo, antes de escrever o código. É uma noção boçal.</p>
<p>O resumo é simples: a descrição deve ser a mais concisa, com o menor número de palavras possível. A equipe deve conseguir se reunir e em pouco tempo entender o que precisa ser feito, quem vai fazer, quem precisa de ajuda. O gerente, ou Product Owner, e o equivalente tech lead ou programador mais sênior, deveriam estar alinhados. Daí quando seja lá qual programador entregar o pull request praquela funcionalidade, o tech lead consegue avaliar rápido e mandar pro QA. O PO e o QA precisam estar alinhados, pra ver se o que foi entregue resolve o que se queria resolver.</p>
<p>Burocracia e formalidades em excesso aparecem em empresas onde esses personagens tem preguiça de conversar ou pior: não sabem o que estão fazendo. Porque se soubessem, poderiam ir direto ao assunto. Toda burocracia em excesso é defendida por aqueles que não sabem o que estão fazendo, porque aí podem usar a desculpa de &ldquo;mas, mas, eu segui os procedimentos, a culpa não é minha&rdquo;. Toda burocracia é uma muleta pra cabideiro que não deveria estar ocupando as posições que estão ocupando. É assim simples.</p>
<p>Voltando pra estimativas. Não existe nenhuma fórmula nem procedimento que, dado uma descrição em texto de um caso de uso, ou user story ou seja lá o que for, chega num número de horas ou dias exatos pra resolver essa tarefa. Cocomo e outras bullshitagens são lixo. Não tem como. Só a experiência dos programadores envolvidos é capaz de dar uma ordem de grandeza, cuja qualidade vai ser proporcional à experiência da equipe. Se a equipe for super experiente, mesmo assim vai ser uma ordem de grandeza.</p>
<p>Não tem nada mais retardado do que gente que pega esses números de estimativas, número de horas realizadas, vai pondo num gráfico e fica tentando derivar coisas desses números, fazer integral, aplicar fórmulas. Só porque se tem números, não signfica que existe cálculos que dê pra fazer. Eu posso sair jogando dados, colocar todos os resultados num gráficos e gerar um monte de conclusões. É assim que nasce pseudo-ciência, numerologia, astrologia e todas essas logias idiotas. Estimativa é um chute. Estimativas nunca estão erradas, porque não são previsões. Fazer contas com esses números não faz nenhum sentido.</p>
<p>Dá pra saber que vai ser perto de 6 meses mas menos de 1 ano. Agora, se vai ser 5 meses, 2 semanas, 4 dias e 5 horas, exatamente. Isso é impossível. Gastar horas tentando estimar tudo é um exercício de futilidade. Não perca tempo tentando prever com exatidão. Aprenda a lidar com ordens de grandeza. Simplesmente escreva o que se sabe que realmente precisa fazer. E nem tente detalhar 6 meses de trabalho de uma só vez. É inútil. Descreva o curto prazo em detalhes, 1 mês, no máximo 2 meses de trabalho. Tenha a direçao do longo prazo em mente, mas ajuste enquanto vai andando. Deixe a equipe se dividir em quem faz o que. E siga o que falei até agora sobre pull requests e merge.</p>
<p>Mesmo sem ter estimativa nenhuma, você como gerente ou como qualquer membro da equipe vai ver que numa semana a equipe entregou 10 tarefas, stories ou seja lá como quer chamar. Na semana seguinte, entregou 9. Na outra semana conseguiu entregar 11. Na semana seguinte entregou 7. O que o gerente ou facilitador dessa equipe começa a notar? Uma tendência. Parece que, seja lá como se descreve tarefas nessa equipe, eles conseguem entregar uma média de 8 a 9 unidades dessas &ldquo;coisas&rdquo;. E se for esperto, vai notar que quando entrega menos coincide quando sobe versão nova pra produção, daí o suporte recebe reports de bugs, que entram no backlog da equipe e isso diminui a quantidade de &ldquo;coisas&rdquo; entregues.</p>
<p>O gerente fala com o tech lead, que revê o processo, e vê que ele tava deixando passar pull requests com testes não tão bons. Ele pareia com o programador júnior que tava fazendo errado. Ensina na prática onde tava errando. E agora ele passa a produzir melhor. E é assim que uma equipe evolui, um passo de cada vez. Não é via metodologia, nem aumentando formalidades e burocracias, é via bom senso. Resolvendo problemas na raíz em vez de ficar inventando band-aids, ou pior, mais burocracias inúteis. E o principal: reorganizado a lista de coisas a fazer pra garantir que as coisas mais importantes estão sendo feitas primeiro e tudo que é opcional ou de pouco valor está no fim da lista. Assim, caso não dê tempo de fazer tudo, pelo menos você sabe que o mais importante foi feito.</p>
<p>Cuidado, não estou dizendo que não se deve perder tempo descrevendo tarefas ou que não se deve fazer estimativas. Estou falando que a formalidade não é tão importante, tem que começar a escrever e aceitar que vai estar mau escrito. Aceitar o feedback de que o programador fez errado porque do jeito que tava escrito ficou ambíguo. E aí vai ajustando os detalhes pra próxima vez, até o nível que faz sentido. &ldquo;Ah, se tivesse descrito essa conta com um exemplo, ele teria entendido&rdquo;, ou algo assim. Aceitar que uma estimativa nunca vai estar certa ou errada. É só uma referência. Não tente fazer projeções baseado em estimativas, porque isso só vai multiplicar um erro com outro erro.</p>
<p>Em vez disso veja em ordens de grandeza como falei. Seja lá como organiza as tarefas da equipe, veja, no geral, que tipos de funcionalidades ou correções de bugs a equipe entrega num certo período de tempo, como toda semana. Daí nem precisa perguntar pra equipe se o que tem no backlog cabe ou não na semana. Você já sabe essa resposta pela velocidade que já conhece. Quando sabe que não vai caber, seja honesto e faça seu trabalho: corte ou simplifique. Não tem mágica. Se não cabe, não cabe. Se tentar fazer caber, obviamente a qualidade vai cair. É onde vai vir o &ldquo;se eu pular fazer testes, talvez caiba&rdquo;. E quando se cede uma vez, isso vai acumular. Na semana seguinte já começa a vir a conta. E uma decisão feita no desespero numa semana, vai prejudicar todo o resto do andamento daqui pra frente.</p>
<p>Não existe almoço de graça. Toda vez que vai se deixando passar uma pequena coisa errada, isso vai acumulando. Em breve, vai estar tudo errado. Ser sustentável é exercitar disciplina. E não tem coisa mais maçante, mais entediante, do que ser disciplinado. Quando tudo é uma bagunça, é difícil elencar os problemas. Mas numa equipe disciplinada, fica fácil ver quem tá puxando a equipe pra trás. Sem ter a muleta da burocracia, fica fácil ver quem é a pessoa inconstante, aquele que promete demais, entrega de menos, e quando entrega outra pessoa precisa consertar. A equipe inteira sabe quem é essa pessoa. Eles devem ensinar, ajudar, mas quando a pessoa é resistente a trabalhar em equipe, ela deve ser removida. É assim simples.</p>
<p>A decisão errada é manter essa pessoa e contratar outra pra aumentar produtividade. Muitas equipes que eu já vi teriam a produtividade aumentada só de cortar os maus elementos, porque agora eles não precisam ficar consertando o que o mau elemento tá entregando de mau jeito. Automaticamente a produtividade aumenta, o stress diminui, todo mundo trabalha melhor. Uma coisa que aconteceu durante esse período que já passou de vacas gordas, com montes de empresas contratando gente ruim no atacado, é que em vez de aumentar a produtividade, eles prejudicaram a qualidade do produto e das equipes. Imagina um monte de gente ruim, fazendo o contrário de tudo que falei até agora. Só acumulou um monte de código porcaria que funciona em produção na força bruta, com alguns poucos hiper estressados, varando noite, consertando a porcaria que recebe.</p>
<p>Se a equipe não se importa com o que está entregando, nada do que eu falei até agora importa. E todo novo integrante, ao ver que ninguém tá realmente muito interessado, vai aprender do jeito errado: que o melhor é ligar o foda-se e fazer igual todo mundo. E é assim que um projeto entra em colapso, porque ninguém está ligando. Em empresas com dinheiro dos outros demais, é o que mais acontece. Mas se sua empresa realmente depende do código sendo feito, sinto dizer, rapidamente todo mundo vai perder o controle. E daí pra frente é só cavar o buraco mais fundo.</p>
<p>De novo. Todo projeto é uma incerteza, especialmente nos primeiros dias. Especialmente se for uma equipe nova, recém constituída. Precisam aprender a trabalhar juntos ao mesmo tempo que precisam entender o que diabos vão construir. É uma montanha de incertezas. Por isso o ideal é garantir que o básico do básico está garantido: que pelo menos o que está sendo entregue vai continuar funcionando ao longo do tempo. Exercitem o processo de testes, pull requests, integração contínua, deployment em staging. Daí comecem a ver até que nível de detalhes realmente as tarefas precisam ser definidas. E vai ajustando.</p>
<p>Não tente estabelecer regras escritas em pedra no dia um. É inútil. Comece no equivalente a fazer rascunhos. Avalie se o rascunho está num nível de detalhes suficiente. Se não estiver, vai ajustando. O PO, o UX, precisam ir refinando isso. Daí o QA e o suporte precisam também ir refinando o processo de testes. Esse processo volta pra equipe de desenvolvimento, que reflete se está cometendo deslizes técnicos que poderiam evitar bugs óbvios. Todo mundo ainda estava crú em fazer testes, e aos poucos vai aprendendo a realmente testar os casos que interessam e deixar de lado os casos que não precisa. Naturalmente vão se acostumando a saber até onde precisa ou não cobrir determinados tipos de funcionalidades.</p>
<p>Sério. Exercite sua equipe em usar Git direito, em usar os recursos de testes que certamente já tem no seu framework. Como falei, Rails tem, Django tem, Laravel tem, Spring Boot tem, Express tem, React tem. Todo mundo tem suporte a testes que vocês só escolheram não usar. Só que vocês não são seres ungidos que fazem código sem erros. Pelo contrário, todo programador vai mais fazer erros do que acertar. Especialmente se for júnior. É normal. Só que hoje todo mundo deixa esses erros acumularem no repositório, porque os deploys pra produção acontecem só 1 vez por mês, ou 1 vez por bimestre. Daí toda vez que faz deploy fica todo mundo apreensivo, porque já sabe que vai dar merda. Todo mundo sabe que empurrou os problemas com a barriga. Daí o dia do deploy é o dia da pizza na madrugada. Todo mundo correndo atrás do próprio rabo pra consertar os erros que vão aparecendo. Um caos.</p>
<p>Não seja esse clichê. Faz direito um pouco todo dia pro dia de deploy em produção ser só mais um dia normal, tedioso, sem nenhuma adrenalina, porque todo mundo tem segurança que tá tudo testado e funcionando. Fazer as coisas direito é muito chato, eu sei. Deixa pra fazer código porco gambiarrado nos seus projetinhos pessoais. Mas em projeto dos outros, aprenda a ser profissional. Imagina se seu médico também fizesse programação orientada a gambiarras sem testes como você faz. Imagine se o médico do seu filho fizesse como você faz. Acho que não ia gostar né? Cresce, e age como profissional. Se ficaram com dúvidas, mandem nos comentários abaixo. Se curtiram o video deixem um joinha, assinem o canal e compartilhem o video com seus amigos. A gente se vê, até mais!</p>
]]></content:encoded><category>testes</category><category>engenharia-de-software</category><category>agile</category><category>akitando</category></item><item><title>[Akitando] #119 - Rant: Aprendizado na Beira do Caos | Rated R</title><link>https://akitaonrails.github.io/2022/05/30/akitando-119-rant-aprendizado-na-beira-do-caos-rated-r/</link><guid isPermaLink="true">https://akitaonrails.github.io/2022/05/30/akitando-119-rant-aprendizado-na-beira-do-caos-rated-r/</guid><pubDate>Mon, 30 May 2022 10:33:00 -0300</pubDate><description>&lt;div class="embed-container"&gt;
&lt;iframe
src="https://www.youtube.com/embed/am-FQ86mKV0"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2&gt;DESCRIÇÃO&lt;span class="hx:absolute hx:-mt-20" id="descrição"&gt;&lt;/span&gt;
&lt;a href="#descri%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Finalmente chegamos na marca de 300 mil assinantes no canal! E hoje vai ser mais um video de Rant, Rated R, onde quero só falar livremente sobre minhas pesquisas e hipóteses sobre uma teoria geral sobre os princípios de aprendizado, gestão, empreendedorismo e qualidade. Vai ser uma longa conversa metafísica que costuma ser assunto de minhas conversas de bar. Vamos tentar falar sobre isso sem o efeito de álcool. Vai ser meio bizarro, mas aguentem firme.&lt;/p&gt;</description><content:encoded><![CDATA[

<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/am-FQ86mKV0"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<h2>DESCRIÇÃO<span class="hx:absolute hx:-mt-20" id="descrição"></span>
    <a href="#descri%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Finalmente chegamos na marca de 300 mil assinantes no canal! E hoje vai ser mais um video de Rant, Rated R, onde quero só falar livremente sobre minhas pesquisas e hipóteses sobre uma teoria geral sobre os princípios de aprendizado, gestão, empreendedorismo e qualidade. Vai ser uma longa conversa metafísica que costuma ser assunto de minhas conversas de bar. Vamos tentar falar sobre isso sem o efeito de álcool. Vai ser meio bizarro, mas aguentem firme.</p>
<h2>Conteúdo<span class="hx:absolute hx:-mt-20" id="conteúdo"></span>
    <a href="#conte%c3%bado" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><ul>
<li>00:00:00 Intro</li>
<li>00:01:55 Determinismo</li>
<li>00:06:54 Atualizando Newton</li>
<li>00:10:41 Caos</li>
<li>00:13:10 Lavagem Cerebral</li>
<li>00:15:02 História da Qualidade</li>
<li>00:21:18 Deming a Six Sigma</li>
<li>00:25:14 Origens de Agile</li>
<li>00:31:34 Resolvendo Problemas Desconhecidos</li>
<li>00:33:28 Priorização</li>
<li>00:34:44 Mito da Ordem e Progresso</li>
<li>00:36:01 Beira do Caos</li>
<li>00:39:00 Ordem e Caos</li>
<li>00:45:02 Jogando Tudo Fora</li>
<li>00:47:21 Medo do Erro</li>
<li>00:52:08 Gestão de Risco</li>
<li>00:55:44 Saindo da sua Área</li>
<li>00:58:31 Conclusão</li>
<li>01:01:00 Bloopers</li>
</ul>
<h2>Links<span class="hx:absolute hx:-mt-20" id="links"></span>
    <a href="#links" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><ul>
<li>DR. DEMING’S 14 POINTS FOR MANAGEMENT (<a href="https://deming.org/explore/fourteen-points/"target="_blank" rel="noopener">https://deming.org/explore/fourteen-points/</a>)</li>
<li>Edge of Chaos (<a href="https://www.systemsinnovation.io/post/edge-of-chaos-1"target="_blank" rel="noopener">https://www.systemsinnovation.io/post/edge-of-chaos-1</a>)</li>
<li>Education at the edge of chaos (<a href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC3207078/"target="_blank" rel="noopener">https://www.ncbi.nlm.nih.gov/pmc/articles/PMC3207078/</a>)</li>
<li>Your Brain Operates at the Edge of Chaos. Why That&rsquo;s Actually a Good Thing (<a href="https://www.cnet.com/science/biology/features/your-brain-operates-at-the-edge-of-chaos-why-thats-actually-a-good-thing/"target="_blank" rel="noopener">https://www.cnet.com/science/biology/features/your-brain-operates-at-the-edge-of-chaos-why-thats-actually-a-good-thing/</a>)</li>
<li>Edge of chaos as a guiding principle for modern neural network training (<a href="https://arxiv.org/abs/2107.09437"target="_blank" rel="noopener">https://arxiv.org/abs/2107.09437</a>)</li>
<li>Optimal Machine Intelligence at the Edge of Chaos (<a href="https://arxiv.org/abs/1909.05176"target="_blank" rel="noopener">https://arxiv.org/abs/1909.05176</a>)</li>
<li>cowsay and cowthink (<a href="https://web.archive.org/web/20120225123719/http://www.nog.net/~tony/warez/cowsay.shtml"target="_blank" rel="noopener">https://web.archive.org/web/20120225123719/http://www.nog.net/~tony/warez/cowsay.shtml</a>)</li>
</ul>
<h2>SCRIPT<span class="hx:absolute hx:-mt-20" id="script"></span>
    <a href="#script" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Olá pessoal, Fabio Akita</p>
<p>Minha voz anda ruim esses dias, mas decidi gravar assim mesmo, espero que não incomode. Este video é pra comemorar os 300 mil assinantes do canal. Obrigado a todos que acompanham e quem é recém chegado, os videos deste canal foram feitos pra serem assistidos desde o começo. Não tem videos opcionais aqui. Se você tem uma pergunta, eu provavelmente já respondi antes. Enfim, já faz muitos episódios que eu só tenho abordado temas bem técnicos, e sendo honesto até pra mim é cansativo editar tanto detalhe de conceito técnico então resolvi dar uma pausa hoje pra falar de alguns assuntos que estudei por muitos anos mas ainda não discuti no canal. O assunto vai ser sobre como eu penso sobre aprendizado. Uma teoria mais geral sobre aprendizado.</p>
<p>Este video é pra todos vocês que já me perguntaram, “Akita, como eu devo estudar?” ou “Akita, como devo gerenciar um projeto?” ou “Akita, como devo administrar uma empresa?” Impressionante, que apesar de eu já ter falado diversas vezes que vocês não deveriam estar fazendo essas perguntas pra mim nem pra nenhum outro influencer, elas continuam aparecendo. Mas hoje eu quero tentar ensinar a fundação de como vocês mesmos podem tentar responder essas perguntas.</p>
<p>Já deixo avisado logo de cara que quase tudo que vou contar vai soar como auto-ajuda, coaching e tudo mais. A diferença é que não estou vendendo nada. O problema é que assuntos como aprendizado, gestão, empreendedorismo, são abstratos por natureza. Não existem definições exatas e objetivas pra nenhuma delas. Por isso cada um precisa ter uma imagem na cabeça, um modelo pra encaixar na realidade. O que vou contar agora não é a resposta definitiva nem nada disso. É só a forma como eu penso sobre esses assuntos. Alguns de vocês talvez já tenham imagens diferentes na cabeça, e não tem nenhum problema. Vocês queriam saber como eu penso, bem, eis como eu penso.</p>
<p>(&hellip;)</p>
<p>Lógico, sei que não importa quantas vezes eu disser que é perda de tempo fazer perguntas como “Akita, o que eu devo fazer da minha vida”, é da natureza humana querer uma resposta fácil, resultados fáceis. Consigo simpatizar com a idéia de imaginar “cara, esse sujeito parece ter sucesso, vou perguntar pra ele como que ele fez, daí é só copiar”. Existem milhões de coisas simples que conseguimos achar respostas fáceis. Como faz pra fazer um ovo cozido com gema meio mole? Procura no Google, e descobre que é só deixar exatamente 7 minutos em água fervente.</p>
<p>Se pra achar como cozinhar um ovo é tão fácil, por que tudo não pode ser assim fácil? Aliás, dá pra extrapolar bastante. Se quero viajar, basta colocar o destino no Waze ou Google Maps, e ele consegue me estimar com bastante precisão o tempo que vai levar pra chegar. De novo, parece fácil. E posso ficar o resto do dia só elencando exemplos de coisas que você não sabe, mas com uma rápida pesquisa no Google, eu acho a resposta e vai ser até bem exata.</p>
<p>Se eu consigo achar respostas tão fáceis pra coisas como achar um trajeto no Waze, por que não consigo achar qual o melhor caminho pra estudar? Ou qual a melhor forma de gerir um projeto que vai ser barato e acabar rápido? Ou qual a forma mais eficiente de administrar uma empresa? Ou simplesmente, como ter sucesso na vida? Por que diabos o Google não consegue me dar essa resposta? Será que é só questão de tempo até a tal da inteligência artificial e machine learning melhorarem um pouco mais?</p>
<p>No fim das contas, por trás de todas essas perguntas que me fazem, elas podem ser reduzidas só a essa mais simples: “Akita, como eu faço pra ter sucesso na vida?” Cara, todo coaching vai te vender que sabe como. E se você for bem trouxa ou muito desesperado, vai cair que nem um pato. Mas como eu não tenho paciência pra isso já digo logo de cara: nem eu, nem ninguém sabe essa resposta e nem nunca vai saber. Nem se juntar todas as cem pessoas consideradas de maior sucesso do século XXI na mesma sala e mandar eles escreverem uma lista de procedimentos. Ninguém vai conseguir seguir e ter o resultado esperado. E intuitivamente a maioria de vocês assistindo já sabem disso, mas por que exatamente?</p>
<p>Foi fazendo essa pergunta que eu me interessei em estudar mais um pouco sobre conceitos de outras áreas. E se você ler demais vai começar a entrar em filosofia e em diversos outros campos. Apesar de achar filosofia clássica chata pra caralho, obviamente tem coisas interessantes a considerar. É fazer as perguntas difíceis, aquelas que todo mundo vai responder “ah, isso é óbvio”, mas se pedir pra detalhar, ninguém consegue colocar em palavras. Deixa eu pegar um exemplo super simples. Lembra as aulas de física básica que você teve no colégio? Lembra daquela formulinha besta de S = v x t? Ou espaço é igual a velocidade vezes o tempo?</p>
<p>Com essa fórmula, se eu estiver num carro a uma velocidade média de 100 quilômetros por hora, e dirigir por exatamente 2 horas, significa que no final vou ter percorrido 200 quilômetros. Você já parou para pensar a implicação disso? Não só dessa mas de todas as fórmulas que aprendeu no colegial? Com tudo que Newton descobriu e documentou no que chamamos de “física clássica” eu não consigo só prever onde meu carro vai estar daqui 2 horas, mas até a órbita de planetas do sistema solar. Dá pra prever onde Marte vai estar em relação à Terra daqui 20 anos, e dá pra saber onde estava 20 anos atrás. Essas fórmulas descrevem o presente, confirmam com os dados vistos no passado e conseguem prever o futuro! Já parou pra pensar nisso?</p>
<p>Um século atrás isso levantou várias questões filosóficas e morais. Aqui eu posso estar sendo simplista porque realmente não sou estudante de filosofia, mas se começar a pensar no que acabei de explicar vai cair no ramo da filosofia conhecida como Determinismo, que na real teve sua origem na Grécia antiga, 7 ou 8 séculos antes de Cristo, época dos primeiros e verdadeiros “influencers”, como Aristóteles. Mas no Ocidente ela é associada com a física clássica de Newton e a busca pelas leis e fórmulas que descrevem a realidade como algo estático e previsível. Vocês entendem a implicação das fórmulas? Se eu tenho na fórmula todas as variáveis que causam um efeito, como velocidade e aceleração, e se eu consigo extrapolar a variável de tempo pro futuro, e se o resultado tem que bater com a realidade, então em essência, estou prevendo o futuro.</p>
<p>Por um lado isso parece extremamente agradável, se a pesquisa continuar e conseguirmos desvendar todas as leis da natureza, quem sabe, não existe uma fórmula mágica, determinista, de como ter sucesso? Por outro lado, se parar pra pensar no lado moral, se essas leis realmente existem, o que isso diz sobre coisas como nosso livre arbítrio? Na realidade a gente não tem agência sobre nós mesmos? Se é possível existir leis que prevêem o futuro, então tudo que estamos fazendo agora, neste minuto, eu gravando este video, ou vocês aí assistindo, não são escolhas que fizemos mas sim passos já pré-destinados que não temos nenhum controle? Será que existe uma fórmula pra isso que a gente só não descobriu ainda?</p>
<p>Na realidade, não. No século XX as chamadas Leis de Newton foram quebradas, caso vocês não saibam. Elas não eram bem “leis”. É por isso que as pessoas tem dificuldade de confiar na ciência. Por um lado mantemos a “Teoria da Evolução de Darwin” ainda como “Teoria” sendo que na verdade já tem bases mais que suficientes pra ser promovida a Lei. E eu sei que alguém já tá indo nos comentários pra discordar, mas esquece, só aceita que dói menos. Mas por outro lado, as “Leis” de Newton não são leis. Deixa eu explicar.</p>
<p>A física clássica de Newton funciona super bem pra fenômenos com dimensões que vão desde o átomo até o tamanho de algumas estrelas e planetas. Parece um escopo bem grande, mas não é o total, nem de longe. Essa mesma física que consegue prever com boa precisão onde meu carro vai estar depois de dirigir por um determinado tempo ou onde um planeta vai estar em relação à outra daqui alguns anos, falha miseravelmente em tamanhos ou densidades muito maiores que estrelas, particularmente quando falamos de coisas como buracos negros. Ela não consegue explicar da onde vem a gravidade. E falha miseravelmente em tamanhos muito menores que o átomo, o mundo sub-atômico da física quântica.</p>
<p>No campo cosmológico, Einstein nos trouxe a Teoria Geral da Relatividade e a Teoria Especial da Relatividade. Na prática, a física clássica de Newton é um caso especial, simplificado, da Relatividade. Ou seja, das teorias de Einstein você consegue derivar física newtoniana pra dimensões “pequenas” onde o espaço-tempo parece estático e linear. Quando falamos em escalas de quilômetros, Newton funciona, por isso ainda aprendemos na escola. Mas quando falamos de escalas de anos-luz, velocidade da luz, aí precisa de Einstein. Mesma coisa quando falamos de efeitos quânticos, não dá pra prever onde uma sub-particula vai estar usando Newton.</p>
<p>Literalmente não dá realmente pra prever onde uma sub-particula vai estar porque no mundo quântico falamos em espaços de probabilidades. Ela pode estar na direita, mas também pode estar na esquerda. As diferentes respostas existem ao mesmo tempo em superposição e só vamos realmente saber exatamente onde depois que colapsarmos o sistema. O mundo quântico não é determinista. A gente sempre acha que toda causa tem um efeito. Mas no mundo quântico temos uma gama de probabilidades. Incerteza e aleatoriedade passam a fazer a diferença. E descobrimos que Deus joga dados. Nada é sagrado, nem as Leis de Newton.</p>
<p>E como eu sempre aviso: cuidado pra não cair em papo de coach quântico. Como o nome diz, física quântica só se aplica no mundo quântico, sub-atômico. Mas o ponto é que até o colegial, você só aprendeu a encarar a natureza como se fosse algo determinista, causa e efeito, segundo as Leis de Newton, que por coincidência corroboram visões antiquadas de destino ou algum tipo de força maior te guiando num caminho pré-definido. Por intuição, na cabeça de muitos, ou existe uma fórmula mágica determinista pra alcançar algum tipo de sucesso, ou na verdade, você está pré-destinado a não ter sucesso e só aceita isso. E a resposta é bem mais complicada do que isso.</p>
<p>Onde eu quero chegar é primeiro fazer vocês entenderam o seguinte: atividades curtas, em dimensões de seres humanos como um ingrediente de cozinha, ou em tempos curtos com poucas variáveis, como a duração de uma viagem pra uma cidade vizinha, existem sim, fórmulas Newtonianas, que conseguem prever como partir de um ovo cru e chegar em um ovo com gema cremosa em 7 minutos. E se o destino da sua viagem fica a 200 quilômetros daqui, se conseguir manter uma velocidade média de 100 quilômetros por hora, vai chegar em aproximadamente 2 horas. Ordens de grandeza muito diferente disso, nem machine learning, nem inteligência artificial, vão conseguir ajudar. Tudo passa a ser uma probabilidade.</p>
<p>Aleatoriedade é um campo inteiro de pesquisas que levam a física do Caos. Pequenas variações iniciais que pareciam insignificantes e podem levar a grandes efeitos difíceis de prever. É uma das razões de porque apesar de todo o poder computacional que nós temos, até hoje é impossível prever a meteorologia com precisão, todos os dias do ano, sem errar. Conseguimos sim, ter uma noção geral, mas nunca vamos acertar como exatamente vai estar o tempo daqui exatamente 1 ano. Não digo no mesmo mês de daqui um ano, mas se vai estar chovendo ou não no dia 1o de junho do ano 2033, volume exato de precipitação entre quais horários. É impossível, e se acertarmos não vai ser porque previmos, vai ser sorte ou coincidência.</p>
<p>Tudo isso que falei foi pra concluir o seguinte: sim, pra coisas com tempo de duração relativamente curto, é possível ignorar muitas dessas variáveis e aleatoriedade, e conseguir seguir um conjunto de passos que te leva de algo simples como um ovo cru pra um ovo cozido decente. É um período de tempo e dimensões onde conseguimos reduzir objetivos a passos deterministas. Porém, estique pra um período de tempo maior, e de repente variáveis que estávamos ignorando começam a aparecer e a dar efeito, até perdermos o controle. Pra todos os efeitos e propósitos, toda receita funciona pra coisas pequenas na dimensão de horas ou dias, mas nunca anos ou décadas, e pra todos os efeitos e propósitos, considere que é impossível ter uma receita determinista, repetível, de como ter sucesso na vida ou mesmo num projeto curto. Quanto mais complexo o objetivo e mais tempo for necessário, mais a aleatoriedade vai quebrar toda fórmula e todo planejamento.</p>
<p>Entenderam? É impossível prever o futuro. Os deterministas newtonianos perderam faz mais de um século já, desde quando descobrimos Relatividade, Física Quântica e Teoria do Caos. Por um lado, não perdemos nosso livre arbítrio. O futuro é incerto e suas decisões afetam o futuro, portanto você é responsável por elas. Mas por outro lado, é seguro dizer que é impossível ter uma receita de sucesso. Mas, cuidado, não é a mesma coisa dizer que estamos totalmente à mercê da aleatoriedade. Isso também nos tira livre arbítrio. O futuro não depende de só ter sorte ou ter azar. Na realidade ela depende das suas decisões somado a ter sorte ou azar. Se tudo fosse só aleatório, nós estaríamos vivendo em caos total. Mas você sabe que não é verdade. Então deixa eu explicar o que é a realidade.</p>
<p>Imagino que estejam confusos. Lembra em episódios passados do Guia de Aprendendo a Aprender ou o que Cursos não tem ensinam? Eu disse que todos vocês sofreram lavagem cerebral a vida inteira. Até se formar no colégio sua vida toda foi pré-determinada. Você sabia passo a passo o que vinha pela frente. Toda matéria era explícita. Você podia escolher não estudar, mas só. De repente você cai no mundo real, e descobre que não tem matéria pré-definida, não tem prova bimestral, não adianta tirar 5. Você não repete mais de ano, mas mesmo assim parece que todo ano é uma repetição do mesmo fracasso anterior. E por isso fica desesperado tentando achar de novo uma receita, como tinha no colégio. Você é um junkie, viciado em passar de ano artificialmente como se isso representasse algum tipo de progresso.</p>
<p>Toda vez que vem à sua cabeça “vou perguntar a receita do sucesso” pra alguém, você está com a noção que existe uma fórmula determinista, uma fórmula newtoniana, pra ter uma carreira de sucesso, ou um projeto de sucesso ou uma empresa de sucesso ou sucesso em geral. Você acha que existe uma forma de seguir passos pré-definidos, algum segredo que ninguém te contou, mas que se conseguir achar, seguir, trabalhar duro todos os dias, garantidamente vai atingir esse sucesso.</p>
<p>E eu contei toda essa história pra te confirmar o que você já sabia mas não queria admitir: esse segredo não existe. E só trabalhar duro não te garante absolutamente nada. Vou repetir: só trabalhar duro, sem método, não adianta nada. Na verdade, até tem um tipo de “segredo” sim, mas você provavelmente não vai acreditar que funciona. Na verdade é irônico que vocês preferem acreditar numa mentira bonita do que numa verdade inconveniente. Antes de chegar nela vou precisar contar outra história pra vocês que começa com um outro tema relacionado, chamado “qualidade”.</p>
<p>A primeira vez que parei pra pensar no termo qualidade, foi numa matéria eletiva na faculdade, lá no meio dos anos 90, alguma coisa sobre Qualidade Total. E eu quero que vocês parem dois segundos pra pensar: vocês conseguem definir a palavra &ldquo;qualidade&rdquo;? O que significa alguma coisa ter qualidade? Pra alguns, qualidade significa &ldquo;ter muitas funcionalidades&rdquo;. Pra outros significa &ldquo;ter a menor quantidade de defeitos&rdquo;. Também pode significar &ldquo;o que deixa o cliente mais satisfeito&rdquo;. Você consegue pensar numa definição não-ambígua, objetiva, que teria consenso de todo mundo? Acha que é possível?</p>
<p>Qualidade, assim como aprendizado, empreendedorismo, gestão, sucesso, é outro termo abstrato e subjetivo. O que pra mim parece ser de qualidade, pra outra pessoa pode ser o oposto. Um exemplo bobo é uma coisa que quem me segue no insta já me viu reclamando. Pra grande maioria das pessoas aqui no Ocidente, o que você encontra de sushi num buffet de churrascaria é de excelente qualidade. Inclusive, quanto mais cream cheese, mais qualidade parece ter. Não é isso? Agora, pra mim, e pra maioria dos Orientais, um sushi com cream cheese faz todos os melhores sushiman que já existiram no Japão virar nos seus caixões de desgosto. E o ponto é que no contexto de Ocidente, eu provavelmente estou errado: se existe demanda, provavelmente a qualidade não é zero, especialmente na definição que falei antes de &ldquo;o que deixa o cliente mais satisfeito&rdquo;. Se o cliente tem mau gosto, quem sou eu pra julgar.</p>
<p>Mas deixa eu voltar um pouco na história. No fim dos anos 70, começo dos anos 80, o mundo Ocidental se viu numa encruzilhada estranha. Assistam este trechinho do filme De Volta pro Futuro 3, que saiu no fim dos anos 80.</p>
<p>(&hellip; trecho)</p>
<p>Esse trecho é da hora, porque o Doc versão de 1955 fica chocado quando o Marty de 1985 fala que componentes eletrônicos japoneses são os melhores, mas na visão dos anos 50, se um componente dava problema, obviamente era por ser japonês. Lembrem-se, em 1945 o Japão perdeu a 2a Guerra Mundial, foi tomada pelos americanos, proibida de se armar de novo, e teve que reconstruir o país, depois de ter tomado duas bombas nucleares no rabo. Fazer o que, meio que mereceu. Mas o resultado é que o país inteiro ficou totalmente quebrado. Imagina reconstruir um país não do zero, mas do negativo.</p>
<p>Em pouco mais de 30 anos, só 3 décadas, ela foi de um país devastado que não conseguia produzir nada de qualidade, pra chegar nos anos 80 com os melhores produtos eletrônicos do mundo. Pra você que é novo, quanto é 30 anos? Se contar de hoje, é mais ou menos a partir dos anos 90 pra cá. Alguns podem achar que é pouco tempo, outros que é muito tempo, mas considere que essa é mais ou menos a idade da internet comercial. Nesse período nós evoluímos de todo mundo fazer ligações telefônicas de orelhão, pra quase todo mundo ter um computador ligado na internet no bolso. 30 anos é o tempo da minha carreira inteira.</p>
<p>Mas o ponto é que quando chegamos nos anos 80, pela primeira vez os Estados Unidos realmente ficaram com medo da invasão de produtos japoneses. Outro fator, foi na Inglaterra que começou a Revolução Industrial no fim do século 19. E nos anos 80 foi quando pela primeira vez ela tava importando mais produtos manufaturados do que exportando. E o Oriente, liderado pelo Japão, tava causando uma invasão inesperada, mas em vez de uma invasão de mísseis e explosivos, era uma invasão no sistema econômico, via produtos de consumo de alta qualidade e mais baratos que da concorrência.</p>
<p>E não só do Japão, mas de outros países orientais que ficaram conhecidos como os Tigres Asiáticos, incluindo Cingapura, Coréia do Sul, Hong Kong, Taiwan. Enquanto os Estados Unidos ficaram perdendo tempo com a Guerra do Vietnam e com a recessão até os anos 70, os asiáticos cresceram monstruosamente. Tudo bem que logo depois, o Japão meio que se fodeu com o estouro da bolha imobiliária e a grande recessão nos anos 90 que se segue até hoje. Essa foi a primeira década perdida deles. E nós notamos isso quando as marcas mais reconhecidas de produtos asiáticos eram Sony, Mitsubishi, Toyota, Honda e agora são Samsung, LG, Xiaomi, Huawei.</p>
<p>Mesmo assim, no começo dos anos 80 tava claro que o Ocidente precisava se modernizar. E por isso todos os olhos se voltaram pra Ásia, em particular, pro Japão. Que diabos eles estavam fazendo que conseguiam produzir produtos de alta qualidade em larga escala a preços baixos? Os governos e empresas ocidentais estavam realmente determinados a quebrar esse código. Eles mandaram pesquisadores e delegações pro Japão pra entender esse fenômeno. Nunca é um único fator. Tem o contexto histórico, tem a diferença cultural, tem até fator sorte. Por isso nunca acredite numa única resposta mágica que seja bala de prata.</p>
<p>Mas uma das coisas que eles descobriram, mais próximo de uma receita, foi o tal Modelo Toyota de Produção ou TPS. Esse modelo descreve o funcionamento e filosofia de uma fábrica inteira, não só a linha de produção, mas desde a contratação até a evolução das pessoas. O Ocidente se focou mais em técnicas, como o sistema de pull em vez de push, pra evitar desperdícios, que muitos de vocês já devem ter ouvido falar, o tal do Kanban. E o conceito que é o coração de praticamente toda metodologia que surgiu depois disso, o ciclo de melhoria contínua conhecido como Kaizen.</p>
<p>No começo dos anos 80 foram publicados vários livros relacionados mas tem 2 que preciso mencionar. O primeiro foi o famoso livro Out of Crisis, ou Saindo da Crise, do Dr. Edward Deming, famoso pelo ciclo PDCA que é similar ao modelo Kaizen da Toyota. PDCA pra quem nunca viu, é o ciclo básico de Planejar, Fazer, Checar, Ajustar e repetir. Já falo mais sobre isso mas esse livro tornou famoso os 14 pontos de gerenciamento de Deming como: criar constância de propósito, ou parar de depender de inspeção pra ter qualidade. Todo mundo que tem posição de gerência precisa pelo menos saber o que são esses pontos. Alguns são óbvios e ninguém faz direito até hoje, justamente porque ignora a história. Vou deixar um link com o resumo dos 14 pontos na descrição abaixo.</p>
<p>O segundo livro eu vejo coaches porcaria falando dele até hoje. É sobre o TOC, ou Teoria das Restrições do Dr. Goldratt. O livro onde ele apresenta essa teoria é o &ldquo;The Goal&rdquo;, publicado em 1984, no formato de uma novela, uma historinha mesmo, de um cara trabalhando numa fábrica e otimizando processos. Em resumo muito resumido ele fala sobre a idéia de resolver um problema de cada vez, a analogia de &ldquo;qual é a força total de uma corrente?&rdquo; E a resposta correta é &ldquo;a força do elo mais fraco&rdquo;. Portanto conserte o elo mais fraco primeiro. Mas agora outro anel vai se tornar o elo mais fraco, então conserte ele. E vai indo um anel de cada vez. É outra forma de explicar melhoria contínua.</p>
<p>Mas mais influente do que todos eles, acho que foi a Motorola por volta de 1986. Ela também foi afetada pela invasão japonesa e conseguiu dar a volta por cima criando uma nova metodologia que chamou a atenção de diversas outras empresas como a poderosa General Electric, de Jack Welsh. Foi a metodologia Six Sigma, que tem como objetivo fazer o processo de fabricação não produzir mais que 3.4 DPMOs ou 3.4 defeitos por milhão de oportunidades. Essa metodologia é bem mais detalhada, densa e tratada praticamente como uma doutrina que deve ser seguida à risca. Se você acha engraçado uma posição como scrummaster hoje em dia, Six Sigma tem faixas pretas e faixas verdes. E eles levam a sério saporra.</p>
<p>Se pra você um CEO influente é alguém como Elon Musk ou Jeff Bezos, nos anos 90 só se falava de Jack Welsh da GE. A Motorola inventou isso de Six Sigma mas foi a GE que tornou ela famosa. O objetivo era esse mesmo: como aumentar qualidade e diminuir custos ao mesmo tempo? E os resultados da Motorola foram impressionantes na época. O objetivo deles era melhorar 10X ao longo de 5 anos e eles ainda aumentaram a aposta de melhorar pra ser 10X a “cada” dois anos ou 100X em quatro anos! E em 10 anos de 1987 até 1997 eles cresceram as vendas em 5 vezes, lucros de 20 porcento ao ano, economia de uns USD 14 bilhões, e os preços das ações da Motorola subiram pra uma taxa de mais de 21 porcento ao ano.</p>
<p>Era isso que a gente lia nos anos 90. Mas olhando agora de 2022, obviamente você pode ver que nem mesmo os criadores do Six Sigma tiveram sucesso por tempo indeterminado. Quantos de vocês tem algum produto da Motorola hoje em dia? Não só isso, em paralelo, eu falei do tal Modelo Toyota, que todo mundo de gestão de desenvolvimento de software adotou também, o tal de Lean. Povo startupeiro ficou doido com o Lean Startup do Eric Ries em 2009, inspirado no mesmo Lean da Toyota. Mas se era tão bom assim, era pra gente estar vendo muito mais produtos Toyota ou Motorola hoje em dia, não? Cadê?</p>
<p>Vários autores já tentaram responder a essa pergunta como Clayton Christensen e seu famoso livro The Innovator’s Dillemma, ou O Dilema do Inovador. Ou Chan e Renée no livro The Blue Ocean Strategy. De novo, variáveis imprevisíveis que a fórmula não tem como prever, somado a um comportamento de sentar em berço esplêndido, em bom português, achar que já ganhou e desacelerar até concorrentes menores e mais motivados passarem na sua frente. Ou condições de mercado imprevisíveis como crises aparecerem quando você não tava preparado. Ninguém consegue prever o futuro e muitas vezes você fracassa mesmo, mesmo achando que sabe tudo.</p>
<p>O Ocidente se assustou com o Japão nos anos 80 mas ao longo dos anos 90 e 2000 eles aceleraram e alcançaram patamares semelhantes, daí tivemos a recessão do mercado japonês, e o surgimento do milagre Chinês no século XXI. O mundo não é estático e ninguém está de braços cruzados esperando. Todo mundo já já superou esses métodos. Mas isso não quer dizer que o Modelo Lean ou o Six Sigma são ruins, só quer dizer que a geração de administradores depois dos criadores dos modelos originais fracassaram em continuar evoluindo o método, pelo menos fracassaram em andar rápido o suficiente pra não ficarem pra trás.</p>
<p>Eu trago esses casos porque hoje em dia todo mundo vai encontrar um monte de jargões e conceitos que nasceram nos anos 80 mas todos repetem e usam sem entender porque. Enquanto o mundo de fábricas, manufatura e gestão empresarial em geral estava passando por essa revolução de qualidade ao longo dos anos 90, o mundo de desenvolvimento de software também estava passando por outras revoluções. A transição do mundo de mainframes e computadores inacessíveis para os microcomputadores nos anos 70 e 80 e depois a internet comercial dos anos 90 aos anos 2000. E não por acaso, nós pegamos inspirações no mundo de manufatura.</p>
<p>De onde veio essa idéia de Ágil que todo mundo fala hoje em dia? Da onde saiu esses rituais de planejamento, retrospectiva, sprints e Scrum? De onde veio essa idéia de desenvolvimento baseado em testes? Depois de estudar tudo que saiu dos anos 80 até hoje em gestão, eu penso que todo mundo chegou na mesma conclusão mais ou menos ao mesmo tempo. Alguns foram inspirados por autores como Deming, alguns copiaram uns aos outros mesmo, e alguns realmente pararam pra pensar no problema e naturalmente chegaram a soluções parecidas. Os princípios de todos eles são simples e qualquer um conseguiria chegar em conclusões semelhantes. E chegaram, na real.</p>
<p>No coração do mundo Lean da Toyota está um princípio chamado Kaizen, ou melhoria contínua. Foi Deming quem definiu esse princípio em sua forma mais geral no chamado ciclo PDCA, que é sigla pra Planejar, Definir, Checar e Agir. No mundo da Toyota o conceito é que nenhum problema é resolvido permanentemente na primeira tentativa. Todo problema identificado deve dar origem a uma contramedida. E essas contramedidas podem ser de curto prazo, tipo um band-aid pra corrigir rápido, mas seguido de contramedidas de longo prazo, que buscam resolver o problema na raíz. Daí que vem técnicas como os famosos 5 Ps ou 5 porques. Deixa eu pegar um exemplo do livro.</p>
<p>Digamos que o problema identificado seja “as unidades de fabricação por hora estão abaixo da meta”. Por que? “Não conseguimos produzir peças suficientes por hora”. Por que? “Estamos perdendo oportunidades de produção”. Por que? “Perda de tempo”. Por que? “Perdas de tempo de ciclo”. Por que? “A carga da máquina leva muito tempo”. Por que? “O operador precisa caminhar um metro e meio pra ir pegar o material”. Opa. Esse parece ser a raíz do problema, e o que podemos fazer?</p>
<p>Dar um jeito de reduzir essa caminhada. Portanto, isso vai diminuir o tempo pra carga da máquina. Portanto, isso vai reduzir perdas de tempo de ciclo. Portanto, isso vai aumentar o tempo disponível. Portanto, isso vai aumentar as oportunidades de produção. Portanto, isso vai produzir peças suficientes por hora. Portanto, talvez consigamos atingir as metas de unidades de fabricação por hora.</p>
<p>Ou seja, temos o problema que estamos fabricando poucas peças por hora. A hipótese da raíz do problema é que o operador precisa caminhar demais toda hora pra pegar material e recarregar a máquina. Uma possível solução é trazer mais material pra perto do operador. Mas isso vai resolver de verdade? Só nos restar testar. Depois de um certo período de tempo, que poderíamos chamar de “sprint”, vamos verificar a quantidade de peças produzidas por hora e verificar se realmente voltamos a atingir a meta por hora. Se sim, podemos definir uma contramedida de longo prazo talvez colocando um armazém mais próximo com os materiais pra todos os operários. Se não, analisamos de novo e buscamos uma nova hipótese pra testar.</p>
<p>O que eu falei pareceu meio óbvio? Esse exemplo é da página 334 do manual de aplicação do Modelo Toyota. Um livro de 423 páginas. Isso não é o primeiro capítulo, é uma das partes finais do manual. O que eu acabei de explicar é o processo PDCA. Planejar uma contramedida que é diminuir o tempo de carga do operador. Realizar a contramedida que é estocar mais material próximo dele. Daí checar, medir o tempo médio de produção e validar que a meta foi atingida ou não. Finalmente, agir em estabelecer uma contramedida de longo prazo ou procurar outra possível raíz do problema. Resolveu? Então o elo mais fraco mudou pra outro elo, repete o processo e assim por diante.</p>
<p>No mundo Six Sigma não se fala de PDCA e sim de DMAIC, que é sigla pra Defina, Meça, Analise, Melhore, Controle. É um pouco mais específico no sentido que uma vez resolvido o problema, controle e garanta que o problema não se repita. Além disso as métricas também são estatisticamente mais exigentes, a começar pelo objetivo do nome: alcançar o nível Six Sigma que significa não mais que 3,4 defeitos por milhão de oportunidades ou 99,9997% de qualidade. Mas em princípio, PDCA e DMAIC são a mesma coisa.</p>
<p>Sabe o que mais é a mesma coisa? Um sprint de Scrum. Planeje as stories, trabalhe e programe, no final faça retrospectiva, revise as métricas, ajuste o processo, recomece outro sprint. Isso não é por acaso. Existe outro ciclo parecido que é a base da civilização moderna. Sim, o tal método científico que todo pseudo-cientista de Twitter esquece que existe. O método começa pela observação, que deve ser sistemática e controlada, a fim de que se obtenham os fatos científicos.</p>
<p>O método é cíclico, girando em torno do que se denomina teoria científica, a união do conjunto de todos os fatos conhecidos e de um conjunto de hipóteses testáveis. Os fatos, embora não necessariamente reprodutíveis, têm que ser necessariamente verificáveis. As hipóteses têm que ser testáveis frente aos fatos, e por tal, falseáveis. As teorias nunca são provadas e sim corroboradas. Se você está focado em tentar provar alguma coisa via algumas poucas evidências, você não está praticando o método científico, está só se inventando uma história.</p>
<p>Mais importante, o método científico é cíclico. Se a hipótese falhou, checam-se os novos fatos, ajusta-se a teoria, e verificamos as previsões de novo. A cada nova tentativa, aprendemos novos fatos. Melhoramos a teoria, continuamente. De novo, melhoria contínua, ou Kaizen. Todos os modelos ciclicos, PDCA de Deming, DMAIC de Six Sigma, Kaizen de Lean, Sprints de Scrum, MVPs de Lean Startup, tem em comum o fato de serem métodos de resolução de problemas desconhecidos. Eu iria um passo além e dizer que esse é o único método que conhecemos hoje pra resolução de qualquer problema desconhecido.</p>
<p>É meio anticlimático, mas eu falei que vocês talvez tenham dificuldade de aceitar que a única solução pra todos os seus problemas se chama literalmente “tentativa e erro”. Qual a melhor forma pra estudar? Tentativa e erro. Qual a melhor forma de gerir um projeto? Tentativa e erro. Qual a melhor forma de administrar uma empresa? Tentativa e erro. Qual a receita pra ter sucesso? Tentativa e erro.</p>
<p>Todos que tentaram seguir receitas, fracassaram. O mundo não é determinista nem newtoniano. A fórmula que você está procurando não existe. A coisa mais frustrante que existe no mundo corporativo até hoje, em particular com empresários amadores, é justamente essa idéia de trazer consultores com balas de prata, que ficam ali um, dois anos tentando implementar um monte de ferramentas e métricas, e no final o resultado é uma droga. É o mesmo problema do monte de gente confiando em cursos mágicos que garantem resultados irreais e achar que certificados garantem alguma porcaria. Todos vocês estão cometendo o mesmo erro, que foi o que a Toyota dos anos 80, a GE dos anos 90, a Apple dos anos 2000 conseguiram melhor que os outros: resolver um problema de cada vez e melhorando um passo de cada vez de maneira sistemática.</p>
<p>Óbvio, quando eu falo “tentativa e erro” não é só sair tentando qualquer coisa e se contentar com todos os erros. Tentativa e erro não é isso. Primeiro, é não errar a mesma coisa mais de uma vez. Isso tem que ser sistemático, é o ítem de controle do DMAIC de Six Sigma. Segundo, é testar logo, é a contrapartida de curto prazo de Lean da Toyota. Terceiro, é ter obcessão por evitar todo e qualquer tipo de desperdício, que é a raíz de toda metodologia de qualidade. Quarto, é não copiar ninguém, e sim identificar e resolver um problema de cada vez que você tenha, sistematicamente, disciplinadamente, obcessivamente, num nível de psicopata mesmo.</p>
<p>Isso me lembra um meme de desenvolvimento de software que alguns de vocês já devem ter visto alguma versão. Lembra os 5 Ps que falei antes? Por que vocês não escrevem testes pras novas funcionalidades? Porque não temos tempo. E por que não tem tempo? Porque tem muita coisa pra fazer e o sistema tem muitos bugs inesperados que nos atrasam. E por que tem tantos bugs? Porque o sistema não tem testes. E por que vocês não escrevem testes? Porque não temos tempo! - É impressionante que toda desculpa se resume a “não tenho tempo”. Quer uma novidade? Ninguém nunca tem tempo. A diferença entre eu e você é que eu não uso tempo como desculpa. Se tem uma coisa que todo mundo tem igual é tempo, a diferença é que alguns priorizam as coisas melhores do que outros. Por que vocês acham que um dos primeiros videos que fiz neste canal é justamente sobre priorização?</p>
<p>Se voltar pra você enquanto estudante. Tem milhões de coisas que você não sabe. E isso deixa você explodindo em ansiedade. Você gasta um tempo fazendo cursos ou seguindo tutoriais. Mas parece que não está evoluindo. O tempo passa, a quantidade de coisas que você não sabia parece que só aumenta. E no desespero começa a ouvir coaches e gurus vendendo cursos mágicos que prometem que vão te acelerar. E você vai na conversa.</p>
<p>Seja tentando descobrir como estudar, ou como gerir um projeto, ou como administrar uma empresa, você sempre entra num momento de desespero e tenta achar alguma fórmula mágica. Você tenta sair do caos e encontrar alguma ordem, seja lá qual ordem, pra tentar conseguir algum progresso. Ordem e Progresso. Eu pessoalmente sempre achei essa frase muito estranha. Ordem não leva ao progresso. Ordem no máximo mantém as coisas no mesmo lugar, o que não é progresso, mas o mais natural é que só ordem eventualmente deteriora e retorna à desordem. É inevitável. Até se falarmos de novo em termos de física, é a 2a lei da termodinâmica. Todo sistema fechado tende a aumentar a entropia, que é o grau de desordem. É literalmente uma lei da física.</p>
<p>Ordem e progresso é o lema dos positivistas de Auguste Comte, ironicamente ela é pró-ciência, mas derivada da época da Revolução Industrial e realmente se acreditava que o pré-requisito pro progresso seria criar ordem. Obviamente é um pensamento já ultrapassado, assim como o determinismo newtoniano. Mas o que eu quero argumentar é que ordem não leva ao progresso. E alguns poderiam concordar dizendo que caos leva ao progresso. Mas anarquia absoluta também não leva a progresso. Então qual a saída?</p>
<p>Já que falei da física que você aprendeu no colégio, lembra outra coisa que aprendeu naquela época? O que acontece quando você ferve água e ele chega no ponto de ebulição de 100 graus celsius no nível do mar? Ele começa a virar vapor certo? Por outro lado se congelar essa água pra baixo de zero graus celsius, ela muda de líquido pra sólido. São as mudanças de fases de um material. Isso é transição de fase de um sistema em equilíbrio. Não vou tentar explicar termodinâmica, nem sou especialista e é muito fácil fazer metáforas erradas, mas deixa eu só arriscar um pouco. A parte importante é só pra lembrar que existe esse fenômeno de transição de fases de um estado de baixa entropia pra um estado de mais entropia, da ordem do gelo pro caos do vapor e de volta pra líquido.</p>
<p>Eu gostaria de ter um pouco mais de bases pra conseguir explicar Einstein, Podolski, Rosen, condensado Bose-Einstein, transição de fase de não-equilíbrio. Quem for físico assistindo, vejam se conseguem explicar em português nos comentários abaixo. Mas vamos nos contentar só com um conceito. A entre-fase entre uma fase e outra, a fronteira que separa uma fase de outra durante sua transição, que é conhecido como Edge of Chaos ou beira do caos, como foi cunhado nos anos 80 na Teoria do Caos por Norman Packard. Mas é na biologia que esse conceito me chamou mais a atenção, em particular no fenômeno de adaptabilidade de sistemas complexos não-lineares. Eu falei um pouco sobre isso no episódio sobre Organizações, depois assistam.</p>
<p>Eu sei que tá ficando bem meta isso, mas aguentem firme. A observação interessante é que todos sabemos que ao longo de milhões de anos, todos os seres biológicos sofrem mutações e via seleção natural temos a evolução das espécies. Mas interessante como apesar de tantas mutações, apesar da segunda lei da termodinâmica que falei antes, os ecossistemas não decaem em caos. Fala-se em adaptabilidade na beira do caos. E falando em termos mais gerais, beira do caos é usado como metáfora pra descrever outros fenômenos difíceis de explicar em sistemas complexos, como uma sociedade por exemplo. Se tudo tendesse ao caos e aleatoriedade, como explicar que todos nós, conseguimos conviver numa sociedade organizada e estruturada que, apesar de altos e baixos, não regride pra puro caos, mas parece avançar. Devagar e sempre?</p>
<p>Beira do caos é o que temos na transição de fase entre ordem e aleatoriedade ou caos. Não temos nem ordem e nem caos, mas ficamos indo e voltando entre ordem e caos. E se isso tá ficando esquisito, existem pesquisas que argumentam que nosso cérebro, nossa rede neutral, funciona mais ou menos na beira do caos. E em particular no campo de Deep Learning existem pesquisas de aplicação do conceito de beira do caos pra melhorar inteligência artificial. Ainda é um campo aberto e em estudo, mas onde eu quero chegar é que nem ordem e nem caos levam ao progresso, nem à adaptabilidade e evolução, mas sim um estado transitório entre ordem e caos, que é a beira do caos.</p>
<p>E aqui vem uma hipótese minha. Pra mim, beira do caos, é o que todo mundo realmente quer dizer quando falamos em “encontrar balanço”, ou “ser equilibrado”. Quando falamos isso, todo mundo pensa automaticamente em ordem, num sistema estático, fixo. Mas eu acho que isso tá errado. Balanço é justamente balançar entre ordem e caos. Por um lado você entende balanço como ordem, como equilíbrio estático, que significa uma balança com os dois lados sempre imóveis e fixos. Pra mim balanço é beira do caos, pendendo entre ordem e caos de tempos em tempos. É um equilíbrio, só que é dinâmico. Hora é +10 pontos, hora é -10 pontos, na média dá zero, saca. Esse é o “segredo”. E como fazemos isso? Disciplinadamente evoluindo um passo de cada vez num ciclo entre ordem e caos.</p>
<p>Se não ficou claro ainda: todos os ciclos que eu expliquei antes: o PDCA de Deming, o DMAIC de Six Sigma, o Kaizen de Lean, o Sprint de Scrum. Durante um sprint de Scrum exercitamos a ordem: trabalhamos linearmente, uma story de cada vez, ao longo da semana. No final fazemos retrospectiva e no review adicionamos um pouco de caos, uma mudança com objetivo de testar uma nova hipótese de resolver um problema. Iniciamos um novo sprint, ordem de novo. Terminamos com um novo review e adicionamos mais um pouco de caos, que é sair um pouco da ordem anterior. Assim como uma mutação genética esperando uma seleção natural no mundo biológico. Ou como nossos neurônios funcionam pra promever aprendizado.</p>
<p>É por isso que você está constantemente ansioso e inseguro quando está estudando. Você tem um programa pra seguir, aulas pra assistir, trabalhos pra fazer, materiais pra ler, mas não sente que tá evoluindo. E é claro. Provavelmente não está mesmo, só tá fazendo o tempo passar. Quantas vezes você pára e testa o que sabe? Realmente testar. No caso de programação, parar e fazer um programinha simples do zero diferente de tudo que já foi pedido nos exercícios? Fora da zona de conforto, tirando as rodinhas da bicicleta? Você nunca faz isso. E quando tenta, não consegue e desiste rápido. Mesmo quando um professor pára pra dar uma prova, isso não testa nada, no máximo que você é bom de decorar as coisas. Mas decorar coisas não torna ninguém um bom profissional em nada.</p>
<p>O ideal seria que os professores dessem provas surpresa o tempo todo. E que as aulas fossem ajustadas e modificadas depois dessas provas. E as provas não tivessem nada de decoreba e sim de raciocínio lógico, que desse pra deduzir a maioria das respostas só por indução e bom senso. Todo mundo aqui ia odiar isso, e eis o motivo: seria caótico, seria fora de ordem, poderia até parecer injusto. Mas eis a realidade: o mundo real é caótico, fora de ordem e injusto, mas você nunca treinou pra isso. Sua reação instintiva é tentar encontrar ordem onde ela não existe. E aí vocês ficam que nem idiotas perguntando pra influencers o que eles acham que você deveria estudar, que cursos deveria fazer, que livros deveria ler. Não importa. Nada disso importa se você não está preparado pra viver à beira do caos. Abandonar esse conceito que existe uma ordem, e abraçar momentos de caos e incerteza como coisas boas.</p>
<p>Se ainda não ficou claro vou repetir. É impossível prever o futuro. Tentar prever é um exercício em futilidade. Tentar planejar tudo que vamos fazer anos pra frente é inútil. Em vez disso planejamos só o que é possível: uma semana pra frente, um mês pra frente, não muito mais. Agora executamos. Seja estudo, seja trabalho num projeto, seja administração de uma empresa. O importante é parar depois de um período curto de tempo e checar a hipótese. Conseguimos atingir essa pequena meta? O que deu errado? O que dá pra melhorar? Adicionamos um pouco de caos, reformulamos a hipótese, e agora continuamos executando por mais um período de tempo. Paramos de novo. E repetimos esse ciclo, resolvendo um pequeno problema de cada vez, melhorando um pequeno aspecto de cada vez, mas garantindo que não estamos cometendo os mesmos erros, e que a melhoria que fizemos vai se acumular.</p>
<p>Você tem dúvida se vai gostar de um determinado curso de 10 meses? Nunca, jamais, sob hipótese nenhuma, compre os 10 meses adiantado, isso é estupidez, é tentar prever o futuro - que já estabelecemos que é impossível. Pare de insistir no impossível. Pague 1 mês e teste. Se gostar e ver resultados, pague mais um mês. Ah, mas se pagar os 10 meses de uma vez vai ser mais barato. Não, não vai. Porque se você não gostar, vai jogar 10 meses fora. Por outro lado, se pagar só um mês e não gostar, vai jogar fora só esse 1 mês. Mas e se o curso não der opção de pagar só um mês? Isso é sinal que eles não acreditam no que estão vendendo e precisam já te forçar a pagar tudo de uma vez pra não poder desistir. Isso é um sinal claro que você pode descartar essa opção porque sem nem experimentar já sabemos que se trata de uma grande fraude. Tá vendo, é assim que evitamos ser feitos de idiotas.</p>
<p>E isso vale pra tudo. Pegue um projeto longo, como garanto que consigo entregar? Eu não garanto. Sempre use a boa e velha estratégia de Jack o estripador: vá por partes. E sempre se lembre do bom e velho Napoleão: dividir pra conquistar. É daí que nasce o conceito de Minimal Viable Product ou MVP de Lean Startup. Em vez de tentar planejar um sistema gigante que parece que vai levar 2 anos pra uma equipe de 10 pessoas entregar, primeiro escolha 1 funcionalidade, em versão simplificada, que é a mais importante do sistema e que 2 pessoas consigam fazer em 2 meses.</p>
<p>Você vai aprender mais sobre a equipe, sobre o produto, e no final de 2 meses, se não gostar do resultado, só perdeu 2 meses e não 2 anos. E se não ficou claro, todo projeto você define o custo e o tempo primeiro, daí encaixa só o que couber nesse limite. O que não couber, não coube. O errado é definir todo o escopo primeiro e tentar fazer o custo e o tempo encaixar. Isso é impossível e quem faz isso parece um idiota tentando encaixar uma peça redonda num buraco quadrado.</p>
<p>A mesma coisa vale do ponto de vista de um programador como eu ou você. Na dúvida, comece fazendo um protótipo. Um código que talvez você pode jogar fora. Talvez não, um código que certamente vai jogar fora. Programar não é só digitar código que nem um idiota. É jogar fora a maior parte do que digitar. Escreva e jogue fora. Escreva e jogue fora. Acostume-se a jogar fora o que faz. Nem tudo que você faz é especial, a maior parte nunca é. Nunca vai ser especial se guardar tudo.</p>
<p>Você precisa jogar fora e produzir mais. Programe um dia inteiro, qualquer coisa, sem nenhum propósito real. E no final do dia, jogue tudo fora. Quantas vezes ouviu alguém dizer isso? Se nunca ouviu falar isso, você só teve péssimos professores. Jogue, tudo, fora. Respira. Começa tudo de novo. Se você economiza e escreve só o que parece que precisa, só pra uma tarefa em especial, e raramente joga alguma coisa fora, eu tenho certeza que você é medíocre.</p>
<p>Só quando tiver uma versão mínima que se sinta realmente confortável, só aí comece a se comprometer com esse código. Desde o começo você vai cometer erros e, pior, começar a repetir os mesmos erros. Adicione testes unitários. Isso garante que no mínimo o que já foi feito, vai continuar funcionando, mesmo que você continue experimentando adicionando mais coisas. Pare, reflita o que fez, adicione caos, refatore o código, pague parte da dívida técnica, e continue. E repita esse ciclo. É como desenvolvimento de software moderno funciona, e não é à toa.</p>
<p>Tudo que você, ou faz sem pensar e só vai fazendo no caos, ou tudo que planeja demais e segue cegamente um plano sem parar pra revisar, vai dar errado. Você precisa balancear ordem e caos. O que significa que precisa intercalar períodos de ordem com períodos de caos, é isso que significa achar balanço. E não é aleatório. Em todo intervalo você mede e critica a hipótese original. Modifica a hipótese e tenta de novo. Nem só ordem, nem só caos. Dar um passo pra trás pra conseguir dar dois passos pra frente. Isso é o que eu quis dizer no começo com “tentativa e erro”, uma forma cíclica de sistematicamente melhorar um passo de cada vez. Melhoria contínua ou Kaizen. Sempre balanceando na beira do caos.</p>
<p>O que estou tentando fazer vocês refletirem é que provavelmente sua forma de pensar ainda é newtoniana determinista positivista, buscando ordem absoluta, evitando caos o máximo possível, com a promessa de progresso. A razão disso é muito simples: vocês tem medo de errar. E nesse medo acaba acreditando que algum guru ou alguém mais especial que você vai dar o camiho das pedras. O segredo é simples: assuma que vai errar, só garanta que vai errar pouco e errar cedo pra não sair tão caro. Daí é só ajustar e repetir.</p>
<p>A raíz do problema de tudo na sua vida é medo. E é um grande clichê mas ainda bem que você tem medo. Parece que tem gente que não tem medo de nada e sai enfiando a cabeça em tudo, até literalmente rachar a cabeça num poste, ou pior, atropelar alguém. Isso não é coragem, isso é imprudência, ou melhor, pura burrice mesmo. Coragem é dar um passo pra frente, mesmo com medo. Eu falei no video sobre como eu aprendi inglês que o que falta pra maioria dos adultos é voltar a ser criança um pouco. A diferença de porque crianças parecem ter mais facilidade de aprender as coisas que adultos é porque elas não tem medo de serem julgadas, de alguém ridicularizar os resultados ruins que ela vai ter no começo. Elas simplesmente ignoram os comentários dos outros e seguem em frente até conseguir o que querem.</p>
<p>Elas viram adultos quando a prioridade passa a ser imaginar o que essa entidade abstrata e fantasiosa chamada “outros” pode pensar dela. Será que vão achar que sou lento? Será que vão achar que sou incompetente? Será que vão achar que eu não levo jeito. Será que vão achar que sou velho demais pra começar? Esse monte de “será” inútil se torna sua muleta e sua rotina de desculpas pra não fazer nada e você se torna um adulto realmente inútil, absolutamente chato e totalmente desinteressante. Todo dia que você não faz nada porque acha que é tarde demais só garante uma coisa, que amanhã vai ser tarde demais menos um dia.</p>
<p>O que você precisa fazer? Ligar o foda-se pra opinião dos outros. Opinião é lixo, opinião não vale nada, e principalmente, a opinião dos outros não paga minhas contas. Felizmente eu pago minhas próprias contas, não dependo de ninguém e por isso eu tô literalmente cagando e andando pro mundo. Se o mundo resolver criticar o que eu estou fazendo falando que é infantil, ou não combina ou qualquer merda dessas, minha resposta é sempre a mesma: vem pegar minhas bolas pra ver se tá gelado.</p>
<p>Programação é a mesma coisa: você não precisa começar programando nada que seja útil. Só precisa começar a programar qualquer coisa, qualquer lixo, pra perder o medo da janela vazia do editor de textos. Programe qualquer coisa e jogue fora. E se você não consegue imagina o que significa algo inútil, esses dias me lembrei que toda distribuição Linux dá pra instalar um programinha super inútil chamado “cowsay”. Em alguns já vem instalado, mas num Arch linux dá pra instalar com <code>pacman -S cowsay</code> ou num Ubuntu acho que um <code>apt install cowsay</code> também funciona. Daí abre um terminal e digita <code>cowsay</code> seguido de uma mensagem qualquer e olha o que aparece.</p>
<p>Sim, esse programa desenha uma vaca com caracteres ASCII na tela. Só isso. Você já viu um programa mais inútil que isso? E mesmo assim é um programa que todo mundo que usa Linux faz algum tempo sabe que existe. Pode sair perguntando pros seus amigos mais veteranos e todos eles vão saber disso. Esse programa existe faz anos, foi escrito em Perl e eu acho que é um excelente exercício pra um iniciante de qualquer linguagem. Experimente fazer um cowsay em Javascript, ou em C# ou em Go, não importa. E pra que? Pra absolutamente nenhuma razão, só pra fazer. Jogue fora no final, faça de novo em outra linguagem, faça outra imagem diferente da vaca, como do pinguim Tux que é outra opção desse programa. Só faz. Programar não tem que ter outro objetivo além de programar em si mesmo. O código no final não é importante, só saber que você é capaz. No final pode jogar fora esse código.</p>
<p>Aliás, eu fico pasmo e chocado quando vejo gente com medinho de começar a escrever código sem objetivo, sem utilidade, com a mentalidade que se ele não fizer algo que funcione perfeito, nem vale a pena começar a fazer. Mas ao mesmo tempo perde horas vendo TikTok, Instagram, jogando Candy Crush ou LOL ou qualquer outra porcaria desses. O que você produziu depois de ficar 1 hora jogando LOL? Absolutamente nada. Ficou mais rico? Não. Ficou mais inteligente? Não. Avançou sua carreira? Não. Foi uma total e completa perda de tempo. Mas você fez mesmo assim. Encare fazer código da mesma forma. Só faça, sem objetivo. Garanto que vai ser mais útil fazer um cowsay pra jogar fora do que jogar meia hora de Candy Crush.</p>
<p>Aprendizado, gestão, empreendedorismo, qualidade, todas essas palavras subjetivas pra mim se resumem a uma coisa: gerenciamento de risco. Gerenciar risco não significa ter zero risco. Muita gente medrosa acha que o objetivo é zerar os riscos. Zero risco é você nunca sair da sua cama, porque só de se levantar você corre o risco de tropeçar, bater a cabeça e morrer. Todos os dias você aceita diversos riscos. Risco de morrer num acidente de carro. Risco de ser morto num assalto na rua. Risco de um fucking meteoro cair na sua casa. Não existe vida sem risco. Se você tentar só minimizar risco, é a mesma coisa que não viver. Morre de uma vez então. Em vez disso assuma que o risco vai existir e você vai avançar de forma prudente, só isso.</p>
<p>Pra finalizar esse motivacional, relembrei de um video motivacional que eu mostrava em palestras que eu fazia lá por 2010 e 2011. É super clichê. Mas nem por isso é menos verdade.</p>
<p>(life == risk)</p>
<p>De novo, nada disso significa ser imprudente. Significa ter coragem. Pra ter coragem você não precisa quebrar leis nem migrar pra esportes radicais. Significa a coragem de simplesmente fazer uma página de código inútil que vai jogar fora no final. Significa testar uma idéia num projeto, num ambiente controlado, e assumir que se não der certo, tudo bem porque o experimento no mínimo vai te informar que aquela direção não ia dar certo. Saia da ordem tempo suficiente pra testar um caos controlado, aprender algo com isso, e reajustar pra uma direção melhor.</p>
<p>Em vez de tentar prever o futuro e errar completamente, você vai ajustando a direção um pedaço de cada vez até chegar no objetivo que queria, com menos desperdício do que se tivesse tentado planejar tudo em detalhes desde o começo. Tentar planejar todos os passos antes de começar a achar que vai conseguir adivinhar todos os passos até o fim é o maior desperdício de todos. Em gerenciamento de risco a máxima é que se sentar ter zero riscos vai acabar tendo 100% de perda. Gerenciar riscos é que nem um seguro de carros. Todo ano você paga e parece um desperdício porque nunca tem um acidente. Imprudência é decidir que isso é um desperdício e cancelar o seguro. É quando você vai ter um acidente feio e não vai ter dinheiro pra cobrir o prejuízo. Isso sim é um desperdício de verdade. Aceite um prejuízo pequeno pagando o seguro. Economia porca não é a mesma coisa que não desperdiçar.</p>
<p>Isso tudo dito, agora eu quero que vocês pensem em outra coisa. Tudo isso que eu falei aqui, eu não li num post de blog essa semana e vim repetir pra vocês. Quem acompanha meu blog desde pelo menos 2008 já leu algumas dessas coisas. Eu sempre tive as mesmas dúvidas que todos vocês. Será que eu estou estudando do jeito certo? Será que estou gerenciando projetos da melhor forma? Será que administro empresa do jeito certo? E se não ficou claro, todas essas perguntas sempre são a mesma coisa. Administrar uma empresa, gerenciar um projeto ou aprender algo novo, tem os mesmos princípios. Você é uma empresa de uma pessoa só, sua carreira é um projeto, e tudo é um aprendizado. Não são assuntos distintos.</p>
<p>Como você vai aprender se não sabe o que significa aprendizado? Como vai entregar um projeto se não sabe definir o que é gerenciar? Como quer empreender se sequer sabe definir o que significa a palavra empreender? A maioria de vocês tem um entendimento superficial dessas palavras e os diversos posts de Linkedin, palestras de gurus e videos de influencers, cada um vai vomitando definições erradas, sem dar fontes, dizendo só o suficiente pra você comprar os cursos deles. Fazendo frases bonitas de efeito com tom afirmativo e confiante. É tática de vendedor e você cai que nem um pato, porque tem preguiça de pesquisar.</p>
<p>Ao mesmo tempo que sempre teve um monte de coisas de programação e tecnologia que eu queria aprender e nunca parei de estudar, eu me cansei de não ter certeza e em paralelo gastei uma década estudando todas as coisas que mencionei neste video e muito mais. Essas coisas não se ensina na escola. Quem é de engenharia de produção deve ter reconhecido quando falei sobre coisas como Lean e Six Sigma. Quem é de física e biologia reconheceu quando falei de transição de fases e adaptabilidade. Quem é de economia já deve ter ouvido conceitos similares também.</p>
<p>Parte da sua carreira, se quiser evoluir pra uma etapa superior, é sair da sua própria área e investigar um pouco da área dos outros, em particular das ciências de verdade. Vai notar que muitos assuntos que discutimos em engenharia de software como se fosse uma grande novidade na verdade já existe em economia, física, biologia, outras engenharias, faz décadas. Pare de ler posts motivacionais de LinkedIn, que contribuem zero pra sua carreira, e busque a literatura original. Eu sempre falo que os livros que realmente compensam ler precisam passar pelo teste do tempo, e a maioria é do século passado. No meu caso, eu tive a sorte de esbarrar em alguns deles lá atrás, nos anos 90 e começo dos anos 2000. E já adianto que de lá pra cá não teve tanta novidade não, só os mesmos assuntos que ganharam outros nomes e por isso parece que tem tanta coisa nova. De novo, técnica de venda, marketing, e você continua caindo. Os últimos 10 anos foram muito tediosos nesse sentido.</p>
<p>Em resumo, por mais estranho que os conceitos apresentados pareçam, é basicamente assim que todo ecossistema da natureza funciona. Sem um sistema centralizado de autoridade. Sem um planejamento centralizado. Sem uma ordem definitiva que todos os animais e seres vivos sigam. À primeira vista parece um sistema fechado que vai deteriorar com o tempo, aumentar a entropia, como na segunda lei da termodinâmica. Mas em vez disso sabemos que não só esse sistema não deteriorou como evoluiu, desde microorganismos nos oceanos milhões de anos atrás, até a diversidade de espécies que temos hoje. Esse é o resultado de um sistema de beira do caos.</p>
<p>Mais importante, descentralização, livre competição, adaptação, são características de um sistema natural. Autoridade centralizada, planejamento ordenado, são características de um sistema artificial que sempre deteriora. É inevitável. Portanto tirem da cabeça que qualquer sistema assim possa jamais funcionar, seja sistema educacional, sistema empresarial, sistema econômico ou sistema político. Mesmo que por um curto período de tempo parece que funciona, eventualmente começa a deteriorar.</p>
<p>Enfim, como disse no começo, a intenção desse episódio foi só apresentar as fontes de onde tirei meu modelo mental de como fazer as coisas. A idéia não é vender nada e nem dizer que essa é a única maneira de pensar. Só uma introdução pra desmistificar o que alguns gurus possam estar tentando te vender de forma incompleta como se fosse grande novidade. Eu tenho um pensamento quase obcessivo nessa idéia de beira do caos e melhoria contínua. Toda vez que estou fazendo a mesma coisa do mesmo jeito por muito tempo, eu preciso chacoalhar e fazer alguma coisa diferente.</p>
<p>E pra quem chegou faz pouco tempo no canal. Eu venho contando aspectos disso em diversos videos, em particular na playlist de carreira, onde falo sobre faculdade, mercado, carreira e como encarar os desafios de se comprometer, assumir suas responsabilidades e parar de terceirizar suas decisões pra um influencer bosta qualquer. O medo é sempre o mesmo: e se eu errar. Ué, se errar errou. Levanta, e faz de novo, diferente, pra não errar a mesma coisa. Louco é aquele que fazendo sempre a mesma coisa, espera ter resultados diferentes. Se ficaram com dúvidas mandem nos comentários abaixo, se curtiram o video deixem um joinha, assinem o canal e não deixem de compartilhar o video com seus amigos. A gente se vê, até mais.</p>
]]></content:encoded><category>agile</category><category>engenharia-de-software</category><category>akitando</category></item><item><title>[Akitando] #106 - Recomendação de Livros - Introdução à Design Emergente</title><link>https://akitaonrails.github.io/2021/10/11/akitando-106-recomendacao-de-livros-introducao-a-design-emergente/</link><guid isPermaLink="true">https://akitaonrails.github.io/2021/10/11/akitando-106-recomendacao-de-livros-introducao-a-design-emergente/</guid><pubDate>Mon, 11 Oct 2021 12:31:00 -0300</pubDate><description>&lt;div class="embed-container"&gt;
&lt;iframe
src="https://www.youtube.com/embed/uDqgcsK8Kbc"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2&gt;DESCRIÇÃO&lt;span class="hx:absolute hx:-mt-20" id="descrição"&gt;&lt;/span&gt;
&lt;a href="#descri%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Toda hora alguém me pergunta &amp;ldquo;quais livros eu devo ler?&amp;rdquo; Normalmente eu não respondo, mas hoje resolvi fazer uma primeira lista de livros e temas que eu acho relevantes pra maioria dos programadores. Não é uma lista completa mas eu quero aproveitar pra tocar num tema que você eventualmente vai precisar entender: profissionalismo na área de programação e principalmente entender o que é &amp;ldquo;Design Emergente&amp;rdquo; em software.&lt;/p&gt;</description><content:encoded><![CDATA[

<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/uDqgcsK8Kbc"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<h2>DESCRIÇÃO<span class="hx:absolute hx:-mt-20" id="descrição"></span>
    <a href="#descri%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Toda hora alguém me pergunta &ldquo;quais livros eu devo ler?&rdquo; Normalmente eu não respondo, mas hoje resolvi fazer uma primeira lista de livros e temas que eu acho relevantes pra maioria dos programadores. Não é uma lista completa mas eu quero aproveitar pra tocar num tema que você eventualmente vai precisar entender: profissionalismo na área de programação e principalmente entender o que é &ldquo;Design Emergente&rdquo; em software.</p>
<p>Meio que é uma continuação ao que eu disse no meu video sobre &ldquo;Empreendendo em Software do Jeito Errado&rdquo; quando eu disse que não dá pra especificar todo um software antes de codificar e hoje vou começar a explicar porque.</p>
<h3>Conteúdo<span class="hx:absolute hx:-mt-20" id="conteúdo"></span>
    <a href="#conte%c3%bado" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ul>
<li>00:00 - Intro</li>
<li>01:47 - Introduction to Algorithms</li>
<li>04:31 - The Art of Computer Programming</li>
<li>08:57 - Compilers</li>
<li>11:32 - The Design and Evolution of C++</li>
<li>12:56 - Object Oriented Analysis and Design</li>
<li>14:43 - The Unified Software Development Process</li>
<li>18:21 - UML Distilled</li>
<li>19:05 - Refactoring</li>
<li>19:33 - Agile</li>
<li>23:49 - Extreme Programming Explained</li>
<li>27:32 - Clean Code</li>
<li>28:24 - The Clean Coder</li>
<li>28:54 - The Pragmatic Programmer</li>
<li>30:33 - Design Patterns</li>
<li>33:02 - Patterns of Enterprise Application Patterns</li>
<li>33:36 - Domain Driven Design</li>
<li>35:10 - The Lean Startup</li>
<li>36:59 - The Mythical Man-Month</li>
</ul>
<h2>SCRIPT<span class="hx:absolute hx:-mt-20" id="script"></span>
    <a href="#script" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Olá pessoal, Fabio Akita</p>
<p>Desde que abri o canal, uma das perguntas mais frequentes, tipo que eu recebo no mínimo uma vez por semana é sobre quais cursos eu recomendo pra quem tá começando. E como eu já disse em vários videos: eu não recomendo nenhum, e na prática tanto faz qual. Nenhum curso vai ser completo, eles servem só pra ter dar um empurrão, mas nunca vão te ensinar tudo de qualquer assunto. A segunda pergunta que mais recebo complementa a primeira que é quais livros eu recomendo.</p>
<p>Muito do que você não vai aprender via cursos ou tutoriais está em livros. E não ache que dá pra pegar essa lista e sair lendo tudo de uma vez. Boa parte deles você vai lendo aos poucos ao longo dos seus primeiros 10 anos de carreira, porque você ainda não tem nem o conhecimento e nem a experiência pra entender de fato o que estão tentando te dizer.</p>
<p>Hoje vou listar alguns livros que eu pessoalmente acho importantes. Não é uma lista nem completa e nem definitiva, são livros que eu fui usando ao longo dos anos e que acho que podem te ajudar. E vou apresentar mais ou menos na ordem que conheci eles, cronologicamente, porque faz diferença quando eles foram lançados e em qual contexto. Prestem atenção ao contexto que vou falar mais do que na lista em si.</p>
<p>(&hellip;)</p>
<p>Vamos lá. Nenhum livro é obrigatório. Então não saiam por aí dizendo pros outros que o Akita falou então é pra ler. Os livros que vou falar hoje eu não li tudo de uma vez só, muitos nem li inteiro, e vim acumulando ao longo dos primeiros 10 a 15 anos da minha carreira, durante e depois da faculdade.</p>
<p>Ninguém vai conseguir ler e principalmente entender esses livros numa só leitura. Isso não é literatura, são livros de aprendizado e referência. Alguns temas dentro desses livros você só vai entender de verdade depois que passar por projetos reais e só daí vai vir o &ldquo;ahhhh, era isso que o livro queria dizer&rdquo;, aquele momento &ldquo;ahá&rdquo;.</p>
<p>Isso dito, se você assiste meu canal já deve imaginar que minha primeira recomendação é o livro do Cormen de Introdução a Algoritmos. Eu tenho esta terceira edição, não sei se tem mais novo, mas não importa. O maior problema de começar estudando e usando frameworks e bibliotecas pré-prontas é que elas evitam que você precise saber como são feitos, porque já vem tudo pré-pronto e escondido pra só usar.</p>
<p>Eu falei disso em videos anteriores e até mostrei, mas se usa uma lista ou collection em Javascript, você não tem idéia se por baixo tá implementado uma lista ligada, ou uma árvore Red Black ou o que. Você só adiciona elementos, remove elementos, manda ordenar e pára por aí. E isso vale pra qualquer outra coisa funcionalidade. Você usa uma biblioteca de caching do seu framework favorito, mas como é implementado? É uma fila simples? É uma fila circular? É uma árvore B-Tree? Que tipo de hashing ele usa? Pra você tanto faz, você só empilha e desempilha elementos e deixa o framework cuidar de tudo pra você.</p>
<p>Então toda vez que usa listas, manipula strings, usa threads ou fibers, caching e tudo mais, só confia que o framework sabe o que tá fazendo e não se preocupa. E isso é ok pra 80% dos casos, por isso que muito iniciante consegue ir até longe em alguns projetos sem nunca ter lido um único livro sobre algoritmos e estruturas de dados. Esse é o nível de um junior. Porém um sênior precisa lidar com problemas diferentes.</p>
<p>Otimização de performance, otimização de carga, reorganização e refatoração do código pra ser ao mesmo tempo mais fácil de dar manutenção e também mais performático, diminuir tempo de latência, diminuir uso de memória por requisição, resolver conflitos de versões de bibliotecas externas, fechar buracos de segurança e mais. E pra isso, você precisa saber como essas bibliotecas e frameworks funcionam por baixo, e pra isso, precisa da fundação, que começa em algoritmos e estruturas de dados.</p>
<p>Um livro como do Cormen não é completo. Ele fala de bastante coisa que você deveria saber, mas nenhum livro nunca vai ter tudo. E antes que vocês perguntem nos comentários ou fiquem me mandando DMs, não, não precisa ser o livro do Cormen. Eu mesmo não usei ele na faculdade. Eu aprendi o básico com um muito mais simples, este do Niklaus Wirth. Olha como é menor.</p>
<p>Diferente do Cormen, o livro do Wirth sequer entra no assunto de grafos, por exemplo. Além disso o Wirth escreveu o livro dele em 1986, já o Cormen e seus co-autores escreveram o deles em 2009. Por isso, no livro mais novo tem assuntos mais modernos, como multithreading, que ainda era um assunto que engatinhava nos anos 80.</p>
<p>Se você acha que precisa ter o livro mais completo de todos, ele não existe mas o mais próximo não é um livro, mas uma coleção de livros, do lendário Donald Knuth, o famoso The Art of Computer Programming, o magnum opus da ciência da computação que ele começou a escrever em 1962 e até hoje não terminou. Eu já falei dele em outro video mas os livros que eu tenho são do 1 ao 3 mais o 4A. Segundo a Wikipedia ele tá escrevendo os fascículos 5 e 6 que são os primeiros dois terços do volume 4B.</p>
<p>E quanto ainda falta pra acabar? Bom, depois do 4B ainda vai ter os volumes 4C e 4D e depois os volumes 5, 6 e 7. Ou seja, o que eu tenho aqui ainda não é nem metade do que seria a obra completa. Essa coleção é o Game of Thrones da computação, e o Knuth é o George R R Martin da nossa área. Todos cruzando os dedos pra ele conseguir terminar tudo. Os livros do Wirth e do Cormen eu diria que são um resumão do que seria os livros de 1 a 4D do Knuth.</p>
<p>Ou seja, os temas dos primeiros 7 volumes do Knuth, que incluem os volumes 4B a 4D que ele ainda não escreveu são o que você encontra no sillabus dos primeiros anos de um curso de ciência da computação. Começa com coisas como matemática básica, números, potências, logaritmos, teoria dos números, permutações, fatoriais, coeficientes binomiais, ou seja, não só o assunto de algoritmos mas temas de matemática que você aprende nos primeiros 2 anos de ciências da computação em matérias como Álgebra, Estatística e probabilidade.</p>
<p>No primeiro volume do Knuth você tem coisas básicas como pilhas, filas, listas ligadas, listas circulares, arrays, árvores binárias, que foram assuntos que eu detalhei alguns videos atrás. Por isso o primeiro volume se chama Algoritmos Fundamentais. Já o segundo volume complica um pouco mais. Ele se chama Algoritmos Seminuméricos e logo de cara o primeiro assunto no livro é definir números aleatórios.</p>
<p>Fazendo uma tangente, números aleatórios gerados por computador não são puramente aleatórios, são pseudo-aleatórios. Em qualquer linguagem moderna de programação você só usa uma função como Random e esquece, mas nesse livro você pode estudar como isso funciona. E nos capítulos seguintes ele vai discorrer sobre sistemas posicionais de números como aritmética de ponto flutuante, que foi outro assunto que já expliquei alguns videos atrás. E continua em assuntos como aritmética racional, aritmética polinomial.</p>
<p>E sim, essa coleção inteira é bem pesada em notação matemática. Se você não tá acostumado é absolutamente intimidador. Entendida toda a base matemática fundamental, só no volume 3, que é chamado de Ordenação e Procuram, é que vamos finalmente encontrar os algoritmos de ordenação como inserção, seleção e procura com temas como pesquisa binária e árvores balanceadas que eu também já mostrei alguns videos atrás.</p>
<p>Finalmente chegamos ao volume 4A que é chamado de Algoritmos de Combinatória Parte 1 que explica o básico de álgebra booleana, truques e técnicas de operações bitwise, diagramas de decisão binária e geração de todas as possibilidades onde entramos no assunto de n-tuplas, permutações, combinações, partições, conjuntos e muito mais. E isso é parte 1 porque o tema de Algoritmos de Combinatória vai se esticar nos próximos volumes ainda não escritos, do 4B ao 4D.</p>
<p>Só esses 4 volumes somam quase 3 mil páginas. Pra colocar em perspectiva, o livro do Cormen é menos da metade disso. Mas se prestou atenção vai notar que os livros do Knuth cobrem mais assuntos, em particular a base matemática. Livros mais focados só em algoritmos e estruturas de dados, como do Cormen, se preocupam menos com as provas matemáticas e mais em como cada elemento é implementado e funciona. Eu diria que é mais prático pra gente. Você só vai realmente ler página a página do Knuth se for se especializar em matemática aplicada ou algo assim.</p>
<p>Mas pra assuntos específicos, vale como referência se quiser descer a fundo. Por exemplo, como realmente números aleatórios são matematicamente definidos? Eu repito, a grande maioria de nós não tem o vocabulário de matemática teórica suficiente pra realmente conseguir absorver tudo do Knuth, por isso qualquer coisa perto do livro do Cormen é mais prático. Mesmo o Cormen é um pouco pesado em matemática, então qualquer livro de algoritmos e estruturas de dados é suficiente.</p>
<p>Mas e os livros de 5 a 7 que o Knuth ainda não escreveu? Os títulos parecem que vão ser Algoritmos Sintáticos, teoria de linguagens livres de contexto e técnicas de compiladores. Linguagens livres de contexto você vai cair no trabalho mais importante do Noam Chomsky - e na minha opinião, a única coisa que você precisa ler dele. Enfim, na realidade já existem livros que cobrem esses assuntos. Se você fez ciência da computação já sabe. Essa é minha segunda recomendação: o famoso livro do dragão, o Compiladores - Princípios, Técnicas e Ferramentas, do Aho, Ullman e outros, publicado em 1986.</p>
<p>Eu já falei em outros episódios sobre compiladores como GCC, e principalmente sobre uma das tecnologias mais importantes deste século: o LLVM, que se você pelo menos acompanha artigos técnicos, já ouviu falar diversas vezes. Eu explico sobre LLVM no episódio sobre a Apple e recomendo que assistam pra entender o contexto, mas é graças a LLVM que você tem linguagens como Swift, Rust, Crystal, Julia, linguagens de shaders pra GPU e muito mais. E pra entender LLVM você precisa entender compiladores e realmente como linguagens de programação são criadas.</p>
<p>Na prática, a menos que você pretenda criar sua própria linguagem do zero, não precisa saber o livro do Dragão de cabo a rabo. É mais pra entender os principais conceitos. Esse livro vai te explicar o que é análise léxica e ferramentas como Lex e você mesmo vai descobrir outras como o GNU Flex depois. Daí vai pular pra análise sintática e ferramentas como o Yacc e outros como o GNU Bison. O livro usa os antigos Lex e Yacc, na minha época da faculdade no meio dos anos 90 era Flex e Bison, mas hoje em dia existem ferramentas mais modernas.</p>
<p>Isso é só pra desenhar a linguagem e criar um parser, mas a partir daí tem que fazer a geração do código binário propriamente dito que passa por um código intermediário, otimizações independentes de máquina, paralelismo em nível de instrução, localidade, análise interprocedural. Se você me perguntar se eu ainda sei essas coisas, não, não lembro nem uma fração mais hoje. Mas os conceitos que guardei me ajudam a avaliar toda vez que uma nova linguagem aparece, eu consigo entender como funciona, o que procurar na linguagem, no compilador, no código final gerado e tudo mais.</p>
<p>Compiladores é um tema que você não deveria tentar aprender tudo de uma só vez. Compensa até começar com algum livro mais simples, curso online ou até um tutorial com ferramentas de mais alto nível que te permitem criar linguagens simples que não necessariamente vão ser performáticas, mas vão ajudar a &ldquo;molhar os dedos&rdquo; no assunto antes de aprofundar nos detalhes que tem no livro do dragão.</p>
<p>De qualquer forma, só faz sentido ter a ambição de escrever a própria linguagem se você estudou um pouco mais a fundo sobre linguagens. E não só &ldquo;ah, eu gosto de parênteses&rdquo; ou &ldquo;ah, eu prefiro não ter ponto e vírgula no fim das linhas&rdquo;. Design de linguagem é muito mais que isso. Um livro que talvez ajude a entender as features de uma linguagem é o The Design and Evolution of C++, do Bjarne Stroustrup que é o pai do C++.</p>
<p>Ele conta um pouco a história de como o Stroustrup se inspirou em C with Classes pra chegar ao C++ e justifica as funcionalidades que criou em cima disso como o gerenciamento de memória, herança múltipla, casting, templates, exceptions, namespaces e tudo mais que forma a base do C++ e depois serviu de inspiração pra implementar muitas das linguagens modernas que você usa como um Java ou C#.</p>
<p>Entender o pulo do C pro C++ pela visão do autor é interessante e também as primeiras interpretações sobre o que é orientação a objetos. C++ é uma linguagem que eu mesmo nunca usei muito profissionalmente, então eu mesmo sou amador, mas acho fascinante entender como se encaixa na história das linguagens de programação. Ela ainda é uma das linguagens mais usadas pra código de sistemas, tudo de mais importante que você usa é escrito com C e C++, seu Javascript é escrito em C++. E isso não vai mudar por um bom tempo ainda.</p>
<p>Daí pulamos um pouco do tema de ciências da computação e vamos um pouco pra engenharia de software. Eu já expliquei a diferença em outro video, mas aproveitando o gancho da orientação a objetos do C++ vale pelo menos mencionar outro livro, o Object Oriented Analysis and Design with Applications do Booch e outros autores.</p>
<p>Orientação a objetos é um tema super longo, bem mais complexo do que você aprende na faculdade e eu não vou detalhar tudo hoje. Dependendo da era que estudar você vai ter interpretações diferentes de muitos conceitos, mas o que muita gente chama de orientação a objetos deriva do vocabulário criado pelo Grady Booch, Ivar Jacobson e Jim Rumbaugh. Cada um deles tinha uma versão de definição de orientação a objetos e eles se juntaram pra compilar seus trabalhos numa obra só. O que se publicou dos anos 90 em diante deriva disso.</p>
<p>Esse livro em particular não é a obra definitiva nem nada disso, mas eu acho interessante que ele tenta justamente definir muito desse vocabulário, definir o que exatamente é uma classe, o que é um objeto, qual é a notação que se deveria usar pra comunicar um modelo de objetos. Algumas partes, em particular a seção 3 do livro que pode estar um pouco defasado porque ele tenta explicar esses conceitos usando exemplos de cinco aplicações que vão de um sistema de navegação de satélite até um sistema de rastreio de férias via web, definido com essa notação de objetos.</p>
<p>Eu digo defasado porque a forma como desenvolvemos aplicações e até a forma como modelamos classes e objetos mudou daquela época até hoje então alguma coisa ficou obsoleta mesmo, não tem jeito, mas muitos dos conceitos ainda valem hoje e principalmente o raciocínio e história por trás de porque eles definiram as coisas daquele jeito. Esse livro em particular vale mais pra capturar um momento da história do que pra ensinar todas as técnicas que você precisa saber.</p>
<p>Esse livro, na real, é opcional e complementar a outro livro mais conhecido que é o The Unified Software Development Process escrito pelos mesmos Los 3 Hermanos, o Jacobson, Booch e Rumbaugh. Ele define a famosa e famigerada notação UML mas, mais importante, define o processo de desenvolvimento de software conhecido como Unified Process ou até hoje o que você conhece como Rational Unified Process ou RUP.</p>
<p>Lembrando, esses livros foram escritos antes de 2001, nos anos 90, portanto antes do Manifesto Ágil, antes de cloud computing, antes de smartphones, antes ainda da primeira bolha da internet, literalmente na infância da Web. Então tudo que você conhece como formas modernas de desenvolvimento de software, que só nasceram nos últimos 20 anos, ainda não existiam nessa época. Mesmo assim, eu ainda acho que vale a pena ler o começo desse livro, porque muitos dos conceitos de engenharia de software que você usa são derivados dessa época.</p>
<p>Em particular, eu já falei em outros episódios que pra mim um bom exemplo de linguagem orientada a objetos, por incrível que pareça é o Erlang, em particular o Elixir. Muita gente pensa em Elixir como uma linguagem funcional, mas pra mim é o contrário. Ele é primeiro uma linguagem orientada a objetos que por acaso tem aspectos funcionais. Eu argumentaria que Elixir e Erlang são mais orientados a objetos do que Java, que muita gente ainda pensa como a referência em objetos. Se você não entendeu isso, ainda precisa estudar mais.</p>
<p>Um dos argumentos sobre Erlang é que logo no prefácio desse livro, eles contam sobre o case da Ericsson, que é a inspiração do Unified Process. Se você não sabe, o “ER” de Erlang é de Ericsson. Os autores argumentam que o sistema de telecomunicações deles era tão bom porque modelaram o sistema inteiro como um conjunto de blocos interconectados, o que em UML se chamaria de componentes ou sub-sistemas. E eles foram montando blocos de baixo nível e subindo pra sub-sistemas de alto nível pra tornar o sistema mais fácil de gerenciar e foram encontrando esses blocos trabalhando pelos casos de tráfego anteriores - o que hoje se chamaria em UML de &ldquo;casos de uso&rdquo;.</p>
<p>O caso da Ericsson é relevante pro assunto de orientação a objetos porque quem trabalhou lá foi justamente um dos co-autores desse livro, o Jacobson, que saiu em 1987 e fundou a empresa Objectory e nos anos seguintes ele e alguns colaboradores desenvolveram um processo chamado Objectory também pra servir pra mais casos além de telecomunicações, e foi aí que coisas como &ldquo;casos de uso&rdquo; ganharam esse nome.</p>
<p>Alguns anos depois, em 1995 a empresa Rational Software Corporation comprou a Objectory e eles trabalharam em juntar os dois processos que tinham e chegaram primeiro no Rational Objectory Process. Depois disso que o Booch, Rumbaugh e Jacobson colaboraram pra criar o Unified Modeling Language, o UML, pra ter uma linguagem visual pra comunicar as idéias sobre objetos e finalmente chegaram no Unified Process ou Rational Unified Process, que é o RUP, que muitos que fizeram engenharia de software devem ter estudado.</p>
<p>Em 2021 raramente você vai ver alguma empresa usando fortemente UML e RUP em projetos. Pelo menos eu espero que não. Talvez em empresas antiquadas e altamente burocráticas, mas em tech startups é bem raro encontrar. Mas muito do vocabulário e notações que usamos até em rascunhos numa lousa são derivados do UML. Muito da engenharia de software moderna ainda usa os nomes originais, como &ldquo;casos de uso&rdquo; por exemplo, ou diagrama de componentes. O que eles chamavam de sub-sistemas você poderia chamar hoje de micro-serviços e assim vai.</p>
<p>Se quiser aprender esse vocabulário sem perder muito tempo no detalhamento do processo em si, que ninguém mais usa como antigamente, você pode pular direto pra outro livro bem menor, de menos de 200 páginas, chamado UML Distilled do Martin Fowler, que é basicamente um resumão de UML e RUP. Ele tem só o que o Fowler acha que é mais relevante alguém saber, é quase um cheat sheet sobre UML.</p>
<p>Levou alguns anos, até demais na minha opinião, pras pessoas entenderem que seguir algo como um RUP ao pé da letra era absolutamente burocrático e improdutivo. A gente tava mais preocupado em rastrear, gerenciar e aprovar artefatos, como diagramas, do que com o código em si. É uma das grandes críticas em relação ao campo da orientação a objetos em geral.</p>
<p>Falando em Martin Fowler, ele foi um dos escritores mais prolixos e influentes do fim dos anos 90 até pelo menos o meio dos anos 2000 e um dos seus livros mais importantes parece uma reação contra o que um RUP representa. Esse livro obviamente é o Refactoring, publicado em 1999. E hoje em dia todo mundo fala em refatorar, refatorar, mas quantos de vocês conseguem definir o que é refatorar? Qual a diferença entre refatorar e reescrever?</p>
<p>Nas palavras do próprio Fowler, refatorar é o processo de mudar um software de tal maneira que isso não altere o comportamento externo do código e mesmo assim melhore a estrutura interna. É uma forma &ldquo;disciplinada&rdquo; de limpar código que minimiza as chances de introduzir bugs. Em essência, quando você refatora, está melhorando o design do código depois que ele foi escrito. Muita gente falando “refatoração” na verdade está querendo dizer “reescrever”, que não é um processo disciplinado de melhoria sem mudar comportamento, é literalmente jogar fora e escrever de novo de outro jeito, com outro comportamento, e não garante nenhuma melhoria.</p>
<p>E não é à toa que o Martin, junto com outros autores como Kent Beck, são signatários do Manifesto Ágil. Em metodologias antigas de engenharia de software, onde o RUP se inclui, a ideia principal é primeiro criar o design inteiro do software, por exemplo desenhando com diagramas com UML. E só depois que o design estiver perfeito que se começa a escrever o código. Ou até mesmo daria pra gerar automaticamente esse código a partir dos diagramas. Eles consideram design e codificação como duas etapas separadas. Mesmo tendo coisas como iteração no processo, as etapas em si ainda são conceitualmente separadas. Muitas empresas tentaram criar ferramentas que partiam dos diagramas de classes e tudo mais de UML e geravam código em Java da vida.</p>
<p>Essa ideia nunca funcionou direito e a gente foi entendendo melhor porque depois da virada do século, depois que começamos a ideia de agilidade. A premissa errada é achar que é possível criar um design perfeito em papel primeiro e depois o código seria só um reflexo direto desse design. Na realidade o código &ldquo;é&rdquo; o design e ele nunca vai estar perfeito, muito menos na primeira vez. Daí vem a ideia de fazer o primeiro código que funciona primeiro, que provavelmente vai ser um código ruim, e só depois, disciplinadamente, refatorar esse código até termos uma estrutura que seja livre de bugs e de mais fácil manutenção.</p>
<p>Aliás, vale aproveitar pra dizer que muita gente pensa que primeiro nasceu o Manifesto Ágil em 2001 e só depois começamos a entender o que são técnicas ágeis, mas é o contrário. Primeiro os signatários do manifesto passaram anos praticando, formulando as técnicas e documentando, durante os anos 80 e 90 principalmente, e só depois que isso deu origem ao Manifesto. Essa ordem é importante, porque o Manifesto é só um resuminho de 20 anos de experiência de cada um deles que veio antes.</p>
<p>Na indústria mais tradicional, por décadas sempre se tentou o conceito de design primeiro e código depois. Lá atrás a gente desenhava software com fluxogramas em linguagens procedurais, por exemplo. E isso fazia sentido porque debugar software depois era custoso, difícil, tedioso. As linguagens antigas eram fortran, cobol, algol, Ada ou C. Nenhum programador nos anos 70 e antes tinha um notebook multi-core com gigabytes de RAM. Não, eles tinham que compartilhar um único computador grande com vários outros engenheiros e programar a partir de terminais remotos.</p>
<p>Esses terminais eram lentos, ninguém tinha um VS Code ou Sublime Text da vida. O editor VI original foi criado justamente pra ser super otimizado pra desenhar o mínimo possível na tela e permitir navegar no código com o mínimo de comandos. Porque cada comando navegava numa rede lenta até um computador compartilhado lento que tinha no máximo kilobytes de RAM. Portanto, você gostaria que o código funcionasse de primeira, não era produtivo ficar debugando e &ldquo;refatorando&rdquo; o código depois.</p>
<p>O que aconteceu nos anos 90 até os 2000 é que microcomputadores apareceram e ficaram consideravelmente potentes, internet e rede mais veloz apareceu, e agora era factível você rodar um sistema inteiro no seu computador pessoal antes de rodar no servidor da empresa. Fazer o design antecipadamente era crucial nas décadas de 60 a 80, mas depois disso a tecnologia avançou o suficiente pra gente conseguir fazer código ruim primeiro e refatorar depois pra ter código bom, então o design e o código passaram a ser um processo orgânico de melhoria contínua. Isso é uma interpretação minha, mas eu diria que “Agile” marca quando separávamos design e código em etapas distintas pra serem unidos em design emergente.</p>
<p>Falando em processos ágeis, se tiver só um livro que você queira ler, que seja o Extreme Programming Explained, do Kent Beck, também de 1999. Veja que em 1999 e 2000 que começou a aparecer mais livros sobre esse novo jeito de programar que vinha sendo praticado fazia mais de 10 anos, que culminaria com o manifesto ágil em 2001 e muito do que você considera técnicas de engenharia de software modernas como pair programming, test driven development, continuous integration, refactoring, small releases, nascem nele.</p>
<p>Engenharia de software é um campo em constante mudança. Dependendo de que ano é a literatura que você está estudando, vai cair nos RUP da vida ou vai cair em derivados de Extreme Programming. A ideia não é dizer que os conceitos dos anos 90 estavam errados. Eles faziam sentido pras circunstâncias da época e vale a pena entender porque.</p>
<p>Vocês podem ver que alguns livros e temas envelhecem melhor que outros. Uma coisa que me ocorreu gravando esse video é que se você prestou atenção, note que livros de ciência da computação tendem a envelhecer melhor que livros de engenharia de software. Livros de ciência da computação de 30 anos atrás ainda se aproveitam hoje, mas livros de engenharia de software de 30 anos atrás, estão obsoletos.</p>
<p>Até hoje ainda não temos &ldquo;o&rdquo; melhor jeito de escrever software, estamos constantemente mudando os processos de como transformar idéias em código. Mas as peças fundamentais que usamos pra construir essas idéias ainda continuam válidas. Na ciência da computação o conhecimento meio que vai se estendendo mas não jogando muita coisa fora pelo caminho.</p>
<p>Uma parte disso é porque as teorias matemáticas que embasam coisas como algoritmos, uma vez provadas, variam muito pouco na implementação. É o trabalho de caras como Knuth. Uma árvore balanceada, seja feita em C ou seja em Kotlin, continua sendo uma árvore balanceada. Linguagens diferentes mas as características continuam as mesmas. É um dos motivos de porque linguagens funcionais ganharam algum destaque nos últimos anos. Muitos tentam trazer esse rigor matemático, como de lambda calculus, pros processos de como escrever código. Mas escrever código não é uma ciência exata, é um processo aberto à interpretação.</p>
<p>O problema é que código não é só rápido, ou seguro. Em engenharia a gente tenta buscar várias características como mantenabilidade, flexibilidade, portabilidade, reusabilidade, legibilidade, testabilidade, segurança e assim por diante. Você pode escrever o código mais seguro possível, mas vai prejudicar a flexibilidade e reusabilidade, e assim por diante. O desafio de um programador é balancear essas características, e isso é difícil porque depende de quais problemas você precisa realmente resolver com esse código. E pior, os requerimentos desse código mudam conforme o software é usado.</p>
<p>Num primeiro momento a prioridade pode ser eficiência, mas depois de um tempo a prioridade passa a ser segurança, depois passa a ser mantenabilidade. Então o código precisa ser modificado ao longo do tempo, o design desse código vai mudando conforme as necessidades vão mudando. Por isso, nenhum código está 100% pronto e congelado pra sempre. E repetindo, por isso é quase impossível fazer um design perfeito antes do código.</p>
<p>Muito amador ainda acha que código, se rodar, tá ótimo, não importa se tá sujo, com nomenclaturas toscas, com alta complexidade. &ldquo;Ah, roda, então foda-se&rdquo;. Código que roda, mas é sujo, com baixa mantenabilidade, é lixo, pode jogar fora. Não adianta nada rodar se amanhã você precisar estender, consertar, reusar. Daí mais atrapalha que ajuda. É lixo. Não basta rodar,  precisa estar limpo o suficiente pra quando outro programador for reusar, não vai sofrer.</p>
<p>Se você quiser um livro mais estruturado com a melhor forma de escrever código e como se comportar como um bom profissional, o melhor livro pra começar é de outro agilista, o controverso Robert Martin, vulgo Uncle Bob. Ele é outro escritor prolixo e seu livro mais conhecido é sem dúvida o Clean Code, ou Código Limpo. E o conteúdo é parecido com o Code Complete do McConnell mas bem mais atual.</p>
<p>Ele toca em coisas tipo, como criar nomes de variáveis, funções que sejam fáceis de entender. E segue falando de todas as boas práticas que deveriam ser óbvios pra todo profissional: escrever funções com corpo curto, código bem formatado e legível, como escrever código que lida com exceções, como criar fronteiras claras entre diferentes módulos, como fazer testes unitários, um pouco sobre organização de classes em linguagens orientadas a objetos, noções de design emergente, ou seja, design que emerge à medida que você escreve código, testa e refatora.</p>
<p>Eu diria que se você quer ser um bom profissional, no mínimo tem que escrever código limpo como o Bob Martin ensina E falando em profissionalismo, um livro mais recente dele que lida com temas mais sobre como trabalhar em equipe, como gerenciar tempo, como fazer estimativas e coisas assim é o Clean Coder, ou Programador Limpo. Esse eu mesmo não cheguei a ler, mas pelo pouco que vi, acho que pode ser útil pra quem tá começando na profissão e ainda não sabe exatamente quais são suas responsabilidades perante seus colegas e projetos.</p>
<p>Outro livro com tema similar é um grande clássico que fez 20 anos recentemente, escrito por outros dois agilistas, Dave Thomas e Andy Hunt, o famoso The Pragmatic Programmer. Se o Clean Code e o Clean Coder do Bob Martin são meio que um manifesto do profissional de código, o The Pragmatic Programmer é uma mistura dos dois e tenta explicar a filosofia de um programador pragmático. Eles discorrem sobre como lidar com resolução de problemas de software, tocam em assuntos de agilidade de novo como testes, como escrever código limpo.</p>
<p>Se você assistiu meu episódio intitulado Esqueça Metodologias Ágeis, já sabe que estamos numa era pós-Agile. Os conceitos e técnicas originais de agilidade são simples, mas diversas empresas e consultorias sequestraram o termo &ldquo;ágil&rdquo; e inventaram um monte de metodologias e ferramentas burocráticas que nos levaram de volta à época do RUP e UML.</p>
<p>Se você quer saber o que é realmente ser Ágil, deve ler os autores originais e não trabalhos derivados. Em particular Martin Fowler, Kent Beck, Bob Martin, Dave Thomas e Andy Hunt, que são todos os livros que eu recomendei até agora. Leia os livros deles e você vai estar meio caminho andado pra conseguir distinguir ágil de verdade das bullshitagens de coach de consultoria ágil por aí.</p>
<p>Muitos já me pediram pra falar sobre alguns desses temas, como testes. Ainda não sei se vou fazer um video disso porque é um tema tão bem documentado já que você só não aprende se fizer esforço pra ignorar. E repetindo: leia sobre assuntos de agilidade a partir dos autores originais. Quer saber sobre testes? Comece com Kent Beck e seus livros de Extreme Programming, não tem que inventar moda.</p>
<p>Tem três outros livros que vale mencionar. Uma coisa que vocês só vão realmente entender lendo e escrevendo muito código de verdade é sobre a diferença entre design e código e como design emerge a partir do código e de seu uso, como eu já disse. Num primeiro momento, se está começando os estudos, não pense que vai conseguir pré-planejar todos os aspectos de um software antes de escrever uma linha de código. Não vai. E os próximos livros podem confundir vocês nisso.</p>
<p>O primeiro é o clássico Design Patterns, escrito pelo Erich Gamma e sua gangue dos quatro. No tema de achar que dá pra planejar em detalhes antes de codificar, esse é o primeiro livro mal interpretado. Cansei de ver amador com esse livro embaixo do braço querendo pagar de arquiteto e falando bullshitagens como &ldquo;vamos fazer esse módulo usando alguns decorators pra montar um adapter que vai sair de um factory que vai ser um singleton derivado de um command de um chain of responsability suportado por um observer&rdquo;. Bleh.</p>
<p>Eu já expliquei isso no fim do meu video sobre como aprendi inglês, mas vou repetir. A tradução do título desse livro em português é &ldquo;Padrões de Design&rdquo;. Dá a impressão que esse livro tem todos os padrões, no sentido de as melhores peças, ou as peças definitivas, pra se fazer design de software. O problema é que a palavra &ldquo;padrão&rdquo; em português pode ser traduzida em 3 palavras diferentes em inglês, standard, default ou pattern.</p>
<p>Muita gente pensa que &ldquo;padrão&rdquo; é o standard. E standard é como você pensou mesmo: um padrão oficial, uma definição definitiva sobre alguma coisa. Mas estamos falando de &ldquo;pattern&rdquo;, e pattern é só alguma coisa que se repete muito, independente se é boa ou ruim e definitivamente não é o &ldquo;padrão definitivo&rdquo;. O livro de Design Patterns é um catálogo de patterns, de repetições que os autores viram muito em diversos projetos, e simplesmente deram um nome pra eles. Só isso, nada mais, nada menos.</p>
<p>Esse livro foi publicado em 1994, um ano antes de entrar na faculdade. E eu só fui conhecer ele alguns anos depois, lá por 1998. Nesse momento eu já tava programando faz alguns anos e quando vi o livro, em inglês, foi exatamente o que pensei. &ldquo;Oras, o livro só dá nome pra coisa que já vi várias vezes&rdquo;. Por exemplo, quem mexia com emuladores naturalmente reconhecia o Design Pattern Adapter. Toda vez que troco a biblioteca opengl do game por um directx é meio que um Adapter.</p>
<p>Design Patterns é um catálogo, e não um manual de como fazer design. Se você já programou tempo suficiente, só vai descobrir que alguns trechos de código que já viu várias vezes por acaso tem nomes, como Singletons, ou Visitors. Esse livro é útil somente pra nos dar um vocabulário comum pra ficar mais fácil pra dois programadores comunicarem um conceito com um nome comum. E ele nem é o catálogo mais completo, existem diversos outros patterns que não estão nesse livro. Vide livros como Patterns of Enterprise Applications Architecture do próprio Martin Fowler.</p>
<p>Falando em arquitetura, outro livro que alguns podem usar errado pensando que é um manual de instruções é o Domain Driven Design do Eric Evans, publicado em 2003. Nas palavras do Martin Fowler, esse livro descreve uma forma de desenvolvimento de software centrado num modelo de domínio que tem um entendimento rico dos processos e regras desse domínio. Em resumo bem resumido, é mais um livro que orienta em como dar nome pras coisas e como organizar essas coisas.</p>
<p>Assim como Design Patterns, ele nos dá novos vocabulários pra descrever sistemas como Ubiquitous Language, Aggregates, Bounded Contexts e outras classificações, mas enxergando mais o big picture de um sistema em vez de só pequenos componentes. Bounded Contexts em particular é interessante porque descreve um pattern que aparece em muitos sistemas.</p>
<p>Por exemplo, imagine que você tem um sub-sistema que tem contexto de Vendas e outro sub-sistema com contexto de Suporte. No de vendas você tem entidades como Vendedor, Oportunidade. No de suporte tem entidades como ticket, defeitos. Mas no bound, na fronteira entre os dois sub-sistemas ele compartilham entidades como o usuário ou o produto.</p>
<p>Começa a ficar difícil de lidar com sistemas que crescem se num sub-sistema você chama usuário de cliente e no outro sub-sistema você chama de comprador, por exemplo. Parte da idéia de DDD é criar um linguagem ubíquita, comum entre desenvolvedores e usuários. Enfim, como eu disse antes, ele se preocupa muito com a arte de dar bons nomes pras coisas. Não é à toa que a gente brinca que uma das coisas mais difíceis da computação é dar nomes pras coisas.</p>
<p>O terceiro e último livro, por incrível que pareça acho que é a cola que une todos os livros de engenharia que falei até aqui. É o famigerado The Lean Startup, do Eric Ries, publicado em 2011. Foi exatamente quando começou a atual bolha de tech startups e esse livro apareceu na hora certa pra se tornar meio que a bíblia das novas tech startups. É um livro meio que de empreendedorismo, é superficial, e por causa disso muita gente interpreta do jeito errado. Próxima pessoa que falar que “validou” a idéia fazendo pesquisa com uma dúzia de pessoas, eu juro que eu chuto.</p>
<p>De qualquer forma, ele fala algumas coisas que são relevantes pra engenharia de software. Você pode estudar orientação a objetos, processos de desenvolvimento de software, metodologias ágeis, como fazer código limpo, como modelar sistemas com DDD, mas se você não entende o mínimo de negócios, seu software sempre vai ser ruim. Porque o melhor software é aquele que resolve problemas do mundo real, e não do mundo teórico.</p>
<p>Um conceito importante que o The Lean Startup ajudou a popularizar foi o de Minimum Viable Product ou MVP, ou simplesmente Protótipo. A ideia ultrapassada, vinda de processos monumentais como RUP da vida, é de tentar fazer o design do melhor software possível, o mais complicado, com mais opções, com maior número de funcionalidades possíveis. Eu não sei se alguém aqui já passou por isso, mas eu já tive que avaliar calhamaços, literalmente pilhas de quinhentas páginas de especificações e diagramas de UML.</p>
<p>Nunca vi um design assim no papel que desse pra traduzir em software, sempre tinha um monte de buracos pelo caminho. É impossível desenhar 100% de um software antes de construir, é sempre mais prático começar com um design mínimo, construir, aprender com os erros e ir estendendo e refatorando, ou seja, fazendo o design emergir do software.</p>
<p>Casos que já vi várias vezes, seja a partir de um software legado já existente ou um MVP, povo sempre fica com a ideia de &ldquo;agora sim, eu já sei como que o design de verdade deveria ser&rdquo; e aí segue tentando desenhar a versão 2.0 &ldquo;perfeita&rdquo;, e cai na armadilha do &ldquo;Segundo Sistema&rdquo; que nosso amigo Fred Brooks já avisou no livro The Mythical Man-Month, que eu já fiz um video inteiro a respeito meses atrás. Dêem uma olhada.</p>
<p>É muito difícil fazer uma lista com TODOS os livros que eu acho que todo mundo deveria ler. Acho que uma lista assim seria impossível. Dependendo da sua escolha de carreira ou mesmo dos seus gostos, alguns são mais interessantes que outros. Essa lista é a que pessoalmente acho que é relevante, embora incompleta, pra maioria. Minha recomendação é sempre ir atrás dos autores originais de um determinado tema, autores que têm mais de décadas de experiência em projetos reconhecidos. Evitar ao máximo derivativos que costumam simplificar demais ou até alterar o que o original dizia.</p>
<p>Mas como eu disse antes, em particular livros de engenharia de software tendem a envelhecer mais rápido do que livros técnicos de ciências da computação. Mas ambos os temas são importantes pra qualquer programador. De qualquer forma, se ficaram com dúvidas mande nos comentários abaixo, se curtiram o video deixem um joinha, não deixem de assinar o canal e compartilhar com seus amigos. A gente se vê, até mais!</p>
<p>06:52 - o que vem depois hello world
09:50 - Apple GPL</p>
]]></content:encoded><category>arquitetura-de-software</category><category>engenharia-de-software</category><category>aprendizado</category><category>akitando</category></item><item><title>[Akitando] #104 - RANT: Empreendendo com Software do JEITO ERRADO!</title><link>https://akitaonrails.github.io/2021/09/28/akitando-104-rant-empreendendo-com-software-do-jeito-errado/</link><guid isPermaLink="true">https://akitaonrails.github.io/2021/09/28/akitando-104-rant-empreendendo-com-software-do-jeito-errado/</guid><pubDate>Tue, 28 Sep 2021 11:20:00 -0300</pubDate><description>&lt;div class="embed-container"&gt;
&lt;iframe
src="https://www.youtube.com/embed/NuIOO5VWmXc"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2&gt;DESCRIÇÃO&lt;span class="hx:absolute hx:-mt-20" id="descrição"&gt;&lt;/span&gt;
&lt;a href="#descri%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Depois de 2+ décadas atendendo centenas de projetos, quero resumir alguns dos casos toscos que eu já vi no caso de pequenos empreendedores amadores não-técnicos e muitas das coisas que eles pensam errado e fazem errado com projetos de software.&lt;/p&gt;
&lt;p&gt;Assista pra não cometer os mesmos erros!&lt;/p&gt;
&lt;p&gt;Se gostou da proposta do video e quiser se candidatar, estamos contratando: &lt;a href="mailto:become@codeminer42.com"&gt;become@codeminer42.com&lt;/a&gt;&lt;/p&gt;</description><content:encoded><![CDATA[

<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/NuIOO5VWmXc"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<h2>DESCRIÇÃO<span class="hx:absolute hx:-mt-20" id="descrição"></span>
    <a href="#descri%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Depois de 2+ décadas atendendo centenas de projetos, quero resumir alguns dos casos toscos que eu já vi no caso de pequenos empreendedores amadores não-técnicos e muitas das coisas que eles pensam errado e fazem errado com projetos de software.</p>
<p>Assista pra não cometer os mesmos erros!</p>
<p>Se gostou da proposta do video e quiser se candidatar, estamos contratando: <a href="mailto:become@codeminer42.com">become@codeminer42.com</a></p>
<p>Conteúdo:</p>
<ul>
<li>00:00 - Intro</li>
<li>01:27 - Disclaimer</li>
<li>02:02 - Sua idéia NÃO é original</li>
<li>03:00 - Zero Experiência</li>
<li>04:04 - Sem co-fundador técnico</li>
<li>05:40 - Sua empresa sequestrada!</li>
<li>07:30 - Não reinvente a roda!</li>
<li>07:54 - Especificações que não valem NADA!</li>
<li>10:25 - Escopo Fechado NÃO FUNCIONA!</li>
<li>11:53 - Por que o que você imaginou vai desandar</li>
<li>15:24 - Software NUNCA acaba!</li>
<li>15:52 - Você PRECISA de Júniors!</li>
<li>18:07 - Economia PORCA</li>
<li>18:33 - NUNCA TERCEIRIZE TUDO!</li>
<li>20:10 - Indianos e Príncipes Nigerianos</li>
<li>21:01 - Dá pra fazer igual empresa X??</li>
<li>22:06 - NDA é lixo</li>
<li>23:05 - Jurídicos AMADORES</li>
<li>23:35 - Licitações: LIXO</li>
<li>24:45 - E o que você REALMENTE deveria fazer?</li>
<li>26:17 - Fechamento</li>
</ul>
<h2>SCRIPT<span class="hx:absolute hx:-mt-20" id="script"></span>
    <a href="#script" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Olá pessoal, Fabio Akita</p>
<p>Andei um pouco sumido nas últimas semanas porque a última série me cansou um pouco, acho que exagerei e detalhei demais um tema só e isso me deixou bem entediado. Então vou retornar um pouco mais light antes de pegar mais temas técnicos. Hoje quero mudar de marcha e falar um pouco sobre projetos.</p>
<p>Por décadas eu trabalhei em projetos de software e até hoje  vejo que muita gente ainda pensa errado, especialmente os amadores, mas até gente que diz ter experiência comete alguns desses erros. Estando do lado da empresa que realiza os projetos, quero explicar que tipo de coisas que aparecem na minha porta e que eu quero chutar a mesa quando escuto. Obviamente não dá pra cobrir tudo, mas vou dar alguns exemplos pra que vocês não cometam os mesmos erros no futuro.</p>
<p>Uma coisa que você vai ouvir sempre é &ldquo;depende&rdquo;. Quanto custa? Depende. Quanto tempo leva? Depende. O que eu vou precisar fazer? Depende. E depende porque como já disse no video sobre The Mythical Man-Month, não existe Bala de Prata. Não existem soluções one-size-fits-all, ou seja um tamanho que cabe em qualquer problema. Todo projeto é sempre caso a caso. Hoje quero focar mais no pequeno empreendedor, microempresa, a startup de primeira viagem, o fundador individual não-técnico que nunca participou de projetos de software antes.</p>
<p>(&hellip;)</p>
<p>Como disclaimer vale dizer eu não estou generalizando dizendo que todo mundo que empreende, começa um projeto do zero faz tudo errado como vou falar agora. Já consigo ver gente nos comentários falando “ah, mas eu não sou assim” ou “ah, mas eu conheço gente que não é assim” e bla bla bla. Foda-se. Óbvio que existem exceções, senão não existiriam casos de sucesso. Mas é um fato que ao longo de quase 30 anos, tendo passado por literalmente centenas de projetos, estatisticamente a grande maioria se encaixa muito no que vou explicar hoje. Se a carapuça servir, não culpem o mensageiro, só isso.</p>
<p>Parte do que vou falar hoje já falei no video dos mitos de startups, mas vou repetir pra reforçar. E a primeira coisa que todo empreendedor de primeira viagem acha, é que teve alguma idéia inédita que vai revolucionar alguma área ou até o mundo - se for mais um megalomaníaco iludido. Deixa eu colocar da maneira mais suave possível: sua idéia não é original e muito menos revolucionária. Entenda: é muito, mas muito raro alguém surgir com uma idéia verdadeiramente inédita e revolucionária. Não importa o que sua mãe diga pra você, sua idéia é medíocre, na melhor das hipóteses.</p>
<p>Se você gosta de alguma área e gastou 10 anos fazendo pesquisa, estudando, criando protótipos, testando de verdade no mercado, voltando pra mesa de projetos e redesenhando, melhorando e investindo e depois desses 10 anos, talvez, talvez, você tenha conseguido chegar numa ideia razoavelmente original. Isso é possível. A pergunta é: você gastou esse tempo e esforço?</p>
<p>A coisa mais tosca que me deixa pasmo toda vez que eu ouço é um recém formado, faz de conta, de medicina, chegando pra mim e falando &ldquo;Akita, vou revolucionar o mercado de hospitais&rdquo;. A primeira pergunta que eu tenho que fazer é &ldquo;filho, quantos anos e em quantos hospitais você já trabalhou?&rdquo; E a resposta sempre é: nenhum, ou muito pouco tempo. E como você acha que vai revolucionar um mercado onde você sequer trabalhou ainda? Simples: não vai. Esquece. “Ah, mas teve o caso daquele outro cara que chegou e revolucionou do nada &hellip; “ - cara, um caso, você tá se baseando na exceção da exceção?</p>
<p>Pra compensar isso, o caso seguinte é quando o tal empreendedor conheceu alguém que já trabalhou os tais 10 anos ou mais na tal área e eles acham que juntos vão mudar o mercado. Ok, justo, é um pouco melhor. Não muito, mas já vi dar certo algumas vezes. Poucas vezes. O problema é que agora querem criar um software pra implementar essa ideia. Quantos anos eles tem de experiência trabalhando em projetos de software? Zero. Chances de dar certo? Perto de zero também.</p>
<p>Eu não consigo entender fundadores não técnicos querendo criar uma empresa de software sem ter outro co-fundador que tenha anos de experiência nessa área. É quem ocuparia o cargo de CTO ou Vice presidente de engenharia ou diretor de tecnologia ou qualquer coisa assim. Alguém que já participou diretamente na codificação de diversos sistemas, de diversos tamanhos, e já esbarrou em todo tipo de problemas, tá calejado.</p>
<p>Entenda, se você quer ser uma tech startup significa que o Core Business, o negócio central, dessa empresa é tecnologia. Alguém de cargo de confiança precisa ser responsável por isso. Isso não é opcional. Não se terceiriza o core business inteiro da sua empresa. E eu digo isso sendo um terceirizador. Eu não quero a responsabilidade de decidir por você, porque eu não sou e nem vou ser seu sócio. Nenhum terceirizado jamais vai ter o mesmo nível de preocupação porque a gente não é stakeholder. Entenda esse conceito: não importa o quanto o vendedor te prometeu que vai ser o melhor relacionamento do mundo. Palavras são só palavras.</p>
<p>Também cansei de ver empreendedores não-técnicos falando que começaram a fazer algum curso online de programação, achando que isso vai fazer alguma diferença. Sério? Você acha que pra fazer sistemas eficientes, robustos, seguros, de fácil manutenção é só gastar algumas míseras semanas assistindo video no YouTube? Não perca seu tempo, não é sua praia, não vai fazer absolutamente nenhuma diferença. Foque nas suas responsabilidades. Ou você já é um engenheiro de carreira com anos de experiência nas costas ou você tem um sócio nesse perfil que confia totalmente. Não inventa moda.</p>
<p>Cansei de ver gente que contratou freelancer pra cuidar de tudo. A senha da Amazon fica com esse freelancer, a conta da organização do GitHub fica com esse freelancer, todos os acessos e permissões mais importantes, que podem desligar sua empresa, estão na mão de alguém que sequer é um funcionário da sua própria empresa. É que nem você ter 1 milhão de reais na sua conta de banco e nem você tem a senha dessa conta, está na mão de um estranho qualquer. Você faria isso?</p>
<p>O que acontece se no final o cara que parecia gente boa se mostra de má índole? Em bom português, você se ferrou. Você foi juvenil, agora vem as consequências. O mínimo do mínimo é que você como dono da empresa ou co-fundador técnico tenha os meios de desligar alguém da empresa e ele não ter acesso às coisas que mantém seu negócio de pé. Se não sabe como fazer isso, nem comece. Nunca dê as chaves da sua casa pra um estranho.</p>
<p>Isso é especialmente mais importante agora que existe a LGPD que é a Lei Geral de Proteção aos Dados. Se um terceiro faz bobagem com seu banco de dados e compromete dados pessoais dos seus usuários é sua empresa e você que são responsáveis. Se você precisa compartilhar parte desses dados com um terceiro, tem que ler a lei pra saber em quais condições e o que é necessário fazer pra não ficar juridicamente exposto. Não adianta dizer &ldquo;ah, eu não sabia&rdquo;. Ignorância das leis não te torna inocente.</p>
<p>Muitos projetos que as pessoas vem pedir são coisas que já existem. Um ecommerce, uma plataforma de ensino, um meio de pagamento ou algo assim. Vamos entender: seu negócio principal é produzir algum produto pra vender? Então seu core business, pelo menos no começo, não é tecnologia, é manufatura e vendas. Não tente construir seu próprio ecommerce, não é sua praia. Faça uma pesquisa, hoje em dia temos dezenas de plataformas pré-prontas que vão fazer praticamente tudo que você precisa de forma melhor do que se você tentar fazer do zero.</p>
<p>Não reinvente a roda, se precisa vender, abra uma conta num Shopify da vida. Lá na frente, quando seus processos de manufatura estiverem azeitados, quando já tiver bom volume de vendas e, principalmente, boa margem de lucros, daí sim, talvez você queira mais controle da tecnologia e vai ter dinheiro pra pesquisar e investir. E acredite, não vai ser barato, então não coloque o carro na frente dos bois.</p>
<p>Digamos que você chegou nesse ponto, ou talvez conseguiu ludibriar algum investidor disposto a colocar dinheiro no seu negócio. De novo, se você não tem um co-fundador técnico com muita experiência - e ênfase aqui em muita experiência, porque um co-fundador técnico recém formado não vai te ajudar em muita coisa. Daí você comete o próximo erro clássico: começa a desenhar como acha que seu sistema perfeito deveria ser.</p>
<p>Normalmente contrata algum designer, sei lá porque, pra sair desenhando telas de mockup. Acho impressionante quando vejo esses trabalhos porque vira um calhamaço de telas e a primeira tonelada de papel é sempre telas de formulários pra se registrar, login, esqueci minha senha e outras bobagens assim. Sério? Todo mundo sabe como um formulário de registro funciona, não precisa detalhar isso.</p>
<p>Mas coisas que deveriam ter sido especificadas e até feito mockup incluem as funcionalidades chatas que ninguém gosta de fazer justamente porque nem sabem que existem e como deveriam funcionar: as partes administrativas, relatórios, integração com backoffice e todos os controles que precisa pro sistema realmente funcionar. Pergunta se alguém que faz mockups lembra de desenhar essas coisas? Raramente! Dão mais atenção pra uma tela de login do que um admin.</p>
<p>Entenda: você, marinheiro de primeira viagem, sempre vai conseguir desenhar o que “acha” que precisa e não o que “realmente” precisa. No papel pode tudo mas sua imaginação não vai conseguir visualizar coisas que você nunca viu, as coisas por trás das telas bonitas. Se for um ecommerce, no final vira um copy e paste das telas de uma Magazine Luiza ou Mercado Livre. Mas se você nunca trabalhou numa plataforma dessas, não tem idéia de como eles funcionam por trás. O tanto de sistema que existe que um usuário jamais vai ver. Logística é um grande exemplo. Você realmente acha que com seus trocados e nenhuma experiência vai fazer uma fração disso? Não vai, então pára de chegar pedindo &ldquo;ahh, dá pra fazer essa funcionalidade igual do MercadoLivre?&rdquo; - claro que dá, se você pagar a mesma coisa que eles investiram, a gente pode tentar fazer.</p>
<p>Acho interessante que a primeira concepção que alguém sem experiência chega sempre é achar que é possível desenhar tudo em papel e de uma só vez chegar num software que funciona, custando &ldquo;barato&rdquo; ainda. Não é assim que software funciona. Design emerge do software e não o contrário. Software nunca tá pronto na versão 1.0. É sempre um trabalho em andamento. Se você acha que terminou a última linha de código e nunca mais vai mexer, provavelmente é um software que ninguém usa.</p>
<p>E na sequência dessa concepção errada, vem outra concepção errada. A próxima pergunta é &ldquo;olha só, fiz aqui o desenho, me dá um prazo e quanto vai custar.&rdquo; Podemos ficar dias aqui discutindo porque esse pedido não faz sentido. Construir um negócio baseado em software não é que nem construir uma casa, que quando o último tijolo for colocado, acabou. Nunca vai ter o último tijolo.</p>
<p>A primeira coisa que vou dizer é: a maior parte do que tá desenhado aqui você não vai precisar. Pode jogar tudo fora, perda de tempo. A segunda coisa é: esquece, posso dar uma ordem de grandeza de quanto vai custar pra chegar numa versão minimamente funcional. Mas o software nunca vai terminar. No mínimo, no mínimo, você sempre vai precisar fazer atualizações de segurança, nos frameworks, bibliotecas e outros componentes da infraestrutura. Senão em pouquíssimo tempo seu sistema vai ser atacado e invadido embaixo do seu nariz. Não pode largar código rodando sem ninguém mais vendo.</p>
<p>Entenda, você só vai entender o que realmente precisa implementar quando uma versão mínima for pro ar, pessoas reais realmente começarem a usar, e daí as reais necessidades vão começar a emergir e elas vão quase sempre ser diferentes do que você imaginou. É a natureza de se lidar com tecnologia. Só quando é um software muito pequeno, pra poucos usuários, e que é um copy e paste de outro software que já existe. Por exemplo, você só quer colocar no ar mais um Wordpress da vida e mudar o logotipo na primeira página. Ok, isso pode ser simples, barato e vai pro ar logo. Muito mais que isso é incerto.</p>
<p>Num exemplo tosco só pra ilustrar aqui. Um pequeno ecommerce, você pode facilmente baixar um Magento da vida que é um ecommerce de código aberto, pagar alguém pra instalar num servidorzinho qualquer e tá pronto. Dificilmente vai ser simples assim, mas enfim. Um freelancer amador vai instalar tudo num VPS, tipo numa DigitalOcean ou Linode da vida, servidor web, banco de dados, tudo numa máquina virtual só. Vai suportar algumas dezenas de usuários e se você só precisa disso, ok, tá pronto. Por algum tempo vai funcionar.</p>
<p>Mas normalmente não é só isso. Provavelmente você quer integrar com meios de pagamento, por exemplo. Alguns já tem plugins pré-prontos pra um Magento da vida, outros não. Implementar pode ser fácil ou difícil. Se sua empresa tem algum mínimo de organização, certamente tem um ou mais sistemas de backoffice, um ERP, que administra aspectos da sua empresa como manufatura, estoque, contabilidade, RH, CRM e mais. Você provavelmente quer integrar com ele, pra poder gerar nota fiscal, controlar faturamento, contas a pagar e a receber, disponibilidade de produtos.</p>
<p>Isso é mais difícil ter plugins prontos, alguém vai precisar integrar, e se for um amador como é a maioria dos casos, vai fazer uma zona. Certeza. Em breve você vai ter problemas de performance. O banco de dados rapidamente vai se tornar um gargalo. Então você instala mais plugins como de cache pra tentar ajudar. Não tava previsto, porque quem nunca fez projetos grandes, não vai saber que precisa disso. Lá se vão mais dias de bateção de cabeça.</p>
<p>Por acaso você tem sorte, e seu marketing foi competente pra trazer muitos usuários. De repente nenhuma venda acontece. Começa a vir um monte de tickets de suporte porque ninguém consegue comprar nada. Lembra aquela integração com seu ERP? Pois é, foi feita de tal maneira que se ela não responder a tempo, seu checkout falha. Clássico. Nenhum ERP foi feito pra aguentar escala de web e se você programa um passo pra ser sequencial e dependente do outro, dançou. Todo amador cai nisso.</p>
<p>Agora tem que rearquitetar pra resposta do ERP ser assíncrona do checkout e só bloquear a próxima etapa, que é a entrega, por exemplo. Tornar um código síncrono em assíncrono significa ter que colocar uma fila, e se tiver uma fila é mais um componente que precisa ser monitorado e gerenciado porque se cair e perder o que tava lá, muitas vendas vão ficar bloqueadas ou corrompidas de novo. Uma solução sempre vai criando novos problemas. Não existe uma solução definitiva que resolve todos os problemas e você nunca mais vai precisar olhar.</p>
<p>Esse cenário é bem mais comum do que parece. Já vi acontecer várias vezes. Mas o oposto é igualmente ruim, que é quando alguém que já passou por essas coisas uma ou duas vezes, agora quer tentar prever tudo que pode dar errado e implementar de uma vez no projeto que tá fase super inicial, onde o negócio não foi provado, não tem um usuário pagante ainda. Agora o sistema fica tão complexo de fazer, demora tanto tempo, e por consequência custa tão caro, que o negócio não aguenta esperar tanto e fecha as portas. Nem tanto oito, nem tanto oitenta. E é aí que experiência faz diferença.</p>
<p>Em vez de planejar um projeto que vai levar 2 anos pra ficar pronto o melhor é planejar uma versão mínima, que dá fazer em 2 ou 3 meses pra testar a ideia e o mercado. Se tudo der errado, você perdeu 3 meses em vez de 2 anos. Toda vez que acha que pode economizar 100% já prevendo e fazendo tudo de uma vez, é quando você vai se dar mau, garantidamente. Porque você está partindo da premissa errada que dá pra prever tudo e que você vai aguentar esperar implementar tudo. Melhor arriscar pouco e perder pouco. Não existe risco zero, existe gerenciar riscos. E colocar todos os ovos num lugar só é o oposto disso.</p>
<p>Por isso não venha com mentalidade de &ldquo;ah, depois de 1 ano, meu sistema vai estar pronto e nunca mais vou precisar me preocupar&rdquo;. Você sempre vai precisar se preocupar. Dar manutenção, atualização. Melhorar seu sistema com o feedback dos seus usuários tem que virar parte da rotina da sua empresa e você deve se preparar pra isso. Precisa de sistema de suporte, precisa de equipe treinada pra atender as pessoas. O mercado é super competitivo, quem fica parado e não ouve seus usuários, sempre vai ficando pra trás.</p>
<p>Outro erro super comum. Mesmo caso, o cara me chega com um calhamaço de especificações e pede &ldquo;pra fazer meu sistema perfeito, preciso da equipe perfeita, me vê aí uns 5 ou 6 desenvolvedores sênior, pra viagem&rdquo;. Povo pensa que é pastelaria. Nenhum projeto precisa ter só seniors, além de ser um desperdício, você vai desmotivar pelo menos metade deles, que em pouco tempo vão vazar. Isso porque todo projeto tem tarefas desafiadoras e tem muitas tarefas mundanas. Ficar trocando textos, substituir imagens, corrigir pequenos bugs, atender suporte. Pede pra um senior fazer isso, ele vai mandar você ir lá praquele lugar, especialmente num mercado aquecido e competitivo como de agora.</p>
<p>É que nem você querer construir sua casa dos sonhos, aí na sua infinita sabedoria pensa &ldquo;cara, não vou contratar nenhum pedreiro, vou contratar uma dúzia de mestres de obra. Se os pedreiros fazem minha casa em 6 meses, certamente os mestres de obra sozinhos vão fazer em 3 meses e ainda com muito mais qualidade&rdquo;. Entenderam o ridículo? Todo projeto tem tarefas pra seniors e pra juniors. A tarefa mundana que o senior já fez quinhentas vezes e não quer fazer de novo? É exatamente o tipo de tarefa que um junior precisa pra ganhar experiência.</p>
<p>Coloque seniors orientando juniors e não só sua produtividade vai ser melhor do que num time só de seniors, vão ser todos mais motivados e você ainda aproveita pra garantir que sua equipe naturalmente consiga se auto-repor. O junior de hoje é o senior de amanhã. E quando chegar amanhã ele vai saber da importância de orientar novos juniors, porque foi assim que ele cresceu também. É um ciclo positivo. Toda empresa de tecnologia precisa de juniors, estagiários. Não é sustentável achar que sempre você vai achar seniors com disposição pra ficar fazendo tarefas mundanas de manutenção. É isso que eu pratico na minha empresa faz anos.</p>
<p>&ldquo;Ah, esse mercado tá foda, não consigo contratar.&rdquo; Lógico, você tá procurando só seniors pra ficar mudando botão de lugar na sua tela. Não é o mercado que tá foda, é você que não sabe contratar e não sabe formar pessoas. Formação de novas pessoas é fundamental pra qualquer negócio, seja grandes corporações ou pequenas startups. Pessoas entram e saem, ninguém fica pra sempre, mas se você forma pessoas, seu processo já está adaptado a mudanças.</p>
<p>Não sei se vocês notaram, mas em todos os exemplos que falei até agora o tema comum é que todo mundo sempre pensa em economizar. E tá correto, não se deve esbanjar dinheiro a toa. Mesmo quando tem sobrando. Porém, em todos os casos, estamos falando de casos de &ldquo;economia porca&rdquo;. Toda economia porca sempre vai sair caro lá na frente. É que nem comprar um Mercedes e querer economizar não fazendo seguro. O que acham que vai acontecer? Murphy é o cara que mais trabalha.</p>
<p>Um exemplo disso é quando o tal empreendedor decide que gerenciar projetos, gerenciar pessoas, processos de tecnologia e tudo mais não é pra ele. Então terceiriza 100% de toda a tecnologia pra outra empresa. Pronto, agora ele só dá ordem, paga fatura no fim do mês, e deixa outra pessoa com a dor de cabeça de gerenciar tudo. Faz uma pesquisa porca, acha uma agênciazinha de esquina que tem um sisteminha pré-pronto e lá vai ele confiar o negócio pra um estranho.</p>
<p>Hoje em dia é comum no mundo de Software as a Service, ou SaaS, mudar muita coisa de capex pra opex. Em poucas palavras mudar de gastos internos pra gastos externos, ou de propriedade própria pra aluguel de serviços. Por exemplo, seria impossível toda empresa ter seu próprio servidor de emails que seja rápido, seguro e tudo mais. Por isso ninguém faz isso, todo mundo faz uma assinatura do Gmail, Outlook e outros e pronto. O mesmo vale pra vários outros serviços como video conferência, email marketing, até CRM e contabilidade. Todo mundo conhece as marcas mais famosas e mais confiáveis. Mailchimp, Salesforce, Zoom e muito mais.</p>
<p>O problema é contratar uma empresinha desconhecida de fundo de quintal, onde você paga pra eles desenvolverem customizações ou novas funcionalidades, mas por contrato você não é dono do que tá pagando pra construir. Propriedade intelectual é sério. Software é propriedade intelectual. Mas no começo você não se incomoda, afinal sai mais em conta pra você trabalhar assim. Se alguma coisa parece boa demais, é porque é: é menos caro porque você não tinha a propriedade. E se no futuro o relacionamento azedar, você fica sem nada. E acredite, sempre azeda. É assim que as coisas funcionam. Aprenda a ler contratos.</p>
<p>Mas aí você não quer nem pagar caro e nem ficar na mão de um terceiro assim. Aconteceu um caso que o cara veio pedir uma demanda pra minha empresa, passamos o preço e ele reclamou que achou muito caro e que se a gente não baixasse  ia terceirizar pra uma empresa indiana. Por alguma razão acho que ele achava que tava me oferecendo alguma grande honra de trabalhar pra ele.</p>
<p>Resumindo minha resposta eu disse algo como &ldquo;não tem nenhum problema, o código é seu, você terceiriza pra quem você quiser. Mas eu não abaixo meu preço, e já aviso que você vai pagar a metade com os indianos e daqui 6 meses vai voltar pra mim pedindo pra consertar, e nessa hora meu preço vai ser o dobro.&rdquo; Seis meses depois, ele voltou. Não existe almoço de graça, você recebe proporcional ao que paga, se foi barato, é porque o resultado vai ser porco. Simples assim. Eu recebo tanto email de empresa desconhecida indiana me oferecendo serviços que eles já tão ganhando do príncipe nigeriano.</p>
<p>Tô cansado de virem procurar a gente falando &ldquo;olha só, conhece esse site X? Quanto vocês cobram pra fazer igual? Eu falei com um indiano e ele me falou que por mil dólares ele faz, se vocês fizerem por menos fecho com vocês&rdquo;. Não estou nem inventando, foi um caso recente. Você abre o tal site, é uma plataforma de fintech, mais ou menos. Só tem um hotsite bonitinho. Eu nem duvido que por mil dólares ele faça a 1a página, que é exatamente o que a maioria das pessoas pensa.</p>
<p>Entenda, só a primeira página. Esquece as coisas invisíveis por baixo: integração com outras plataformas, banco de dados, administrativo, etc. Muita gente acha que um site é só as primeiras páginas que ele vê, sendo que o grosso do trabalho é tudo aquilo que um usuário comum nunca vai ver. Como eu falei antes do designer que só faz mockup da página de login, porque é só isso que ele conhece. E muita gente acredita que é só isso mesmo. Mil dólares pfff. Um protótipo de software começa na ordem de grandeza de 10 vezes isso. Uma tech startup de verdade começa na ordem de 100 vezes isso. Pra mais. Mil dólares &hellip;</p>
<p>Falando em gente que inventa abobrinha, coloco nessa categoria os famosos NDAs que me mandam pra assinar. Coisa de departamento jurídico amador ou empreendedor de primeira viagem querendo impressionar do jeito errado. NDA pra quem não sabe é non-disclosure agreement, basicamente um contrato de confidencialidade querendo dizer &ldquo;eu acho que minha ideia é super foda, mas ninguém pode ficar sabendo, e se você roubar minha ideia ou contar pra alguém, cobro uma multa&rdquo;. Acho NDA uma coisa ridícula, especialmente pra empresa iniciante.</p>
<p>Como eu disse lá no começo, sua ideia não é original, pára de ficar se super-valorizando. Em segundo lugar, se sua ideia realmente é algo fora do comum que eu nunca vi, e se eu for de má índole e quiser roubar, a multa de um NDA é só um preço de compra barato. Só isso. Qual é a multa? 1 milhão de reais? 5 milhões? Noooosa. Se a ideia for tão boa assim deve valer 50 milhões, 100 milhões? Comprar por um 1 milhão é barato, pago a vista, em cash se quiser. Tosco.</p>
<p>E esses departamentos juridicos amadores são os que fazem contratos toscos, copy e paste de alguma coisa que viu no Google, com cláusulas do tipo &ldquo;pra trabalhar com a gente, você se compromete, caso a gente termine, de não trabalhar com mais nenhuma empresa do setor&rdquo;. Aí você vê que o cara é do setor de fintech. Ele acha que eu nunca mais vou trabalhar com nenhum outro fintech. Tá de brincadeira? Quer comprar minha empresa, você paga por ela. De graça, vai sonhando. É impressionante a quantidade de juridico tosco assim que eu vejo.</p>
<p>Jurídico tosco me lembra de licitações. Como eu já expliquei, software não tem como especificar e construir exatamente. Eu ainda estou pra ver uma licitação que especifica alguma coisa direito. Pra quem não sabe licitação é um leilão. A empresa faz o desenho de um projeto de software e convida algumas empresas pra avaliar e apresentar propostas de tempo, custo, suporte e tudo mais. Daí eles escolhem o mais barato, normalmente, ou a empresa de algum conhecido. Então é tudo menos justo. Como eu disse: barato sai caro e eu não participo de licitações porque acho o modelo inteiro tosco pra começo de conversa. Só lamento pra quem precisa trabalhar nesse modelo.</p>
<p>Isso me lembra de casos que a gente já recebeu de licitação que pede pra gente mandar um prazo pra entregar o projeto, sendo que um dos itens de trabalho que vai ser realizado é literalmente &ldquo;definir o escopo&rdquo;. Entenderam? Pra participar da licitação eles querem que a gente já se comprometa num prazo final sendo que o escopo nem sequer está definido e vai ser parte do projeto, depois que ganhar a licitação, definir esse escopo. É uma piada de tão mau gosto que fico imaginando que tipo de gênio da lâmpada escreve essas coisas e pior ainda, que tipo de animal aprova isso.</p>
<p>Eu disse que ia me focar no pequeno empreeededor mas licitação já começa a entrar na área de empresas maiores então acho que é minha deixa pra finalizar. Se não ficou claro, no dia zero, quando você tá pensando em criar um software pra sua empresa e você é o dono e/ou o investidor principal, nem pense em começar se não tem um sócio técnico experiente pra gerenciar tudo. Contrate alguns programadores internamente primeiro, funcionários devidamente contratados em tempo integral, e não freelancers.</p>
<p>Só depois terceirize uma parte pra acelerar a produtividade, mas faça os terceiros trabalharem junto com seus funcionários de confiança, nunca em modelo de black box onde você manda especificação e fica meses esperando eles entregarem alguma coisa depois. Se preocupe com aspectos de infraestrutura e segurança, LGPD tá aí. E se preocupe em formar pessoas. Você precisa sim de bons seniors, que sejam de confiança, que vão ajudar a orientar e treinar os juniors e estagiários. Esse é o básico do básico.</p>
<p>E veja, falei um monte até aqui e nem entrei no assunto sobre melhores linguagens de programação, frameworks ou coisas assim. Porque não importa. A melhor linguagem e ferramentas são aquelas que seus melhores funcionários preferem. Não é essa escolha que vai fazer diferença se todo o resto que falei antes não estiver correto primeiro. Você como administrador e empreendedor não-técnico não tem que meter o bedelho nisso, pra isso serve um CTO ou um Tech Lead. E lembre-se do mais importante: economia porca não compensa.</p>
<p>Tem muito mais que posso falar sobre isso, mas acho que por hoje é o suficiente. Se ficaram com dúvidas mandem nos comentários abaixo, se curtiram o video deixem um joinha, assinem o canal e não deixem de compartilhar o video com seus amigos. A gente se vê, até mais.</p>
]]></content:encoded><category>startups</category><category>engenharia-de-software</category><category>gestao</category><category>akitando</category></item></channel></rss>