<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[nddtech - Medium]]></title>
        <description><![CDATA[Somos especialistas em transformar dados em informações relevantes para facilitar a rotina das empresas. - Medium]]></description>
        <link>https://making.ndd.tech?source=rss----c9197bc611ac---4</link>
        <image>
            <url>https://cdn-images-1.medium.com/proxy/1*TGH72Nnw24QL3iV9IOm4VA.png</url>
            <title>nddtech - Medium</title>
            <link>https://making.ndd.tech?source=rss----c9197bc611ac---4</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Tue, 19 May 2026 06:40:50 GMT</lastBuildDate>
        <atom:link href="https://making.ndd.tech/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Harness Engineering: O que separa times que escalam IA dos que escalam dívida]]></title>
            <link>https://making.ndd.tech/harness-engineering-o-que-separa-times-que-escalam-ia-dos-que-escalam-d%C3%ADvida-d7cdd5eee4bd?source=rss----c9197bc611ac---4</link>
            <guid isPermaLink="false">https://medium.com/p/d7cdd5eee4bd</guid>
            <category><![CDATA[leadership]]></category>
            <category><![CDATA[tecnologia]]></category>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[artificial-intelligence]]></category>
            <dc:creator><![CDATA[Hugo Estevam Longo]]></dc:creator>
            <pubDate>Mon, 09 Mar 2026 12:18:45 GMT</pubDate>
            <atom:updated>2026-03-09T12:18:47.444Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*mEHEgRrce9SVXYOl" /><figcaption>Photo by <a href="https://unsplash.com/@pascal_habermann?utm_source=medium&amp;utm_medium=referral">Pascal Habermann</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><h3>Quando a velocidade sobe, mas a confiança cai</h3><p>Se você está desconfiado com a IA, você não está sozinho. Eu também já desconfiei.</p><p>Lendo um <a href="https://martinfowler.com/fragments/2026-02-18.html">artigo recente</a> do Martin Fowler (se você não conhece esse cara, se informe sobre ele pra ontem), uma frase ficou martelando na minha cabeça: a IA acelera aquilo que você já é. Se seu sistema de engenharia é saudável, acelera saúde. Se está capenga, acelera dívida.</p><p>Foi nesse ponto que a ideia ganhou forma para mim: o jogo não é mais sobre “quem escreve sintaxe mais rápido”. O jogo virou sobre quem constrói melhor o sistema de controle ao redor da IA.</p><p>Esse sistema eu tem sido chamado de <strong>Harness Engineering</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ZmlbzvHfM8og_EYikGUsxQ.png" /></figure><h3>O que eu entendo por Harness Engineering</h3><p>Se eu tivesse que resumir em uma frase:</p><p><strong>Harness Engineering é a disciplina de projetar testes, restrições arquiteturais, contexto e governança de risco para guiar o que a IA produz com segurança e consistência.</strong></p><p>Repara que isso muda o centro de gravidade da nossa profissão.</p><p>Antes, o foco principal era: “como eu escrevo esse código?”</p><p>Agora, o foco estratégico passa a ser:</p><ul><li>“Como eu defino o comportamento esperado?”</li><li>“Como eu protejo os limites arquiteturais do sistema?”</li><li>“Como eu forneço contexto suficiente para reduzir ambiguidade?”</li><li>“Como eu calibro o nível de autonomia da IA pelo risco da tarefa?”</li></ul><p>Eu gosto de uma analogia simples: <strong>o harness é a torre de controle</strong>. O avião (agente) pode ser rápido e poderoso, mas sem plano de voo, comunicação e regras de aproximação, a chance de colisão aumenta rápido.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*NC0i_lF7EaQQKi5f8AZXRQ.png" /></figure><h3>Por que esse tema importa agora</h3><p>No mesmo artigo do Fowler, aparecem ideias que eu considero centrais para os próximos anos:</p><ul><li><em>middle loop</em> (camada de supervisão) como trabalho de engenharia cada vez mais relevante</li><li><em>risk tiering</em> (estratificação de risco) como disciplina central</li><li><em>TDD</em> como forma robusta de <em>prompt engineering </em>(olha ele de novo aí)</li></ul><p>Eu concordo com essa direção porque ela conversa com algo que eu já vejo na prática: equipes que tratam IA como brinquedo de produtividade tendem a gerar pico de velocidade e vale de confiança. Equipes que tratam IA como parte do sistema de engenharia criam um efeito mais sustentável.</p><p>E aqui tem um ponto de liderança muito importante: <strong>isso não é responsabilidade de um indivíduo isolado</strong>. É desenho de sistema de trabalho. É alinhamento entre liderança técnica, arquitetura, plataforma e produto.</p><blockquote><em>“Poxa, Hugo, então agora todo dev vai virar auditor de IA e parar de programar?”, diz o Leitor</em></blockquote><p>Não. A programação continua existindo. O que muda é o vetor de valor.</p><p>O diferencial competitivo deixa de ser só escrever código e passa a incluir a capacidade de desenhar <strong>barreiras de proteção</strong> e <strong>ciclos de validação</strong> que mantêm qualidade em alta velocidade.</p><h3>Os 4 pilares do Harness Engineering</h3><p>Para não ficar abstrato, vamos ver o tema em quatro pilares que se reforçam.</p><h4>1. Testes e avaliações primeiro</h4><p>Se a IA gera opções, quem define certo e errado é o seu sistema de avaliação.</p><p>Por isso, eu tenho visto <em>TDD</em> (<em>Test-Driven Development</em>, desenvolvimento guiado por testes) ganhar um novo papel: não apenas melhorar design de código humano, mas também <strong>ancorar o comportamento esperado para agentes</strong>.</p><p>Sem isso, você está validando no olho e no <em>feeling</em>. E <em>feeling </em>não escala.</p><p>Na prática, esse pilar significa:</p><ul><li>Definir critérios de aceitação antes da geração</li><li>Usar testes automatizados como contrato mínimo de comportamento</li><li>Incluir avaliações não-funcionais quando fizer sentido (performance, segurança, observabilidade) ou as famosas <em>Architectural Fitness Functions</em></li><li>Tratar falhas recorrentes como sinal de lacuna no <em>harness</em>, não apenas “erro do modelo”</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*lM-tiM-8asp_0COGAeGFKg.png" /></figure><h4>2. Restrições arquiteturais explícitas</h4><p>Arquitetura implícita morre rápido quando você injeta velocidade de geração.</p><p>Se os limites de domínio, os contratos e os padrões de integração não estão claros, a IA tende a preencher lacunas com soluções plausíveis, mas desalinhadas.</p><p>Aqui entra um trabalho que times maduros já deveriam fazer, com IA ou sem IA:</p><ul><li>Tornar decisões arquiteturais explícitas (ADRs)</li><li>Definir limites que não podem ser atravessados</li><li>Estabelecer padrões aceitos para comunicação entre componentes</li><li>Reduzir ambiguidade estrutural</li></ul><p>É literalmente engenharia de contenção. Você não está reduzindo criatividade. Está protegendo integridade do sistema.</p><h4>3. Engenharia de contexto</h4><p>Esse pilar conecta diretamente com o que venho escrevendo sobre maturidade de agentes: contexto bom gera saída boa.</p><p>Quando falo de contexto, não é “prompt enorme”. É contexto útil, curado e orientado a decisão:</p><ul><li>convenções do time</li><li>decisões arquiteturais e seus porquês</li><li>regras de negócio que não podem ser violadas</li><li>exemplos reais que servem como referência</li></ul><p>Se você já usa artefatos como <em>OpenSpec</em>, <em>OpenCode</em> e <em>AgentSkills</em>, ótimo: eles cabem perfeitamente dentro deste pilar como instrumentos concretos de contexto.</p><p>O erro comum é achar que contexto é documento estático. Não é. <strong>É um ativo vivo de engenharia.</strong></p><p>Para maiores detalhes, leia meu artigo anterior: <a href="https://hugoestevam.medium.com/lideran%C3%A7a-situacional-na-era-da-ia-voc%C3%AA-j%C3%A1-lidera-agentes-e-nem-percebeu-8db7c8cf5ccd?source=user_profile_page---------0-------------1e79ee9dfe35----------------------">Liderança Situacional na Era da IA</a>.</p><h4>4. Risk tiering e autonomia proporcional</h4><p>Nem toda tarefa merece o mesmo nível de autonomia.</p><p>Esse é, talvez, o pilar mais negligenciado no começo da adoção de IA.</p><p>Eu sugiro uma matriz simples:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_6NUbJQhHuRt9oDrK5tg1g.png" /></figure><p>A ideia é simples: <strong>quanto maior o impacto potencial, maior o rigor de validação</strong>.</p><h3>O Harness Loop: operacionalizando no dia a dia</h3><p>Uma forma prática de tornar isso rotina é operar em ciclo.</p><p>Eu uso um loop de cinco etapas:</p><ol><li><strong>Especificar</strong> comportamento, limites e critérios</li><li><strong>Gerar</strong> com agentes de IA</li><li><strong>Avaliar</strong> com testes, checks e revisão orientada a risco</li><li><strong>Restringir</strong> onde houve deslizes (ajustar contexto e limites)</li><li><strong>Aprender</strong> com incidentes, retrabalho e acertos para evoluir o <em>harness</em></li></ol><p>Perceba que esse modelo desloca a conversa de “qual prompt mágico eu uso” para “qual sistema de aprendizagem e proteção meu time está construindo”.</p><p>Quando esse loop amadurece, acontece algo poderoso: a velocidade deixa de ser inimiga da qualidade.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*9B3Aq5RypIlNnqSX1KwhEw.png" /></figure><h3>Anti-patterns: sinais de que você está sem harness</h3><p>Se você quiser um check rápido de realidade, aqui vão sinais clássicos de adoção desequilibrada:</p><ul><li>Volume de PR aumentou, mas o tempo de <em>review </em>explodiu</li><li>Mesma <em>feature </em>com padrões diferentes dependendo de quem pediu ao agente</li><li>Crescimento de correções pós-merge</li><li>Discussões arquiteturais reaparecendo em toda sprint</li><li>Sensação constante de “não confio totalmente nisso”</li></ul><p>Se três ou mais desses sintomas estão acontecendo juntos, provavelmente não falta IA. Falta <em>harness</em>.</p><p>Outro anti-pattern comum: tentar resolver <strong>tudo </strong>com uma política genérica de uso de IA em uma base e achar que isso basta. Política sem mecanismo operacional vira intenção sem efeito.</p><h3>O papel dos líderes técnicos nesse cenário</h3><p>Na minha visão, o líder técnico da era dos agentes não perde relevância. Ele muda de alavanca.</p><p>Em vez de ser apenas o “resolvedor final” de problemas complexos, ele passa a ser também:</p><ul><li>designer de sistema de controle</li><li>curador de critérios de qualidade</li><li>articulador entre arquitetura, plataforma e produto</li><li>educador do time em práticas de validação</li></ul><p>Isso conversa com algo que eu já defendi em outros artigos: liderança técnica não é cargo, é comportamento. E aqui esse comportamento aparece de forma cristalina.</p><p>Você pode até usar a melhor IA do mercado, mas sem engenharia de proteção o resultado tende a oscilar. Com <em>harness </em>bem desenhado, até agentes diferentes convergem para outputs mais consistentes.</p><h3>Conclusão: velocidade sem controle não é evolução</h3><p>Se eu tivesse que resumir tudo em poucos pontos, seria isso:</p><ul><li>A IA muda o jogo, mas não elimina engenharia; ela muda onde a engenharia precisa ser mais forte</li><li><em>Harness Engineering</em> é o nome que tem sido usado para esse novo centro: testes, arquitetura, contexto e risco trabalhando juntos</li><li>O papel do desenvolvedor e do líder técnico evolui de executor de sintaxe para designer de sistema de controle</li><li>Times que tratam IA como aceleração sem proteção tendem a escalar dívida</li><li>Times que constroem <em>harness </em>consistente conseguem escalar velocidade com mais confiança</li><li>Aos CEOs, vocês sempre encontrarão alguém num corredor querendo vender uma solução mágica, vocês já sabem a resposta, o filme se repete.</li></ul><p>No fim do dia, não se trata de frear inovação. Se trata de colocar cinto de segurança, freios ABS e pneus novos em um carro que agora corre muito mais rápido.</p><p>E aí, no seu contexto, qual pilar do <em>Harness Engineering</em> está mais frágil hoje: testes, restrições arquiteturais, contexto ou <em>risk tiering</em>? Quero muito ler sua experiência nos comentários. 👍😃🚀</p><p><em>Artigos relacionados que podem aprofundar essa conversa:</em></p><ul><li><a href="https://hugoestevam.medium.com/lideran%C3%A7a-situacional-na-era-da-ia-voc%C3%AA-j%C3%A1-lidera-agentes-e-nem-percebeu-8db7c8cf5ccd?source=user_profile_page---------0-------------1e79ee9dfe35----------------------">Liderança Situacional na Era da IA</a></li><li><a href="https://hugoestevam.medium.com/arqu%C3%A9tipos-da-lideran%C3%A7a-t%C3%A9cnica-2ca14014b5cc?source=user_profile_page---------8-------------1e79ee9dfe35----------------------">Arquétipos da Liderança Técnica</a></li><li><a href="https://hugoestevam.medium.com/times-de-plataforma-a8126c8f3b4c?source=user_profile_page---------10-------------1e79ee9dfe35----------------------">Times de Plataforma</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d7cdd5eee4bd" width="1" height="1" alt=""><hr><p><a href="https://making.ndd.tech/harness-engineering-o-que-separa-times-que-escalam-ia-dos-que-escalam-d%C3%ADvida-d7cdd5eee4bd">Harness Engineering: O que separa times que escalam IA dos que escalam dívida</a> was originally published in <a href="https://making.ndd.tech">nddtech</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Liderança Situacional na Era da IA: Você Já Lidera Agentes e Nem Percebeu]]></title>
            <link>https://making.ndd.tech/lideran%C3%A7a-situacional-na-era-da-ia-voc%C3%AA-j%C3%A1-lidera-agentes-e-nem-percebeu-8db7c8cf5ccd?source=rss----c9197bc611ac---4</link>
            <guid isPermaLink="false">https://medium.com/p/8db7c8cf5ccd</guid>
            <category><![CDATA[tecnologia]]></category>
            <category><![CDATA[pessoas]]></category>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[artificial-intelligence]]></category>
            <category><![CDATA[leadership]]></category>
            <dc:creator><![CDATA[Hugo Estevam Longo]]></dc:creator>
            <pubDate>Mon, 02 Mar 2026 16:59:33 GMT</pubDate>
            <atom:updated>2026-03-02T16:59:35.517Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*auFnpuiv8iH5ueW2b32y3A.png" /></figure><h3>O déjà vu que mudou minha perspectiva</h3><p>Há alguns meses, eu estava revisando o <em>output</em> (resultado) de um agente de IA que configurei para gerar código em um projeto real. O código estava razoável, mas fora do padrão. Não seguia as convenções do projeto, ignorava decisões de arquitetura que tomamos meses atrás e, sinceramente, parecia aquele código genérico de tutorial que qualquer ferramenta cospe por padrão.</p><p>Eu parei. Respirei. E pensei: <strong>“Já vivi isso antes.”</strong></p><p>Não com uma IA. Com pessoas.</p><p>Lembrei de um desenvolvedor júnior que entrou no meu time anos atrás. Brilhante, motivado, cheio de energia, mas que produzia código fora do padrão, ignorava convenções do projeto e trazia soluções genéricas de <em>Stack Overflow</em>. Não porque era ruim, mas porque <strong>lhe faltava contexto, maturidade e direcionamento</strong>.</p><p>E o que eu fiz com ele? Direcionei. Expliquei padrões. Revisei <em>pull requests</em>. Aos poucos, fui dando mais autonomia. Até que um dia, ele estava tocando <em>features</em> complexas sozinho, com qualidade impecável.</p><p>Foi aí que caiu a ficha: <strong>eu estava liderando agentes de IA exatamente como lidero pessoas.</strong> E, mais importante, o modelo que uso para desenvolver liderados funcionava perfeitamente para desenvolver agentes.</p><p>Esse modelo tem nome: <strong>Liderança Situacional</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*RG8o6yz2zB1GHYr22ztPNg.png" /></figure><h3>O modelo que você já conhece (mas talvez não aplique assim)</h3><p>A <a href="https://en.wikipedia.org/wiki/Situational_leadership_theory"><em>Situational Leadership</em></a> (Liderança Situacional), criada por Paul Hersey e Ken Blanchard, é um dos modelos de liderança mais conhecidos do mundo. A ideia central é simples e poderosa: <strong>não existe um único estilo de liderança que funcione para todos. O estilo certo depende da maturidade de quem você está liderando.</strong></p><p>O modelo define <strong>quatro níveis de maturidade</strong> do liderado:</p><ul><li><strong>D1 — Iniciante Entusiasmado:</strong> Baixa competência, alto comprometimento. Quer fazer, mas não sabe como.</li><li><strong>D2 — Aprendiz Desiludido:</strong> Alguma competência, baixo comprometimento. Começou a ver a complexidade real e perdeu parte da confiança.</li><li><strong>D3 — Capaz, mas Cauteloso:</strong> Alta competência, comprometimento variável. Sabe fazer, mas ainda hesita em decisões mais autônomas.</li><li><strong>D4 — Autossuficiente:</strong> Alta competência, alto comprometimento. Pronto para receber uma tarefa e entregar com qualidade, sem microgerenciamento.</li></ul><p>E para cada nível de maturidade, existe um <strong>estilo de liderança</strong> correspondente:</p><ol><li><strong>S1 — Dirigir:</strong> Alta direção, baixo suporte. Você diz o quê e como fazer.</li><li><strong>S2 — Orientar (<em>Coach</em>):</strong> Alta direção, alto suporte. Você explica, ensina e acompanha de perto.</li><li><strong>S3 — Apoiar:</strong> Baixa direção, alto suporte. Você está disponível, mas deixa a pessoa conduzir.</li><li><strong>S4 — Delegar:</strong> Baixa direção, baixo suporte. Você entrega a responsabilidade e confia no resultado.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/736/0*WaHTZC7jYR6bFrbB.jpg" /></figure><p>A beleza do modelo é que ele não é estático. <strong>A maturidade evolui</strong>, e o líder precisa acompanhar essa evolução, ajustando seu estilo. Tratar um D4 como D1 gera frustração. Tratar um D1 como D4 gera desastre.</p><blockquote><strong><em>“Poxa, Hugo, mas isso eu já sei. O que isso tem a ver com IA?”</em></strong><em>, diz o Leitor</em></blockquote><p>Tudo. Absolutamente tudo!</p><h3>A grande sacada: agentes de IA também têm níveis de maturidade</h3><p>Pense no seguinte: quando você abre o <em>Claude Code</em>, o <em>GitHub Copilot</em> ou qualquer agente de código pela primeira vez em um projeto, o que acontece?</p><p>Ele não conhece suas convenções. Não sabe quais padrões de arquitetura você adotou. Não entende por que vocês escolheram uma lib em vez de outra. Ele é, literalmente, um <strong>D1 — Iniciante Entusiasmado</strong>. Tem uma capacidade absurda (o “comprometimento” aqui é o poder computacional), mas <strong>zero contexto</strong> sobre o seu projeto.</p><p>E o que a maioria das pessoas faz? Trata esse agente D1 como se fosse D4. Joga um prompt vago, “crie o endpoint de usuários”, e reclama que o resultado veio genérico, fora do padrão, sem considerar as decisões do projeto.</p><p><strong>Isso é como delegar uma tarefa complexa para um júnior no primeiro dia.</strong> Claro que não vai funcionar!</p><p>A grande sacada está aqui: <strong>você precisa evoluir a maturidade do seu agente de IA da mesma forma que evolui a maturidade de um liderado.</strong> Isso não acontece com um prompt mágico. Acontece com um <strong>processo estruturado</strong> de construção de contexto, especificações e padrões.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jVDlVkhs5Ew5VkVoOcunXA.png" /></figure><h3>O agente D1: muito poder, nenhum contexto</h3><p>Vamos ser honestos: a maioria dos líderes técnicos hoje está preso no estágio D1 com seus agentes de IA. E a culpa não é da ferramenta, <strong>é da falta de investimento em maturidade</strong>.</p><p>Um agente D1 é como aquele desenvolvedor júnior brilhante que acabou de chegar. Ele é capaz? Sim, extremamente. Mas quando você pede “implementa o serviço de notificações”, ele vai entregar algo que funciona, mas que não segue o padrão de <em>services</em> do projeto, usa uma estrutura de pastas diferente, escolhe uma abordagem de <em>error handling</em> (tratamento de erros) que ninguém do time usa e ignora completamente o padrão de <em>logging</em> que vocês definiram.</p><p>O que você faz com esse desenvolvedor júnior? <strong>Dirige.</strong> Senta do lado, explica os padrões, mostra exemplos, revisa linha por linha.</p><p>Com o agente D1, é a mesma coisa: você precisa ser extremamente diretivo nos prompts, especificar cada detalhe, e revisar tudo. <strong>É trabalhoso, é lento, e muitas vezes você pensa: “era mais rápido eu mesmo ter feito.”</strong></p><p>E sabe o que mais? Esse pensamento é <strong>exatamente </strong>o mesmo que muitos líderes têm com liderados D1. Mas líderes maduros sabem que o investimento inicial se paga exponencialmente depois.</p><h3>Os frameworks que aceleram a evolução: AgentSkills, OpenSpec e OpenCode</h3><p>Assim como no desenvolvimento de pessoas em que nós usamos PDIs (<em>Plano de Desenvolvimento Individual</em>), <em>one-on-ones</em>, <em>feedbacks</em> estruturados e programas de mentoria, no desenvolvimento de agentes de IA existem <strong>frameworks que estruturam a evolução da maturidade</strong>.</p><p>Na minha experiência, três se destacam, e usados em conjunto, são transformadores:</p><h4>AgentSkills: O que o agente sabe fazer</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/601/1*-R15k8ddilKKvUltbHnOkw.png" /></figure><p>O <a href="https://agentskills.io/"><em>AgentSkills</em></a> é um framework que define as <strong>habilidades e capacidades</strong> do agente no contexto do seu projeto. Pense nele como a “matriz de competências” que muitas empresas usam para guiar a carreira dos desenvolvedores.</p><p>Quando você estrutura as <em>skills</em> (habilidades) do agente, está dizendo: “Você sabe fazer isso, siga essas regras ao fazer aquilo, e quando encontrar esse cenário, use essa abordagem.”</p><p>É o equivalente a mapear as competências de um liderado e definir expectativas claras para cada uma.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ThNgSUunB4b6ZP4kk_evRA.png" /></figure><h4>OpenSpec: O contexto e as decisões do projeto</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/673/1*AsV0gqf9M3PsgJCuyMFyIw.png" /></figure><p>O <a href="https://openspec.dev/"><em>OpenSpec</em></a><em> </em>é onde vivem as <strong>especificações </strong>do projeto, as decisões de arquitetura, os <em>trade-offs</em> (prós e contras) que foram feitos, os requisitos não-funcionais, as regras de negócio fundamentais.</p><p>Se o <em>AgentSkills</em> é “o que o agente sabe fazer”, o <em>OpenSpec</em> é <strong>“o que o agente precisa saber sobre o projeto”</strong>.</p><p>É como aquele documento de <em>onboarding</em> que você prepara para um novo membro do time, mas estruturado para consumo de uma IA. Inclui:</p><ul><li><strong>Decisões de arquitetura</strong> e suas justificativas</li><li><strong>Padrões adotados</strong> e por que foram escolhidos</li><li><strong>Contexto de negócio</strong> relevante para decisões técnicas</li><li><strong>Restrições</strong> técnicas e organizacionais</li></ul><p>O papel do <em>OpenSpec </em>no meu fluxo de trabalho é planejar. Antes de qualquer Agente sair codificando, é preciso que existam artefatos (<em>specs</em>) que descrevem exatamente o que precisa ser feito. Aqui é essencial o uso de modelos de IA mais “poderosos” para criação de artefatos ricos e detalhados, para que na codificação possamos economizar.</p><h4>OpenCode: O executor do trabalho</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/631/1*fehHvWC9_7yi8QgooCxvcA.png" /></figure><p>O <a href="https://opencode.ai/"><em>OpenCode</em></a><em> </em>complementa o trio definindo <strong>como o código deve ser escrito</strong>. Não é apenas executor, mas também o orquestrador que escolhe as habilidades necessárias para a execução da demanda, consultando <em>specs </em>e <em>skills</em>:</p><ul><li>Padrões de nomenclatura</li><li>Estrutura de arquivos e pastas</li><li><em>Design patterns</em> (padrões de projeto) preferidos</li><li>Como tratar erros, logs, testes</li><li>Tarefas a serem executadas, bem como seu andamento</li></ul><blockquote><em>Pense assim: se o </em>AgentSkills<em> é o currículo do agente, o </em>OpenSpec<em> é a especificação do projeto e o </em>OpenCode<em> é o que da vida a funcionalidade. </em><strong><em>Juntos, eles transformam um agente D1 em um agente D3 com potencial D4</em></strong><em>.</em></blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*UmJhZ6pdMkb3z56O0pqBvw.png" /></figure><h3>De D1 a D4: o caminho na prática</h3><p>Vou compartilhar como funciona a evolução, baseado na minha experiência com <strong>Claude Code </strong>e <strong>GitHub Copilot</strong>.</p><blockquote>De modo proposital não pretendo explicar no detalhe cada ferramenta, elas tem uma documentação abrangente e esse não é o objetivo do artigo.</blockquote><h4>Estágio 1: Dirigir (D1 → D2)</h4><p>No início, o agente não tem nada. Você começa criando as bases:</p><ul><li><strong>Documente as decisões de arquitetura</strong> no <em>OpenSpec: </em>não precisa ser perfeito, precisa existir em openspec/config.yaml. Depois você evolui.</li></ul><pre>schema: spec-driven<br><br>context: |<br>  Tech stack: .NET 10, ASP.NET Core Web API, C#<br>  Architecture: Feature Folder with Vertical Slice Architecture<br>  ORM: Entity Framework Core (PostgreSQL / SQL Server<br>  Auth: Keycloak with JWT Bearer tokens<br>  Events: Dapr pub/sub integration events<br>  Testing: xUnit with Arrange-Act-Assert pattern<br>  API docs: Scalar (OpenAPI)<br>  We maintain backwards compatibility for all public APIs<br>  ... <br>  to be continued<br><br>rules:<br>  proposal:<br>    - Include rollback plan for risky changes<br>  specs:<br>    - Use Given/When/Then format for scenarios<br>    - Reference existing patterns before inventing new ones<br>  design:<br>    - Include sequence diagrams for complex flows<br>  task:<br>    - Break down implementation into checkboxed tasks.</pre><ul><li><strong>Configure</strong> o <em>OpenCode: </em>Faça com que ele conheça o que um executor precisa conhecer. Regras do projeto: CLAUDE.md no diretório do seu projeto (usado se não existir AGENTS.md)</li></ul><pre># Sample Project<br><br>## Architecture Overview<br><br>This is a .NET 10 Web API using **Feature Folder with Vertical Slice Architecture** and **CQRS pattern**. <br><br>### Feature Folders (Business Logic)<br>Each feature is self-contained under `Features/{FeatureName}/` with use-case slices:<br><br>```<br>Features/{FeatureName}/<br>├── {Entity}.cs                    # Domain entity<br>├── I{Entity}Repository.cs         # Repository interface<br>├── {Entity}Repository.cs          # Repository implementation<br>├── {Entity}Configuration.cs       # EF Core entity config<br>├── {FeatureName}Controller.cs     # API Controller<br>├── {Entity}ViewModel.cs           # ViewModels<br>...<br>```<br><br>### Code Standards<br><br>- Prefer file-scoped namespace declarations and single-line using directives.<br>- Ensure that the final return statement of a method is on its own line.<br>- Use pattern matching and switch expressions wherever possible.<br>- Use nameof instead of string literals when referring to member names.<br>- Always use is null or is not null instead of == null or != null.<br><br>### Database<br>- Supports **SQL Server** and **PostgreSQL** (switch via `DatabaseProvider` in appsettings)<br>- Migrations auto-apply on startup via `ApplyDatabaseMigrations()`<br>- Local default: SQL Server LocalDB; Docker: PostgreSQL<br>... <br>to be continued</pre><ul><li><strong>Defina as primeiras <em>skills</em></strong> no <em>AgentSkills: </em>as tarefas mais comuns que você quer delegar. O OpenCode pesquisa nesse local: .opencode/skills/&lt;name&gt;/SKILL.md</li></ul><pre>---<br>name: api-endpoint<br>description: Creates API controller endpoints with proper routing, authorization, documentation. Use when adding new HTTP endpoints, REST APIs, or when the user asks to create a controller or API route.<br>metadata:<br>  author: hugo<br>  version: &quot;1.0&quot;<br>---<br><br># API Endpoint Skill<br><br>This skill guides the creation of API controllers following the project&#39;s patterns with MediatR and proper documentation.<br><br>## Controller Structure<br><br>Location: `Features/{FeatureName}/{FeatureName}Controller.cs`<br>... <br>to be continued</pre><p>Neste estágio, você ainda está <strong>dirigindo</strong>: cada prompt é detalhado, cada resultado é revisado linha por linha, e você frequentemente corrige e ajusta. É trabalhoso, mas é aqui que a fundação é construída.</p><p>Observe que os exemplos são simples, nesse estágio o objetivo é entender como o fluxo está sendo executado e se as coisas simples aplicadas estão sendo “absorvidas” pelo agente.</p><h4>Estágio 2: Orientar (D2 → D3)</h4><p>Com os frameworks básicos no lugar, o agente começa a produzir resultados mais consistentes, mas ainda precisa de orientação forte. Você:</p><ol><li><strong>Refine a forma como as especificações são geradas </strong>com base nos erros que observa. Não se preocupe em ter as definições de projeto em vários lugares, pois são usadas por ferramentas diferentes em momentos diferentes. Ainda há espaço pra melhorar.</li><li><strong>Adicione exemplos reais</strong> do projeto ao System Prompt do <em>OpenCode. </em>Se as especificações estão corretas, mas a implementação saiu torta, verifique onde faltou contexto para a execução do <em>OpenCode</em>.</li><li><strong>Expanda as <em>skills</em></strong> com cenários mais complexos. Modelos tem limite de contexto, portanto separar bem as <em>skills</em> e rodar em <em>SubAgents </em>é um trunfo.</li><li><strong>Dar <em>feedback</em> ao agente</strong> através de correções no uso do workflow do frameworks</li></ol><p>É como fazer <em>coaching</em> com um liderado D2: “Olha, ficou bom aqui, mas nessa parte você precisa seguir esse padrão. Veja esse exemplo.”</p><h4>Estágio 3: Apoiar (D3 → D4)</h4><p>Aqui a mágica começa. O agente já produz código dentro do padrão na maioria dos casos. Seu papel muda: em vez de dirigir cada passo, você <strong>revisa e valida</strong>. Faz <em>code review</em> do que o agente produziu, assim como faria com um desenvolvedor sênior.</p><p>Você ainda está presente, mas a dinâmica inverteu: o agente conduz, você apoia.</p><h4>Estágio 4: Delegar (D4)</h4><p>Este é o estágio que mudou minha produtividade. Quando o agente atinge a maturidade D4, com <em>AgentSkills</em>, <em>OpenSpec</em> e <em>OpenCode</em> bem estruturados, você pode <strong>delegar tarefas com confiança</strong>.</p><p>Na minha experiência, quando chego nesse estágio, algo impressionante acontece: <strong>os resultados dos Modelos de IA ficam muito similares entre si</strong>. Respeitam o estilo de codificação, seguem as decisões técnicas do projeto e produzem código que parece ter sido escrito pelo time.</p><p><strong>E tudo isso em um tempo drasticamente menor.</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*E3x3SH6D7JRsjySkwGh42w.png" /></figure><h3>O resultado que comprova o modelo</h3><p>Quero ser bem direto aqui, porque sei que muitos líderes técnicos são (justificadamente) céticos com promessas de produtividade da IA.</p><p>Quando você evolui a maturidade dos agentes com esses frameworks, o resultado não é apenas “código mais rápido”. É <strong>código consistente</strong>. É código que respeita as decisões do projeto. É código que parece ter sido escrito por alguém que <strong>entende o contexto</strong>.</p><p>Na prática, o que observei foi:</p><ul><li><strong>Modelos de IA </strong>(GPT Codex e Claude Opus, obrigado Github Copilot por liberar ambos os modelos em uma única assinatura) <strong>produzem resultados</strong> muito similares quando recebem os mesmos artefatos de maturidade. Isso mostra que <strong>a qualidade do output não depende tanto da ferramenta, mas da qualidade do contexto que você fornece</strong></li><li>O <strong>estilo de codificação é respeitado</strong>, nomenclaturas, padrões de projeto, estrutura de arquivos</li><li>As <strong>decisões técnicas são seguidas</strong>, a IA não tenta reinventar a roda quando já existe uma roda definida. Mesmo que não esteja tão redonda, situação da maioria dos projetos de software.</li><li>O <strong>tempo de desenvolvimento cai drasticamente</strong>, tarefas que levariam dias são entregues em horas ou até minutos, com qualidade de review.</li></ul><blockquote><em>A grande sacada não é qual IA você usa. </em><strong><em>A grande sacada é o processo de evoluir a maturidade do agente a ponto de poder delegar.</em></strong><em> Assim como na liderança de pessoas, o investimento em maturidade é o que gera autonomia.</em></blockquote><h3>A armadilha que todo líder precisa evitar</h3><p>Existe um erro clássico na Liderança Situacional com pessoas que se repete <em>identicamente</em> com agentes de IA: <strong>tratar todos os contextos com o mesmo estilo</strong>.</p><p>Assim como um líder que só sabe delegar vai frustrar um júnior, e um líder que só sabe dirigir vai sufocar um sênior, você precisa <strong>calibrar sua interação com o agente de acordo com o estágio de maturidade em que ele está para aquele projeto específico</strong>.</p><p>Repare: eu disse “<strong>para aquele projeto específico</strong>”. Assim como um desenvolvedor pode ser D4 em uma linguagem e D1 em outra, um agente pode ser D4 no seu projeto <em>backend</em> (onde você investiu nos frameworks) e D1 no seu projeto <em>frontend</em> (onde ele tem pouco ou nenhum contexto).</p><p><strong>A maturidade não é global. É contextual.</strong></p><p>Outra armadilha: achar que o D4 é permanente. Projetos evoluem. Novas decisões de arquitetura são tomadas. Se você não atualiza o <em>OpenSpec</em>, o <em>OpenCode</em> e o <em>AgentSkills</em>, o agente <strong>regride</strong>. É como um colaborador que parou de receber atualizações e feedback, ele vai ficar desatualizado.</p><h3>Como começar amanhã</h3><p>Se você é um líder técnico e quer aplicar esse modelo, aqui vai um caminho prático:</p><ol><li><strong>Identifique o projeto mais crítico</strong>, aquele onde a produtividade do agente teria mais impacto</li><li><strong>Comece pelo <em>OpenSpec</em></strong>, documente as 5 decisões de arquitetura mais importantes do projeto. Não precisa ser perfeito, precisa existir</li><li><strong>Depois, crie o <em>OpenCode</em></strong>, registre as 10 convenções de código mais críticas. Inclua exemplos reais do próprio projeto</li><li><strong>Configure o <em>AgentSkills</em></strong>, defina as 3 tarefas mais comuns que você quer delegar ao agente</li><li><strong>Teste com Modelos de IA</strong>, dê a mesma tarefa para modelos diferentes, com os mesmos artefatos, e compare os resultados</li><li><strong>Itere</strong>, a cada resultado fora do padrão, se pergunte: “O que faltou no <em>OpenSpec</em>, no <em>OpenCode</em> ou no <em>AgentSkills</em> para que ele acertasse?”</li></ol><p>Esse ciclo de iteração é <strong>exatamente</strong> o ciclo de desenvolvimento de um liderado. Cada erro é uma oportunidade de refinar o contexto. E a cada refinamento, o agente sobe um degrau na escada de maturidade.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*prD2rT1OiS6IECPFerxmcw.png" /></figure><h3>A liderança que ninguém te ensinou</h3><p>Quando estudamos Liderança Situacional, ninguém imaginou que um dia aplicaríamos esse modelo a agentes de inteligência artificial. Mas se pararmos para pensar, faz todo sentido.</p><p>Liderar é, em essência, sobre <strong>desenvolver capacidade em quem você lidera para que, eventualmente, essa pessoa (ou agente) possa atuar com autonomia</strong>. O veículo muda, de pessoas para IAs, mas o princípio permanece:</p><ul><li><strong>Contexto gera consistência</strong></li><li><strong>Investimento em maturidade gera autonomia</strong></li><li><strong>O estilo de liderança precisa se adaptar ao nível de maturidade</strong></li></ul><p>Os líderes técnicos que vão se destacar nos próximos anos não serão apenas aqueles que sabem usar Claude Code ou GitHub Copilot. Serão aqueles que entendem que <strong>a ferramenta é o meio, e a maturidade é o fim</strong>. Que sabem construir <em>AgentSkills</em>, <em>OpenSpec</em> e <em>OpenCode</em> (ou ferramentas futuras) de forma estruturada. Que aplicam, conscientemente, os mesmos princípios de liderança que já funcionam com pessoas.</p><p>Porque no final das contas, o problema nunca foi a IA. <strong>O problema sempre foi a falta de um processo de maturidade.</strong></p><p>E isso, caro leitor, é algo que todo bom líder já sabe resolver. Você só precisa aplicar o que já sabe em um novo contexto.</p><h3>Conclusão: os pontos que importam</h3><p>Para não perder o fio da meada, aqui vai o resumo do que conversamos:</p><ul><li><strong>A Liderança Situacional</strong> (Hersey &amp; Blanchard) define 4 níveis de maturidade (D1 a D4) e 4 estilos de liderança correspondentes (S1 a S4)</li><li><strong>Agentes de IA também têm maturidade</strong>, e ela começa em D1 (sem contexto) em todo projeto novo</li><li><strong>Três frameworks</strong> aceleram a evolução: <em>AgentSkills</em> (habilidades), <em>OpenSpec</em> (especificações do projeto) e <em>OpenCode</em> (convenções de código)</li><li><strong>A maturidade é contextual</strong>, o mesmo agente pode ser D4 em um projeto e D1 em outro</li><li><strong>Quando o agente atinge D4</strong>, ferramentas como Claude Code e GitHub Copilot produzem resultados surpreendentemente similares e consistentes com o estilo do projeto</li><li><strong>A grande sacada</strong> não é qual IA usar, mas <strong>investir no processo de evolução da maturidade do agente</strong></li></ul><p>E aí, você já parou para pensar em que estágio de maturidade estão os agentes de IA nos seus projetos? Está dirigindo, orientando, apoiando ou delegando? Deixe sua opinião nos comentários, quero muito ouvir como tem sido a experiência de vocês liderando essas “novas mentes” do time! 👍🚀😃</p><p><em>Artigos relacionados que podem te interessar:</em></p><ul><li><a href="https://hugoestevam.medium.com/arqu%C3%A9tipos-da-lideran%C3%A7a-t%C3%A9cnica-2ca14014b5cc?source=user_profile_page---------8-------------1e79ee9dfe35----------------------">Arquétipos da Liderança Técnica</a></li><li><a href="https://hugoestevam.medium.com/o-papel-da-empresa-e-dos-l%C3%ADderes-na-evolu%C3%A7%C3%A3o-de-carreira-dos-liderados-255d17cab662?source=user_profile_page---------6-------------1e79ee9dfe35----------------------">O papel da empresa e dos líderes na evolução de carreira dos liderados</a></li><li><a href="https://hugoestevam.medium.com/contribuidor-individual-ou-gest%C3%A3o-de-pessoas-9417a11da228?source=user_profile_page---------7-------------1e79ee9dfe35----------------------">Contribuidor Individual ou Gestão de Pessoas</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8db7c8cf5ccd" width="1" height="1" alt=""><hr><p><a href="https://making.ndd.tech/lideran%C3%A7a-situacional-na-era-da-ia-voc%C3%AA-j%C3%A1-lidera-agentes-e-nem-percebeu-8db7c8cf5ccd">Liderança Situacional na Era da IA: Você Já Lidera Agentes e Nem Percebeu</a> was originally published in <a href="https://making.ndd.tech">nddtech</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Seu Sistema Ainda Depende de Polling? Como construímos webhooks multitenant no Labs]]></title>
            <link>https://making.ndd.tech/seu-sistema-ainda-depende-de-polling-como-constru%C3%ADmos-webhooks-multitenant-no-labs-e61cb4c7a790?source=rss----c9197bc611ac---4</link>
            <guid isPermaLink="false">https://medium.com/p/e61cb4c7a790</guid>
            <category><![CDATA[desenvolvimento]]></category>
            <category><![CDATA[tecnologia]]></category>
            <dc:creator><![CDATA[Gustavo Fontana]]></dc:creator>
            <pubDate>Thu, 26 Feb 2026 16:22:46 GMT</pubDate>
            <atom:updated>2026-02-26T16:22:45.694Z</atom:updated>
            <content:encoded><![CDATA[<p>Fazendo uma analogia, polling é o equivalente técnico de ligar para a transportadora a cada 5 minutos perguntando “meu pacote chegou?”. Funciona, mas desperdiça tempo dos dois lados. Webhooks invertem essa lógica: a transportadora liga para você quando o pacote chega.</p><p>Esse artigo mostra o conceito, os desafios reais de uma implementação em produção e as decisões de arquitetura que tomamos no NDD Labs ao construir um sistema de webhooks multitenant em <a href="https://learn.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis/overview?view=aspnetcore-9.0">.NET 9</a>.</p><h3>O Que São Webhooks?</h3><p>Webhooks são callbacks HTTP que permitem que uma aplicação notifique outra quando um evento específico acontece. Enquanto APIs tradicionais funcionam no modelo pull (você pergunta: “tem novidade?”), webhooks funcionam no modelo push (o sistema avisa: “acabou de acontecer algo importante!”).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1023/1*shv_-I5AK30mCo6UfIWXpA.png" /><figcaption>Imagens retiradas do portal NDP — Labs</figcaption></figure><h3>Polling vs. Webhook</h3><p>A diferença prática: em um e-commerce com 10.000 pedidos ativos, polling geraria milhares de requisições por minuto, a maioria retornando “nada de novo”. Com webhooks, o sistema só envia notificações quando um pedido realmente muda de status.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*nGLTa7A1HUn-jY_hGq2Gow.png" /></figure><h3>Do Conceito à Produção</h3><p>Entendido o conceito, surge a pergunta prática: como construir um sistema de webhooks que funcione em produção, com múltiplos clientes, segurança real e tolerância a falhas?</p><p>Foi exatamente esse desafio que enfrentamos no Labs. Nossos módulos atendem dezenas de produtos, e cada uma precisa de webhooks configuráveis com seus dados completamente isolados. A seguir, as decisões de arquitetura que tomamos e por quê.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*7KGQl9mksTsqs-cw6taPqw.png" /><figcaption>Imagem retirada do portal NDP — Labs</figcaption></figure><h3>Multitenancy: Isolamento na Camada de Dados</h3><p>O primeiro desafio foi garantir que nenhuma organização visse dados de outra. A solução foi colocar o filtro na camada mais baixa possível: <a href="https://learn.microsoft.com/en-us/ef/core/querying/filters">query filters do Entity Framework Core</a>:</p><pre>// Configuramos o filtro uma vez no DbContext<br>modelBuilder.Entity&lt;WebhookSubscription&gt;()<br>    .HasQueryFilter(s =&gt; s.OrganizationId == _currentTenant.Id);<br><br>// Qualquer query já vem filtrada automaticamente<br>var subscriptions = await _context.Subscriptions.ToListAsync();<br>// Retorna apenas subscrições da organização atual</pre><p>Cada requisição inclui o header X-Organization-Id. Um middleware valida o header, resolve a organização e injeta o contexto de tenant antes que qualquer endpoint execute. Se o header estiver ausente, malformado ou apontar para uma organização inativa, a requisição é rejeitada com 400 Bad Request antes de tocar no banco.</p><h3>Segurança com HMAC</h3><p>Implementamos autenticação <a href="https://docs.github.com/en/webhooks/using-webhooks/validating-webhook-deliveries">HMAC-SHA256</a>, o mesmo padrão usado por <a href="https://docs.github.com/en/webhooks/using-webhooks/validating-webhook-deliveries">GitHub</a>, <a href="https://docs.stripe.com/webhooks">Stripe</a> e Slack. O conceito é simples: funciona como um lacre de segurança em uma encomenda. O remetente lacra o pacote com um código que só ele e o destinatário conhecem. Se o lacre chegar violado, o destinatário sabe que alguém mexeu no conteúdo no caminho.</p><p>Na prática, cada webhook enviado inclui uma assinatura criptográfica nos headers (X-Webhook-Signature, X-Webhook-Timestamp, X-Webhook-Id) que permite ao receptor validar a autenticidade do payload. A comparação usa <a href="https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.cryptographicoperations.fixedtimeequals">FixedTimeEquals</a>, uma comparação time-constant que impede ataques de timing, onde um atacante tenta deduzir a assinatura correta medindo tempos de resposta.</p><p>Além da assinatura, o timestamp é validado com tolerância de 5 minutos, prevenindo replay attacks.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5bOnLJlWBgUVtMzPw5NWsg.png" /><figcaption>Imagem retirada do portal NDP — Labs</figcaption></figure><h3>Confiabilidade com Retentativas Inteligentes</h3><p>Falhas acontecem: o endpoint do cliente pode estar temporariamente fora, a rede pode oscilar, um deploy pode reiniciar o serviço. A estratégia para lidar com isso é o <a href="https://learn.microsoft.com/en-us/dotnet/architecture/microservices/implement-resilient-applications/implement-retries-exponential-backoff">backoff exponencial</a>, a lógica é a mesma de tentar ligar para alguém que não atende: você espera um pouco, tenta de novo, espera mais, tenta de novo. Se insistir a cada 2 segundos, vira inconveniente. Se espaçar as tentativas, as chances de encontrar o serviço disponível aumentam sem sobrecarregá-lo.</p><p>Na prática: se a primeira tentativa falhar, esperamos 5 minutos. Se falhar de novo, 10. Depois 20, depois 40, até um máximo de 1 hora. Cada cliente pode configurar quantas tentativas quer e qual o intervalo base na própria subscrição, um cliente que precisa de entrega rápida usa intervalos curtos com muitas tentativas; outro que tolera mais latência pode ser menos agressivo.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ALG650NIMVZEj0Zy9hPySg.png" /><figcaption>Imagem retirada do portal NDP — Labs</figcaption></figure><h3>Processamento Assíncrono com Filas Priorizadas</h3><p>Todos os webhooks são processados em background. Quando um evento acontece, a requisição apenas enfileira a tarefa e retorna imediatamente. A entrega real acontece em workers paralelos.</p><p>Implementamos filas com prioridades: retentativas entram na fila de alta prioridade, webhooks novos na fila de prioridade média. Isso garante que entregas que falharam são reprocessadas antes de novos webhooks, sem bloquear o fluxo.</p><p>O sistema usa uma abstração (IWebhookJobPublisher) que permite trocar o backend de processamento via configuração, sem mudança de código, suportando <a href="https://dapr.io/">Dapr</a> com Redis Streams para cenários cloud-native e distribuídos.</p><h3>O Que Aprendemos</h3><p>Isolamento de dados não se negocia. No início, consideramos filtrar dados na camada de serviço. O risco ficou evidente rápido: bastaria um desenvolvedor esquecer um .Where() para expor dados de um cliente para outro. Mover o filtro para query filters do EF Core eliminou essa classe inteira de bugs, o isolamento acontece independentemente de quem escreve a query.</p><p>Assíncrono por padrão, sempre. Nas primeiras versões, tentamos enviar webhooks de forma síncrona durante a requisição. Bastou um endpoint de cliente demorar 10 segundos para responder e toda a cadeia travou. Background jobs com filas priorizadas resolveram o problema e tornaram o tempo de resposta da API previsível.</p><p>Retry inteligente resolve a maioria das falhas. Analisando os logs de produção, a grande maioria das falhas de entrega são transitórias, timeouts, 503s temporários, deploys do cliente. O backoff exponencial resolve esses casos automaticamente sem intervenção humana. O retry manual existe para os casos restantes.</p><p>Observabilidade não é opcional. Sem o histórico detalhado de entregas, cada investigação de “o webhook não chegou” seria uma caixa preta. Com status, tentativas, response codes e tempos registrados, o diagnóstico se torna objetivo.</p><h3>Testando Localmente</h3><p>Para experimentar webhooks durante o desenvolvimento, o <a href="https://webhook.site/">webhook.site</a> é uma ferramenta prática: gera URLs temporárias e mostra em tempo real todos os webhooks recebidos, incluindo headers e payload. É útil para validar assinaturas HMAC e estrutura de dados antes de integrar com o endpoint real.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*WEXHRK8QI00TsDHk7fB7tA.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*2SZODlMLgYFfTHr8_IZQCw.png" /></figure><h3>Conclusão</h3><p>Webhooks parecem simples na superfície, é um POST HTTP com um payload JSON. A complexidade real aparece quando você precisa garantir entrega, isolar dados entre clientes, autenticar payloads e dar visibilidade sobre o que está acontecendo.</p><p>Se você está construindo integrações entre sistemas, comece pelo caso mais simples e adicione camadas (retry, HMAC, observabilidade) conforme a necessidade real aparecer. Over-engineering no início custa caro; ausência dessas camadas em produção custa mais.</p><p>O sistema que construímos no Labs está pronto e segue em evolução.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e61cb4c7a790" width="1" height="1" alt=""><hr><p><a href="https://making.ndd.tech/seu-sistema-ainda-depende-de-polling-como-constru%C3%ADmos-webhooks-multitenant-no-labs-e61cb4c7a790">Seu Sistema Ainda Depende de Polling? Como construímos webhooks multitenant no Labs</a> was originally published in <a href="https://making.ndd.tech">nddtech</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Dependency-Track e SBOM: gestão de vulnerabilidades em dependências]]></title>
            <link>https://making.ndd.tech/dependency-track-e-sbom-gest%C3%A3o-de-vulnerabilidades-em-depend%C3%AAncias-27bd53c173ed?source=rss----c9197bc611ac---4</link>
            <guid isPermaLink="false">https://medium.com/p/27bd53c173ed</guid>
            <category><![CDATA[dependency-track]]></category>
            <category><![CDATA[tecnologia]]></category>
            <category><![CDATA[cloud-security]]></category>
            <category><![CDATA[cyber-security-tools]]></category>
            <category><![CDATA[security]]></category>
            <dc:creator><![CDATA[Wallace Maia]]></dc:creator>
            <pubDate>Wed, 25 Feb 2026 15:59:08 GMT</pubDate>
            <atom:updated>2026-02-25T15:59:06.641Z</atom:updated>
            <content:encoded><![CDATA[<p>Para agilizar o desenvolvimento de uma aplicação, é normal usar pacotes e bibliotecas prontas como da Microsoft, Google ou da comunidade open source. Isso economiza tempo, acelera entregas e, na prática, é um dos pilares do desenvolvimento moderno.</p><p>O ponto é que essas dependências viram parte do seu sistema. Se uma biblioteca fica desatualizada, é abandonada ou passa a ter falhas de segurança, a aplicação pode ficar exposta. E como surgem vulnerabilidades novas todos os dias, acompanhar isso manualmente não escala: vira um trabalho constante de “caça a CVE”, conferência em site, planilha, relatório… e, no final, pouca previsibilidade.</p><p>Para resolver isso, uma abordagem bem sólida é usar ferramentas como o Dependency-Track. A ideia é simples:</p><ol><li>Primeiro eu gero um SBOM do projeto</li><li>Depois eu uso o Dependency-Track para analisar esse SBOM de forma centralizada e contínua</li></ol><h3>O que é o Dependency-Track?</h3><p>O Dependency-Track é a ferramenta que eu uso para ter visão centralizada das dependências do projeto e do risco que elas trazem.</p><p>Você entrega para ele um SBOM (por exemplo no padrão CycloneDX) e ele transforma isso em algo prático: mostra quais bibliotecas o sistema usa e quais delas têm vulnerabilidades conhecidas, sem precisar ficar caçando informação em relatório, site ou planilha.</p><p>Na prática, ele serve para:</p><ul><li>Enxergar rapidamente o que está vulnerável em cada projeto;</li><li>Priorizar o que é mais crítico (o que precisa de ação primeiro);</li><li>Acompanhar ao longo do tempo se o risco foi resolvido conforme você atualiza versões e releases.</li></ul><h3>O que é o SBOM?</h3><p>SBOM é como um “rótulo de ingredientes” do software: ele lista tudo o que a aplicação usa (bibliotecas e versões), incluindo dependências transitivas quando a ferramenta consegue enxergar.</p><p>Para padronizar esse “rótulo”, existe o CycloneDX (CDX), que define um formato bem conhecido para SBOM. Uma forma simples de pensar é:</p><ul><li>SBOM é a ideia (a lista de componentes)</li><li>CycloneDX é o modelo (o formato) dessa lista, para que qualquer ferramenta consiga ler e interpretar do mesmo jeito</li></ul><p>Na prática, eles se complementam assim: eu gero o SBOM no formato CycloneDX e consigo integrar essa informação automaticamente em ferramentas como o Dependency-Track.</p><h3>Ganhos na prática</h3><ul><li>Visibilidade rápida do risco: em minutos eu sei quais projetos estão expostos e onde está o problema.</li><li>Menos ruído e mais organização: sai a dependência de planilhas, relatórios soltos e conferência manual.</li><li>Prioridade clara: fica fácil separar o que é crítico do que pode esperar.</li><li>Correção com mais confiança: quando atualizo uma biblioteca, consigo confirmar se o risco foi resolvido e manter um histórico do que mudou.</li></ul><h3>Como o Dependency-Track é utilizado na prática?</h3><p>A forma mais comum de usar o Dependency-Track no dia a dia é organizar por projeto e manter o SBOM sendo enviado automaticamente pelo CI/CD.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8NdJRUOKMu_jKTOw0-eG-A.png" /></figure><h3>Considerações finais</h3><p>Dependências são inevitáveis em software moderno e quando você passa a enxergar bibliotecas como parte do risco do produto, o SBOM deixa de ser burocracia e vira um ativo: ele registra exatamente o que está rodando em cada release.</p><p>O Dependency-Track entra como a peça que transforma esse registro em decisão: centraliza a visão, reduz o esforço de correlação manual e mantém histórico para responder perguntas que realmente importam. O maior ganho aparece quando isso vira rotina via CI/CD: toda entrega atualiza o SBOM, o risco é reavaliado automaticamente e o time consegue priorizar com base em severidade e impacto, não em sensação.</p><p>No fim, não é sobre ferramenta e sim sobre ter processo e rastreabilidade para tratar risco de dependências como parte do ciclo normal de entrega com previsibilidade, evidência e menos ruído.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=27bd53c173ed" width="1" height="1" alt=""><hr><p><a href="https://making.ndd.tech/dependency-track-e-sbom-gest%C3%A3o-de-vulnerabilidades-em-depend%C3%AAncias-27bd53c173ed">Dependency-Track e SBOM: gestão de vulnerabilidades em dependências</a> was originally published in <a href="https://making.ndd.tech">nddtech</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[DefectDojo: centralizando achados de segurança e mantendo histórico entre releases]]></title>
            <link>https://making.ndd.tech/defectdojo-centralizando-achados-de-seguran%C3%A7a-e-mantendo-hist%C3%B3rico-entre-releases-b24ebeaa6899?source=rss----c9197bc611ac---4</link>
            <guid isPermaLink="false">https://medium.com/p/b24ebeaa6899</guid>
            <category><![CDATA[tecnologia]]></category>
            <category><![CDATA[cloud-security]]></category>
            <category><![CDATA[semgrep]]></category>
            <category><![CDATA[security]]></category>
            <category><![CDATA[code-security]]></category>
            <dc:creator><![CDATA[Wallace Maia]]></dc:creator>
            <pubDate>Tue, 24 Feb 2026 11:24:39 GMT</pubDate>
            <atom:updated>2026-02-24T11:24:37.727Z</atom:updated>
            <content:encoded><![CDATA[<p>No dia a dia, é comum a empresa rodar várias análises de segurança: pentest, SAST, SCA, scan de containers, IaC, infraestrutura, secrets… O problema é que cada ferramenta fala um “idioma” e entrega um relatório diferente. No fim, as vulnerabilidades ficam espalhadas em PDFs, dashboards e artefatos de pipeline, muitas vezes se repetem e viram um volume difícil de priorizar, acompanhar e comprovar evolução.</p><p>E é aí que surge um tipo de dúvida que parece simples, mas costuma ser bem trabalhosa de responder:</p><p>Quando não existe um lugar único para consolidar tudo, o histórico se perde, o time perde tempo comparando saídas de scanners e a confiança no processo cai.</p><h3>Onde o DefectDojo entra</h3><p>Uma das opções mais sólidas para endereçar esse cenário é o DefectDojo. Pense nele como um painel único para centralizar achados: em vez de cada scanner gerar um relatório isolado (e ninguém saber por onde começar), você consolida tudo em um lugar só.</p><p>Na prática, o DefectDojo:</p><ul><li>importa resultados de várias fontes (SAST, DAST, SCA, container, IaC, secrets etc.)</li><li>organiza e reduz o ruído (duplicidades)</li></ul><p>O ganho principal é visibilidade: fica mais fácil enxergar o que é mais crítico, quem é o responsável, em qual produto/ambiente está o risco e o que já foi resolvido.</p><h3>O que você ganha na prática</h3><p>Com isso, podemos:</p><ul><li>Centralizar tudo em um único lugar, em vez de ficar analisando relatório por relatório;</li><li>Reduzir duplicidade e ruído, evitando que o mesmo problema apareça várias vezes como se fossem achados diferentes;</li><li>Priorizar com clareza, separando o que é crítico do que pode esperar;</li><li>Manter histórico por projeto e por versão, para saber o que entrou, o que foi tratado e o que continua pendente.</li></ul><p>E, no dia a dia, isso se traduz em:</p><ul><li>Visão única de vulnerabilidades por projeto/repositório;</li><li>Menos retrabalho com planilhas, PDFs e relatórios espalhados;</li><li>Correções mais certeiras, porque fica claro o que realmente importa e o que foi resolvido entre releases.</li></ul><h3>Relatórios de quais ferramentas eu consigo importar?</h3><p>O DefectDojo suporta diversas integrações e formatos de importação. A lista oficial (mantida pela comunidade) está aqui:</p><p><a href="https://docs.defectdojo.com/supported_tools/">DefectDojo — Ferramentas Suportadas</a></p><h3>Como o DefectDojo é usado na prática</h3><p>A forma mais comum de usar o DefectDojo no dia a dia é padronizar uma hierarquia e automatizar a entrada dos scans via CI/CD. Isso evita que o uso vire “manual demais” e garante consistência entre times.</p><h3>1) Estrutura inicial (uma vez por organização/produto)</h3><ol><li>Criar o Product Type<br> Uma categoria que agrupa produtos por domínio/vertical (ex.: Cargo​, Elog​, IP​). Aqui, um padrão bem prático é usar o nome da vertical como Product Type, já que cada vertical pode ter vários repositórios.</li><li>Criar o Product<br> Aqui é o “alvo” real que você quer gerenciar (ex.: nddCargo​, nddElog​, nddIP​). Um padrão que costuma facilitar muito é definir o nome do Product igual ao nome do repositório no TFS/Azure DevOps (ou Git), porque a busca e o vínculo com o projeto ficam óbvios.</li></ol><h3>2) Ciclo de trabalho (por release, sprint ou período)</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*7sWdFpni01dv_yYg_aqVIA.png" /></figure><h3>Como isso entra no CI/CD</h3><p>O fluxo mais comum fica bem objetivo:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*IOgE-Toy_5zPdyuzBwdDxA.png" /></figure><h3>Considerações finais</h3><p>O DefectDojo não “resolve segurança” sozinho, ele resolve um problema bem específico e muito comum: falta de centralização e rastreabilidade. Quando cada ferramenta gera um relatório isolado, o time perde tempo correlacionando achados, lidando com duplicidade e tentando provar evolução entre releases. Ao consolidar tudo em um único lugar, você transforma resultados soltos em dados concretos.</p><p>O maior ganho aparece quando o uso é consistente e automatizado. Padronizar a hierarquia (Product Type -&gt; Product -&gt; Engagement) e enviar os scans pelo CI/CD faz com que o histórico deixe de depender de memória, planilha ou artefatos de pipelines.</p><p>No fim, a ferramenta vira mais valiosa quando é tratada como parte do processo: menos ruído, mais previsibilidade e um backlog de segurança mais claro, alinhado com a realidade do desenvolvimento e com o ritmo de entregas do time.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b24ebeaa6899" width="1" height="1" alt=""><hr><p><a href="https://making.ndd.tech/defectdojo-centralizando-achados-de-seguran%C3%A7a-e-mantendo-hist%C3%B3rico-entre-releases-b24ebeaa6899">DefectDojo: centralizando achados de segurança e mantendo histórico entre releases</a> was originally published in <a href="https://making.ndd.tech">nddtech</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Terraform no Azure com Terragrunt: menos repetição, mais previsibilidade]]></title>
            <link>https://making.ndd.tech/terraform-no-azure-com-terragrunt-menos-repeti%C3%A7%C3%A3o-mais-previsibilidade-c87f5e4d4c65?source=rss----c9197bc611ac---4</link>
            <guid isPermaLink="false">https://medium.com/p/c87f5e4d4c65</guid>
            <category><![CDATA[terraform]]></category>
            <category><![CDATA[tecnologia]]></category>
            <category><![CDATA[ansible]]></category>
            <category><![CDATA[devops]]></category>
            <category><![CDATA[iac]]></category>
            <dc:creator><![CDATA[Wallace Maia]]></dc:creator>
            <pubDate>Mon, 23 Feb 2026 12:44:38 GMT</pubDate>
            <atom:updated>2026-02-23T12:44:36.638Z</atom:updated>
            <content:encoded><![CDATA[<p>No Azure, criar recursos “na mão” pelo portal parece rápido no começo. Você abre o portal, cria uma VNET, sobe uma VM, ajusta uma NSG… e em poucos minutos tudo está “de pé”.</p><p>O problema aparece quando essa infraestrutura vira rotina.</p><p>Quando você precisa repetir o mesmo desenho em outro ambiente (dev/hml/prod), manter padrões, auditar “quem mudou o quê” e recriar tudo com segurança (especialmente em POCs que nascem e morrem o tempo todo), o portal começa a virar um gargalo. A cada ajuste feito “só aqui”, os ambientes inevitavelmente divergem. E, quando você percebe, a diferença entre dev e prod não é mais “configuração”: virou um conjunto de decisões implícitas que ninguém consegue explicar direito.</p><p>É aqui que Terraform muda o jogo. E, quando o projeto cresce, Terragrunt entra como uma camada que resolve um problema muito específico: reduzir repetição, organizar estados e padronizar ambientes sem você copiar e colar providers.tf​, backend.tf​, versions.tf​ em todo lugar.</p><h3>Infraestrutura como código (de verdade)</h3><p>A ideia continua simples: infraestrutura vira código.</p><p>Em vez de clicar no portal, você descreve o que precisa existir rede, AKS, Key Vault, ACR, VMs, discos e aplica isso de forma padronizada e rastreável.</p><p>O ganho real de IaC não é “criar mais rápido”. É:</p><ul><li>eliminar drift (a divergência silenciosa entre ambientes)</li><li>dar previsibilidade (a mesma entrada gera o mesmo resultado)</li><li>criar histórico confiável (git + revisão + rastreabilidade)</li><li>reduzir risco em mudanças (plan antes do apply, revisão antes do merge)</li></ul><p>O ponto é que, com o tempo, o desafio deixa de ser “escrever Terraform” e passa a ser “manter dezenas de stacks consistentes”. E é justamente aí que Terragrunt brilha.</p><h3>Por que Terragrunt entra na conversa</h3><p>Terragrunt não substitui Terraform. Ele organiza o uso do Terraform.</p><p>Na prática, ele resolve três dores comuns em ambientes Azure que crescem rápido:</p><ul><li>​DRY de verdade​: você para de repetir provider/backend/versions em toda stack.</li><li>​Estados bem organizados​: um state por componente, com naming consistente.</li><li>​Orquestração por dependências​: você aplica infraestrutura em ordem (e com segurança) usando outputs como contratos.</li></ul><p>O resultado é uma estrutura que escala melhor quando você começa a ter fundação, plataforma e workloads evoluindo ao mesmo tempo.</p><h3>Exemplo prático: DefectDojo e Dependency-Track (infra + banco)</h3><p>Ao implantar DefectDojo e ​Dependency-Track​, existe uma base mínima no Azure antes da aplicação em si:</p><ul><li>Resource Group</li><li>Rede (VNET, subnets, NSGs)</li><li>VM Linux dedicada para PostgreSQL</li><li>Public IP / DNS (quando necessário)</li><li>Storage</li><li>AKS</li></ul><p>Com Terraform + Terragrunt, isso vira um fluxo claro:</p><ol><li>Provisiona a infraestrutura base (rede, compute, storage, AKS).</li><li>Entra o Ansible para instalar e configurar o PostgreSQL (extensões, parâmetros, acesso, bancos e usuários).</li><li>A camada de aplicação vem depois (Helm, manifests, pipelines), consumindo outputs e secrets de forma padronizada.</li></ol><p>A divisão de responsabilidades continua objetiva:</p><ul><li>​Terraform​: ciclo de vida da infraestrutura e estado.</li><li>​Terragrunt​: organização, padronização, backends, inputs por ambiente e dependências.</li><li>​Ansible​: configuração do sistema e do software de forma idempotente.</li></ul><h3>Organização do repositório: módulos e stacks (com Terragrunt)</h3><p>Uma organização prática e escalável separa:</p><ul><li>o que é reutilizável (módulos Terraform)</li><li>do que é específico de ambiente (stacks com Terragrunt)</li></ul><p>A lógica lembra a separação entre “código reutilizável” e “orquestração”.</p><h3>Estrutura base (exemplo)</h3><pre>infra/<br>├── catalog/<br>│   └── modules/<br>│       ├── azurerm_resource_group/<br>│       ├── azurerm_virtual_network/<br>│       ├── azurerm_subnet/<br>│       ├── azurerm_public_ip/<br>│       ├── azurerm_network_interface/<br>│       ├── azurerm_linux_virtual_machine/<br>│       ├── azurerm_managed_disk/<br>│       ├── azurerm_key_vault/<br>│       ├── azurerm_storage_account/<br>│       ├── azurerm_container_registry/<br>│       └── azurerm_kubernetes/<br>│<br>└── stacks/<br>    └── nde/<br>        ├── root.hcl<br>        ├── env.hcl<br>        ├── dev/<br>        │   ├── foundation/<br>        │   │   └── network/<br>        │   │       └── terragrunt.hcl<br>        │   ├── platform/<br>        │   │   └── keyvault/<br>        │   │       └── terragrunt.hcl<br>        │   └── workloads/<br>        │       └── defectdojo/<br>        │           ├── compute/<br>        │           │   └── terragrunt.hcl<br>        │           └── aks/<br>        │               └── terragrunt.hcl<br>        ├── hml/<br>        │   └── ...<br>        └── prd/<br>            └── ...</pre><h3>Como ler essa estrutura</h3><p>catalog/modules/<br> Módulos Terraform reutilizáveis. Pequenos, com contrato claro (inputs/outputs), fáceis de versionar e reaproveitar.</p><p>stacks/<br> O “live” do Terragrunt: cada pasta representa uma unidade de execução com seu próprio terragrunt.hcl​ apontando para um módulo e definindo inputs, dependências e estado.</p><p>root.hcl / env.hcl<br> Arquivos de “configuração base” que evitam repetição: backend, provider, tags, naming, subscription/tenant, padrões de rede e qualquer coisa compartilhada.</p><h3>O coração do Terragrunt: herança e padrão de state</h3><p>Uma prática que funciona muito bem é ter um root.hcl​ com:</p><ul><li>​remote_state​ centralizado (Azure Storage)</li><li>​generate​ para provider e versões</li><li>padrões comuns (tags, naming, features)</li><li>convenções para o key do state baseado no caminho</li></ul><p>Exemplo de root.hcl​:</p><pre>locals {<br>  project = &quot;nde&quot;<br>}</pre><pre>remote_state {<br>  backend = &quot;azurerm&quot;<br>  config = {<br>    resource_group_name  = &quot;rg-tfstate&quot;<br>    storage_account_name = &quot;sttfstateprod001&quot;<br>    container_name       = &quot;tfstate&quot;<br>    key                  = &quot;${path_relative_to_include()}/terraform.tfstate&quot;<br>  }<br>}</pre><pre>generate &quot;provider&quot; {<br>  path      = &quot;provider.tf&quot;<br>  if_exists = &quot;overwrite_terragrunt&quot;<br>  contents  = &lt;&lt;EOF<br>provider &quot;azurerm&quot; {<br>  features {}<br>}<br>EOF<br>}</pre><pre>generate &quot;versions&quot; {<br>  path      = &quot;versions.tf&quot;<br>  if_exists = &quot;overwrite_terragrunt&quot;<br>  contents  = &lt;&lt;EOF<br>terraform {<br>  required_version = &quot;&gt;= 1.6.0&quot;<br>  required_providers {<br>    azurerm = {<br>      source  = &quot;hashicorp/azurerm&quot;<br>      version = &quot;&gt;= 3.0.0&quot;<br>    }<br>  }<br>}<br>EOF<br>}</pre><p>E um env.hcl​ para variáveis do ambiente:</p><pre>locals {<br>  location    = &quot;eastus&quot;<br>  environment = &quot;dev&quot;<br>  tags = {<br>    env     = &quot;dev&quot;<br>    project = &quot;nde&quot;<br>  }<br>}</pre><h3>Uma stack por componente (e estados pequenos)</h3><p>No Terragrunt, cada pasta com terragrunt.hcl​ normalmente representa:</p><ul><li>um módulo Terraform</li><li>um state isolado</li><li>uma unidade que faz sentido evoluir e aplicar separadamente</li></ul><p>Isso ajuda muito quando você precisa:</p><ul><li>reaplicar só um pedaço</li><li>dar rollback com menor blast radius</li><li>evoluir rede e compute em ritmos diferentes</li><li>reduzir tempo de plan/apply</li></ul><h3>Dependências como contratos (sem acoplamento implícito)</h3><p>Quando uma stack depende de outra, Terragrunt permite consumir outputs como contrato explícito.</p><p>Exemplo: o AKS depende da rede.</p><p>​stacks/nde/dev/foundation/network/terragrunt.hcl​:</p><pre>include &quot;root&quot; {<br>  path = find_in_parent_folders(&quot;root.hcl&quot;)<br>}</pre><pre>locals {<br>  env = read_terragrunt_config(find_in_parent_folders(&quot;env.hcl&quot;)).locals<br>}</pre><pre>terraform {<br>  source = &quot;${get_repo_root()}//catalog/modules/azurerm_virtual_network&quot;<br>}</pre><pre>inputs = {<br>  location = local.env.location<br>  tags     = local.env.tags<br>}</pre><p>​stacks/nde/dev/workloads/defectdojo/aks/terragrunt.hcl​:</p><pre>include &quot;root&quot; {<br>  path = find_in_parent_folders(&quot;root.hcl&quot;)<br>}</pre><pre>locals {<br>  env = read_terragrunt_config(find_in_parent_folders(&quot;env.hcl&quot;)).locals<br>}</pre><pre>dependency &quot;network&quot; {<br>  config_path = &quot;../../../foundation/network&quot;<br>}</pre><pre>terraform {<br>  source = &quot;${get_repo_root()}//catalog/modules/azurerm_kubernetes&quot;<br>}</pre><pre>inputs = {<br>  location      = local.env.location<br>  tags          = local.env.tags<br>  subnet_id     = dependency.network.outputs.snet_aks_id<br>}</pre><p>Isso evita o “estado mental” de lembrar IDs na mão, evita terraform_remote_state​ espalhado e deixa a ordem de execução explícita.</p><h3>Executando por camadas com segurança</h3><p>Com Terragrunt, você consegue aplicar por nível:</p><ul><li>​foundation​ primeiro</li><li>depois platform​</li><li>depois workloads​</li></ul><p>E consegue fazer isso com:</p><ul><li>​terragrunt run-all plan​</li><li>​terragrunt run-all apply​</li></ul><p>Cada componente com seu state, e as dependências guiando a ordem quando necessário.</p><h3>Ambientes (dev / hml / prd) sem workspaces</h3><p>O padrão mais previsível continua sendo:</p><ul><li>pastas separadas por ambiente</li><li>mesmo código, inputs diferentes</li><li>state isolado por ambiente</li><li>backend padronizado e automático</li></ul><p>Isso reduz muito o risco de “aplicar no lugar errado” e facilita auditoria e rollback.</p><h3>O que foi configurado para DefectDojo e Dependency-Track</h3><p>Para essas duas aplicações, normalmente precisamos de:</p><ul><li>bancos dedicados (ex.: defectdojo​, dependencytrack​)</li><li>usuários dedicados para cada aplicação</li><li>permissões corretas</li><li>ajustes e acesso (ex.: pg_hba.conf​, listen_addresses​, parâmetros)</li></ul><p>Com Terraform + Terragrunt, a infraestrutura que suporta isso vira padrão. Com Ansible, a configuração do PostgreSQL vira código versionado. Se amanhã precisar recriar tudo, o processo deixa de depender de “memória” e vira execução.</p><h3>Ganhos na prática</h3><p>Os ganhos mais claros ao organizar Terraform com Terragrunt foram:</p><ul><li>menos repetição de arquivos e configurações entre stacks</li><li>estados menores, mais rápidos de planejar e aplicar</li><li>padronização forte entre ambientes</li><li>dependências explícitas via outputs (contratos claros)</li><li>execução por camadas, com menos risco</li><li>reuso real: mesmos módulos, inputs por ambiente</li></ul><h3>Resumo final</h3><p>Terraform resolve o “o que” da infraestrutura. Terragrunt resolve o “como manter isso organizado” quando o ambiente cresce.</p><p>No caso de DefectDojo e ​Dependency-Track​, essa combinação ajudou a criar uma base consistente no Azure rede, compute, storage e AKS e permitiu recriar ambientes em minutos, algo essencial em POCs e ciclos de teste frequentes. No fim, a infraestrutura fica mais previsível, o estado fica mais controlado e o repositório deixa de virar uma coleção de arquivos repetidos.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c87f5e4d4c65" width="1" height="1" alt=""><hr><p><a href="https://making.ndd.tech/terraform-no-azure-com-terragrunt-menos-repeti%C3%A7%C3%A3o-mais-previsibilidade-c87f5e4d4c65">Terraform no Azure com Terragrunt: menos repetição, mais previsibilidade</a> was originally published in <a href="https://making.ndd.tech">nddtech</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Ansible: ganhos de escala ao automatizar a configuração de servidores]]></title>
            <link>https://making.ndd.tech/ansible-ganhos-de-escala-ao-automatizar-a-configura%C3%A7%C3%A3o-de-servidores-a5052f0a6d9b?source=rss----c9197bc611ac---4</link>
            <guid isPermaLink="false">https://medium.com/p/a5052f0a6d9b</guid>
            <category><![CDATA[terraform]]></category>
            <category><![CDATA[devops]]></category>
            <category><![CDATA[ansible]]></category>
            <category><![CDATA[iac]]></category>
            <category><![CDATA[devops-tools-technologies]]></category>
            <dc:creator><![CDATA[Wallace Maia]]></dc:creator>
            <pubDate>Wed, 14 Jan 2026 14:31:41 GMT</pubDate>
            <atom:updated>2026-01-14T14:31:39.355Z</atom:updated>
            <content:encoded><![CDATA[<p>Configurar servidor manualmente funciona quando é um ou dois. Quando isso vira dezenas ou quando você precisa repetir a mesma configuração em vários ambientes a conta simplesmente não fecha. Cada máquina acaba ficando “de um jeito”, qualquer ajuste vira uma tarefa demorada, sujeita a erro e difícil de auditar. O resultado é conhecido: inconsistência entre servidores, tempo perdido com trabalho repetitivo e pouca previsibilidade.</p><p>O Ansible costuma ser uma das soluções mais diretas e eficientes para esse cenário. A ideia é simples: você descreve o estado desejado do servidor pacotes, configurações, serviços e permissões e o Ansible aplica isso de forma automática e padronizada em todos os alvos. Assim, você deixa de acessar servidor por servidor para repetir o mesmo roteiro manualmente.</p><h3>Como o Ansible é utilizado na prática?</h3><p>Na prática, o Ansible entra quando você quer transformar uma configuração feita “na mão acessar a VM, instalar pacotes, editar arquivos, reiniciar serviços em um processo ​repetível, versionado e consistente​.</p><p>Em vez de cada ambiente ser configurado de forma diferente, você descreve o estado desejado em playbooks e ​roles​, versiona isso em um repositório e executa sempre que precisar, em qualquer servidor que siga o padrão do inventário.</p><p>Um exemplo real é a implantação de ferramentas como DefectDojo e ​Dependency-Track​. Para colocar essas aplicações em produção com estabilidade, foi necessário preparar um PostgreSQL completo: bancos, usuários, permissões, parâmetros de performance e acesso remoto. Esse é exatamente o tipo de tarefa que o Ansible resolve bem: instalar e manter o banco de forma padronizada, reproduzível e rápida.</p><p>Se, em outro momento, a equipe precisar aplicar a mesma automação em um novo ambiente por exemplo, criar uma nova VM de PostgreSQL para outro projeto basta apontar o inventário e executar. Em poucos minutos, o banco está pronto, seguindo o mesmo padrão.</p><h3>Exemplo: configurando PostgreSQL com Ansible (visão prática)</h3><p>Quando você prepara um PostgreSQL manualmente, o fluxo costuma ser mais ou menos assim:</p><ol><li>Instalar o PostgreSQL no servidor</li><li>Criar o banco e o usuário da aplicação</li><li>Ajustar permissões e parâmetros do servidor</li><li>Liberar acesso de rede (pg_hba.conf​)</li><li>Reiniciar o serviço</li><li>Validar a conexão</li></ol><p>Com Ansible, esses passos deixam de ser um “checklist humano e viram uma execução única, automatizada e previsível.</p><h3>Estrutura básica</h3><p>Uma organização simples e que escala bem separa claramente as responsabilidades dentro de um projeto Ansible:</p><ul><li>inventories/<br> Lista os servidores por ambiente (dev​, hml​, prod​) e concentra variáveis associadas a hosts e grupos.</li><li>playbooks/<br> Orquestram a execução: definem o que será aplicado, em quais hosts e em qual ordem.</li><li>roles/<br> Contêm automações reutilizáveis, organizadas por domínio técnico, como a role de PostgreSQL.</li></ul><p>Essa separação facilita a leitura, reduz acoplamento e torna a automação mais previsível conforme o projeto cresce.</p><h3>Modelo mental aplicado à role de PostgreSQL</h3><p>Dentro da role de PostgreSQL, ajuda muito pensar em responsabilidades bem definidas, executadas de forma ordenada. Um modelo mental simples é dividir a automação internamente em etapas como:</p><ul><li>Instalação e configuração do serviço</li><li>Criação de bancos, usuários e permissões</li><li>​Ajustes de performance e tuning​, como max_connections​ e shared_buffers​</li><li>​Configuração de acesso​, incluindo pg_hba.conf​ e listen_addresses​</li></ul><p>Essas etapas não são papéis separados, mas ​camadas internas da mesma role​, o que mantém o controle de estado do serviço centralizado e consistente.</p><h3>Estrutura de pastas (exemplo)</h3><pre>roles/<br>└── postgresql/<br>    ├── defaults/<br>    │   └── main.yml<br>    ├── vars/<br>    │   └── main.yml<br>    ├── handlers/<br>    │   └── main.yml<br>    ├── templates/<br>    │   ├── postgresql.conf.j2<br>    │   └── pg_hba.conf.j2<br>    ├── files/<br>    ├── tasks/<br>    │   ├── main.yml<br>    │   ├── install.yml<br>    │   ├── service.yml<br>    │   ├── config.yml<br>    │   ├── access.yml<br>    │   ├── databases.yml<br>    │   └── tuning.yml<br>    └── meta/<br>        └── main.yml</pre><h3>Visão geral da estrutura</h3><ul><li>inventories/<br> Definem os ambientes e centralizam variáveis por grupo, permitindo diferenças controladas entre dev​, hml​ e prod​.</li><li>playbooks/<br> Funcionam como ponto de entrada da automação, chamando a role correta para os hosts adequados.</li><li>roles/<br> Encapsulam toda a lógica necessária para gerenciar um serviço específico, de forma organizada e reutilizável.</li></ul><h3>Dentro da role</h3><ul><li>defaults/<br> Contêm valores padrão das variáveis, pensados para serem sobrescritos por ambiente quando necessário.</li><li>tasks/<br> Implementam as etapas da automação, separadas por responsabilidade para facilitar manutenção e evolução.</li><li>handlers/<br> Definem ações reativas, como restart ou reload do serviço, executadas apenas quando algo realmente muda.</li></ul><h3>O que foi configurado para DefectDojo e Dependency-Track</h3><p>Para essas duas aplicações, normalmente foi necessário configurar:</p><ul><li>​Bancos dedicados​, como defectdojo​ e dependencytrack​</li><li>Usuários dedicados para cada aplicação</li><li>Permissões corretas nos schemas</li><li>Ajustes de acesso e configuração (pg_hba.conf​, listen_addresses​, parâmetros do PostgreSQL)</li></ul><p>Com Ansible, tudo isso vira código versionado. Se amanhã for preciso recriar o ambiente, basta executar o playbook e o banco sai exatamente igual, sem depender de memória, anotações soltas ou procedimentos manuais.</p><h3>Ganhos na prática</h3><p>Os principais benefícios de automatizar a camada de PostgreSQL com Ansible foram:</p><ul><li>Possibilidade de reaplicar a configuração sempre que necessário</li><li>Redução drástica do tempo de setup e ajustes</li><li>​Menos incidentes​, graças à consistência entre servidores</li><li>​Escala com controle​, mesmo com muitos ambientes</li><li>Menos erros manuais e menos variação entre máquinas</li><li>Mais agilidade na implantação de aplicações</li><li>​Documentação viva​, onde o código mostra exatamente o que foi feito</li></ul><h3>Resumo final</h3><p>No caso do DefectDojo e do ​Dependency-Track​, o Ansible foi essencial para preparar um PostgreSQL consistente com bancos, usuários, permissões e acesso configurados garantindo que o ambiente pudesse ser recriado em minutos sempre que necessário. Isso foi especialmente importante porque o projeto começou como uma ​POC​, exigindo recriações frequentes para testes e ajustes.</p><p>Com inventários, playbooks e roles bem organizados, o resultado é um processo mais rápido, confiável e versionado. No fim, o próprio código se torna a melhor documentação do ambiente.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a5052f0a6d9b" width="1" height="1" alt=""><hr><p><a href="https://making.ndd.tech/ansible-ganhos-de-escala-ao-automatizar-a-configura%C3%A7%C3%A3o-de-servidores-a5052f0a6d9b">Ansible: ganhos de escala ao automatizar a configuração de servidores</a> was originally published in <a href="https://making.ndd.tech">nddtech</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Pipelines C.I e C.D padronizados com templates: menos YAML duplicado, mais velocidade para evoluir]]></title>
            <link>https://making.ndd.tech/pipelines-c-i-e-c-d-padronizados-com-templates-menos-yaml-duplicado-mais-velocidade-para-evoluir-3ac38bd0ed58?source=rss----c9197bc611ac---4</link>
            <guid isPermaLink="false">https://medium.com/p/3ac38bd0ed58</guid>
            <category><![CDATA[ci-cd-pipeline]]></category>
            <category><![CDATA[yml-pipelines]]></category>
            <category><![CDATA[devops-practice]]></category>
            <category><![CDATA[azure-devops]]></category>
            <category><![CDATA[devops]]></category>
            <dc:creator><![CDATA[Wallace Maia]]></dc:creator>
            <pubDate>Wed, 14 Jan 2026 14:30:41 GMT</pubDate>
            <atom:updated>2026-01-14T14:30:39.876Z</atom:updated>
            <content:encoded><![CDATA[<p>No começo, cada repositório tem seu pipeline “do seu jeito”. Em time pequeno, isso até funciona: o objetivo é entregar, e o YAML que roda já parece suficiente.</p><p>O problema aparece quando o empresa/projeto cresce e você passa a ter dezenas (ou centenas) de repositórios. De repente, você tem o cenário clássico:</p><ul><li>etapas parecidas em todo lugar (build, testes, scans, publish, deploy)</li><li>implementadas com pequenas variações</li><li>copiadas e coladas ao longo do tempo</li><li>sem um padrão claro além do “funciona”</li></ul><p>O resultado é previsível: manutenção difícil, copy/paste infinito e mudanças simples virando trabalho duplicado. Pior ainda quando o time precisa ajustar o processo de CI (trocar tecnologia, mudar etapa de build/test/scan, alterar padrão de deploy): você acaba entrando repositório por repositório para corrigir pipeline, gerando commits de “ajuste de infraestrutura” misturados com o código da aplicação.</p><p>Para evitar isso, eu gosto de trabalhar com um princípio simples: o repositório da aplicação não deveria “conter” o pipeline completo. Ele deveria apenas “consumir” um pipeline padrão.</p><p>A abordagem é separar a “infra de pipeline” em um repositório central e dividir a responsabilidade em templates por etapa. O projeto consumidor só chama esses templates e passa parâmetros.</p><p>Com isso, podemos:</p><ul><li>Reutilizar etapas, evitando duplicação de YAML.</li><li>Padronizar o processo, para todo projeto seguir o mesmo fluxo.</li><li>Evoluir rápido, porque uma melhoria no template vale para todos.</li><li>Reduzir falhas, pois o pipeline fica previsível e revisado.</li></ul><h3>Benefícios</h3><ul><li>Menos retrabalho e menos copy/paste entre repositórios.</li><li>Pipelines consistentes, fáceis de manter e de auditar.</li><li>Mudanças mais rápidas, com melhoria centralizada nos templates (uma mudança, impacto em todos).</li></ul><h3>Como os templates são utilizados na prática?</h3><p>O time de engenharia vem trabalhando forte em ferramentas e padrões de segurança para facilitar a vida dos times de DevOps nas verticais. Para isso, foram desenhados templates que padronizam o processo e aceleram migrações, reduzindo retrabalho e evitando variações desnecessárias entre repositórios.</p><p>Aqui vou usar o NDE como exemplo para mostrar como montar um repositório de templates e pipelines e como reutilizá-los no dia a dia.</p><h3>1) Criando o repositório central de DevOps</h3><p>A ideia é ter um repositório único para concentrar tudo que é “infra de pipeline”: pipelines, templates, stages, steps, scripts auxiliares e documentação rápida. O objetivo é reduzir a manutenção para um lugar só e evitar espalhar YAML por vários repositórios.</p><p>Exemplos de nome: devsecops​, devops-pipelines​, templates-pipelines​.</p><h3>2) Organizando pastas e templates</h3><p>Essa parte tem gosto pessoal, mas um modelo que costuma funcionar bem é separar por:</p><ul><li>projeto/domínio (quando você tem variações relevantes)</li><li>tipo de pipeline (CI e CD)</li><li>nível de abstração (stages vs step templates)</li></ul><p>Duas regras práticas que ajudam muito:</p><ul><li>Stage = macro fluxo (source, build, tests, security, publish, deploy)</li><li>Step template = micro padrão (“install tool”, “run scan”, “publish artifact”), usado dentro de jobs/stages</li></ul><p>Exemplo de estrutura objetiva:</p><pre>devops-pipelines/<br>└── pipelines/<br>    ├── NOME_DO_PROJETO/<br>    │   ├── ci/<br>    │   │   ├── default.yml<br>    │   │   └── stages/<br>    │   │       ├── 01-source-stage.yml<br>    │   │       ├── 02-build-stage.yml<br>    │   │       ├── 03-tests-stage.yml<br>    │   │       ├── 04-security-stage.yml<br>    │   │       └── 05-publish-stage.yml<br>    │   └── cd/<br>    │       ├── default.yml<br>    │       └── stages/<br>    │           ├── 01-deploy-stage.yml<br>    │           └── 02-smoke-stage.yml<br>    ├── templates/<br>    │   ├── build/<br>    │   ├── deploy/<br>    │   └── scans/<br>    └── scripts/</pre><h3>3) Criando um pipeline default do projeto (CI)</h3><p>O default.yml​ é o arquivo que descreve o CI completo chamando os stages.</p><p>Exemplo pipelines/default/ci/default.yml​:</p><pre>stages:<br>- template: stages/01-source-stage.yml<br>  parameters:<br>    agentOS: Linux</pre><p>A partir daqui, o pipeline “principal” fica pequeno e estável: ele só monta a orquestração. O detalhe de cada etapa vive nos templates de stage e step.</p><h3>4) Exemplo de stage template (Source)</h3><p>Exemplo pipelines/default/ci/stages/01-source-stage.yml​:</p><pre>parameters:<br>- name: agentOS<br>  type: string</pre><pre>stages:<br>- stage: SourceStage<br>  displayName: &#39;01 - Source Analysis&#39;<br>  jobs:<br>  - job: SourceScans<br>    displayName: &#39;Run source security scans&#39;<br>    steps:<br>    - template: /templates/scans/install-nde.yml@ndetemplates<br>      parameters:<br>        feedToken: &#39;$(NDE_FEED_TOKEN)&#39;<br>        agentOS: ${{ parameters.agentOS }}</pre><pre>    - template: /templates/scans/nde-gitleaks.yml@ndetemplates<br>      parameters:<br>        outputDir: &#39;$(Build.ArtifactStagingDirectory)/reports&#39;<br>        target: &#39;$(Build.SourcesDirectory)&#39;<br>        outputType: &#39;json&#39;<br>        ddUrl: &#39;$(DD_URL)&#39;<br>        ddKey: &#39;$(DD_TOKEN)&#39;<br>        engagementId: &#39;$(DD_ENGAGEMENT_ID)&#39;<br>        agentOS: ${{ parameters.agentOS }}</pre><pre>    - template: /templates/scans/nde-trivy.yml@ndetemplates<br>      parameters:<br>        outputDir: &#39;$(Build.ArtifactStagingDirectory)/reports&#39;<br>        target: &#39;$(Build.SourcesDirectory)&#39;<br>        outputType: &#39;json&#39;<br>        cacheDir: &#39;$(Pipeline.Workspace)/.cache_nde&#39;<br>        ddUrl: &#39;$(DD_URL)&#39;<br>        ddKey: &#39;$(DD_TOKEN)&#39;<br>        engagementId: &#39;$(DD_ENGAGEMENT_ID)&#39;<br>        agentOS: ${{ parameters.agentOS }}</pre><pre>    - template: /templates/scans/nde-semgrep.yml@ndetemplates<br>      parameters:<br>        outputDir: &#39;$(Build.ArtifactStagingDirectory)/reports&#39;<br>        target: &#39;$(Build.SourcesDirectory)&#39;<br>        outputType: &#39;json&#39;<br>        ddUrl: &#39;$(DD_URL)&#39;<br>        ddKey: &#39;$(DD_TOKEN)&#39;<br>        engagementId: &#39;$(DD_ENGAGEMENT_ID)&#39;<br>        agentOS: ${{ parameters.agentOS }}</pre><p>Note que, em cada template, aparece o sufixo @ndetemplates​. Isso indica que o template está vindo de um repositório de templates referenciado via resources.repositories​.</p><h3>5) Consumindo os templates em outro repositório (na prática)</h3><p>No repositório da vertical (ex.: nddCargo​), você não copia templates. Você referencia o repositório central e “puxa” o pipeline pronto.</p><p>Exemplo pipelines/ci.yml​ no repositório consumidor:</p><pre>trigger:<br>- master</pre><pre>variables:<br>- group: NDE-Settings</pre><pre>resources:<br>  repositories:<br>  - repository: ndetemplates<br>    type: git<br>    name: NDE/devsecops<br>    ref: master<br>    endpoint: ndetemplates</pre><pre>  - repository: templates<br>    type: git<br>    name: devsecops<br>    ref: main</pre><pre>stages:<br>- template: pipelines/default/ci/default.yml@templates</pre><p>Pontos de atenção que normalmente evitam dor:</p><ul><li>Se ndetemplates​ estiver em outra collection/projeto, é comum precisar configurar um Service Connection no projeto consumidor e referenciar em endpoint​.</li><li>Centralizar configurações em um Variable Group (ex.: NDE-Settings​) reduz duplicação e mantém o pipeline do projeto mais limpo. Exemplos de variáveis: DD_URL​, DD_TOKEN​, DD_ENGAGEMENT_ID​.</li><li>Os templates de scan ficam no repositório ndetemplates​, e o pipeline “montador” (default/stages) fica no repositório templates​. Essa separação permite evoluir componentes independentemente, quando fizer sentido.</li></ul><h3>Considerações finais</h3><p>Esse modelo muda o jogo principalmente por um motivo: ele separa o que é código de produto do que é infra de entrega. O repositório da aplicação volta a ter um pipeline “leve”, enquanto a evolução do processo (build, testes, scans, publish e deploy) acontece em um lugar único, com revisão, padrão e controle.</p><p>Na prática, você troca o “cada repo faz do seu jeito” por um fluxo previsível, onde:</p><ul><li>melhorias viram mudança centralizada, não uma maratona de PRs em dezenas de repositórios;</li><li>o time consegue padronizar sem engessar, porque os templates aceitam parâmetros e variações controladas;</li><li>auditoria e manutenção ficam mais simples, já que o pipeline deixa de ser uma colcha de retalhos.</li></ul><p>No fim, o ganho não é só reduzir YAML duplicado. É ganhar escala com governança: evoluir rápido, sem perder consistência, e com uma base que permite melhorar continuamente sem quebrar o ecossistema de repositórios.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3ac38bd0ed58" width="1" height="1" alt=""><hr><p><a href="https://making.ndd.tech/pipelines-c-i-e-c-d-padronizados-com-templates-menos-yaml-duplicado-mais-velocidade-para-evoluir-3ac38bd0ed58">Pipelines C.I e C.D padronizados com templates: menos YAML duplicado, mais velocidade para evoluir</a> was originally published in <a href="https://making.ndd.tech">nddtech</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Kubernetes no ambiente local]]></title>
            <link>https://making.ndd.tech/kubernetes-no-ambiente-local-fc58cf815497?source=rss----c9197bc611ac---4</link>
            <guid isPermaLink="false">https://medium.com/p/fc58cf815497</guid>
            <category><![CDATA[kubernetes]]></category>
            <category><![CDATA[tecnologia]]></category>
            <category><![CDATA[desenvolvimento]]></category>
            <dc:creator><![CDATA[William Passig]]></dc:creator>
            <pubDate>Tue, 23 Dec 2025 00:51:00 GMT</pubDate>
            <atom:updated>2025-12-23T00:50:59.457Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*hh3sY08T4JpjU_7eNMi3ug.png" /></figure><h3><strong>Kubernetes (K8s)</strong></h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*K5GMlbO0fKuuFzo66jqujQ.png" /></figure><p>Kubernetes, também conhecido como K8s, é um sistema open source utilizado para automatizar a implantação, o dimensionamento e o gerenciamento de aplicativos em contêiner.</p><p>Por ser open source, existe a liberdade de utilizar o K8s em seu próprio cluster local, em uma arquitetura híbrida ou em qualquer provedor público de computação em nuvem, permitindo que você mova sem esforço suas aplicações para onde quiser.</p><p>Na nuvem, costumamos trabalhar com o AKS (Azure Kubernetes Service) aqui na NDD, mas existem outras alternativas como GKE (Google Kubernetes Engine) e EKS (Amazon Elastic Kubernetes Service). Embora o uso dessa ferramenta integrada na nuvem seja o mais comum, neste artigo vamos analisar o uso de K8s no ambiente local.</p><h3><strong>Por que rodar K8s localmente?</strong></h3><p>Rodar K8s localmente pode ser útil em casos de prototipação, desenvolvimento em fase inicial ou preparação para o ambiente de produção, mas é especialmente valioso para fins de estudo. Rodar K8s em um ambiente local torna a experiência de primeiro contato com essa ferramenta muito mais simples e interativa, eliminando risco de gerar custos adicionais na nuvem e afetar o software já em produção sem precisar sacrificar funcionalidade.</p><h3><strong>Ferramentas para rodar localmente</strong></h3><p>Existem diversas ferramentas que facilitam o processo de instalação e execução de K8s no seu computador. Seguem abaixo algumas delas:</p><ul><li><a href="https://minikube.sigs.k8s.io/docs/">minikube</a>;</li><li><a href="https://K3s.io/">K3s</a>;</li><li><a href="https://microk8s.io/">microk8s</a>;</li><li><a href="https://k0sproject.io/">k0s</a>;</li><li><a href="https://kind.sigs.k8s.io/">kind</a> e <a href="https://k3d.io/stable/">k3d</a> que reaproveitam os conceitos de Docker;</li><li><a href="https://www.redhat.com/en/blog/codeready-containers">CodeReady Containers (CRC)</a> e <a href="https://github.com/minishift/minishift">Minishift</a> que utilizam <a href="https://www.redhat.com/en/technologies/cloud-computing/openshift/">OpenShift</a>.</li></ul><p>Dentre elas, escolhi duas específicas para me aprofundar por dois motivos: maior apoio da comunidade, importante quando precisar de documentação ou outro tipo de ajuda, e especializações diferentes para que consigamos cobrir diferentes casos de uso com ao menos uma dessas ferramentas.</p><h3><strong>minikube</strong></h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*0sqH48tyM-Ljubif698UxQ.png" /></figure><p>O <a href="https://minikube.sigs.k8s.io/docs/">minikube</a> foi feito para ser a melhor ferramenta para desenvolvimento de aplicações com K8s local e para suportar todas as funcionalidades aplicáveis do K8s. Por esse motivo, é bem completo em suas funcionalidades e deve atender a maioria dos casos de uso.</p><h4>Destaques:</h4><ul><li>Suporta a última versão do K8s.</li><li>Suporta múltiplas plataformas (Linux, macOS e Windows).</li><li>Suporta processadores gráficos para desenvolvimento de IA (NVidia, AMD, Apple).</li><li>Pode ser implantado como uma VM, um contêiner ou sem virtualização alguma.</li><li>Suporta múltiplos runtimes de contêiner (CRI-O, containerd, docker).</li><li>Endpoint direto da API para rápido carregamento e construção das imagens.</li><li>Funcionalidades avançadas como LoadBalancer, montagem de sistemas de arquivos, FeatureGates e políticas de rede.</li><li>Suporta Addons com fácil instalação.</li><li>Suporta ambientes comuns de CI.</li></ul><p>Para instalar o minikube, siga o <a href="https://minikube.sigs.k8s.io/docs/start/?arch=%2Fwindows%2Fx86-64%2Fstable%2F.exe+download">guia de instalação</a> que cobre os requisitos necessários, o processo de instalação e passos iniciais para gerenciar seu <em>cluster</em> K8s.</p><h3><strong>K3s</strong></h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/550/1*zX7yekxXQJvvcyzJZOXC0Q.png" /></figure><p>O <a href="https://K3s.io/">K3s</a> foi feito originalmente por Rancher Labs com o objetivo principal de rodar em ambientes com poucos recursos, como é a necessidade de dispositivos de internet das coisas, funcionando até em um Raspberry Pi. Para isso, o K3s é bem leve, reduzindo dependências e aumentando a facilidade de atualizar, executar e atualizar automaticamente um cluster de K8s em produção.</p><h4>Destaques:</h4><ul><li>É disponibilizado através de um único arquivo binário de menos de 70MB.</li><li>Suporte padrão ao SQLite3, suportando ainda Etcd3, MariaDB, MySQL, e Postgres.</li><li>Encapsula K8s e outros componentes em um único, simples executável.</li><li>É seguro com configurações padrões apropriadas para ambientes com poucos recursos.</li><li>Tem dependências mínimas de sistemas operacionais, apenas a montagem de um kernel e cgroups é necessária.</li><li>Simplifica operações do K8s com gerenciamentos de certificados TLS, conexões entre nós e um cluster etcd integrado, além de aplicar recursos de manifestos locais em tempo real conforme eles são modificados.</li></ul><p>Para instalar o K3s basta seguir o <a href="https://docs.k3s.io/quick-start">guia de inicialização rápida</a>. Existe uma alternativa para facilitar esse processo ainda mais: caso você já possua o Rancher Desktop instalado, basta ativar as funcionalidades de K8s. Isso pode ser feito no instalador do Rancher Desktop, que já deixa seu ambiente funcional com pouco esforço.</p><h3><strong>Comparação</strong></h3><p>Ambos foram feitos para criar clusters completos de K8s de um único nó em um único servidor ou máquina virtual, ideal para desenvolvimento local. Também são de fácil instalação e tem processos facilitados e amplamente documentados.</p><p>Quanto às vantagens, K3s se destaca por ser leve, considerando seu baixo consumo de recursos e requisitos menores, com funcionalidades prontas sem precisar de configurações extras. Já o minikube é mais personalizável através dos <em>addons</em> e possui algumas funcionalidades que se aproximam mais de um ambiente de produção.</p><p>Já quanto às desvantagens, o minikube acaba consumindo mais recursos e apresenta um tempo de inicialização mais alto enquanto o K3s, por ser tão leve, não possui todo o conjunto de funcionalidades de um ambiente tradicional de K8s.</p><h4><strong>Qual deles escolher?</strong></h4><p>Ambas as opções são bem suportadas pela comunidade, possuem ampla documentação e dão conta do recado. Por esse motivo, são as soluções mais adotadas na indústria e podem ser usadas para os cenários em que se especializam.</p><p>Caso você já tenha o Rancher Desktop instalado, começar a usar o K3s é muito simples, além de ser um ambiente mais leve. Porém, caso queira explorar mais funcionalidades, o minikube pode ser a melhor opção para você.</p><h3><strong>Como desenvolver nesse novo ambiente K8s local?</strong></h3><p>Além da execução das aplicações, também é possível realizar seu desenvolvimento diretamente em um ambiente K8s local. Algumas vantagens de desenvolver dessa forma são iterações mais rápidas, redução de custos e simulação do ambiente em produção.</p><p>Porém, essa abordagem vem com seus obstáculos. Em aplicações compostas de múltiplos serviços, precisamos garantir a persistência e acessibilidade dos dados utilizados pelos serviços, que a comunicação via rede seja feita corretamente e que os limites dos recursos de hardware sejam respeitados.</p><p>Para esse desafio contamos com a ajuda de ferramentas como <a href="https://github.com/Azure/draft/">Draft</a>, <a href="https://skaffold.dev/">Skaffold</a>, <a href="https://garden.io/">Garden</a>, <a href="https://tilt.dev/">Tilt</a> e <a href="https://www.plural.sh/">Plural</a>, que nos auxiliam na redução do tempo de <em>feedback</em> das alterações feitas, considerando que a aplicação precisa ter seu código escrito, executado e modificado constantemente para não atrasar o processo de desenvolvimento.</p><h3><strong>Considerações finais</strong></h3><p>Embora ainda exista muito para aprender sobre o assunto, esse estudo visa ser um primeiro passo no aprendizado sobre o K8s em um ambiente local. Tópicos como o uso detalhado do minikube e K3s, o desenvolvimento em um ambiente K8s local e a escolha das ferramentas para esse desenvolvimento ficam como sugestões para dar sequência a esse estudo.</p><p>Enquanto isso, já podemos escolher uma ferramenta de K8s local, instalar e executar esse novo ambiente e começar a gerenciar nossas aplicações, seja para simular um ambiente de produção ou apenas para entender como o K8s funciona na prática.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=fc58cf815497" width="1" height="1" alt=""><hr><p><a href="https://making.ndd.tech/kubernetes-no-ambiente-local-fc58cf815497">Kubernetes no ambiente local</a> was originally published in <a href="https://making.ndd.tech">nddtech</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Como implementar e quais os ganhos da telemetria em sua arquitetura]]></title>
            <link>https://making.ndd.tech/como-implementar-e-quais-os-ganhos-da-telemetria-em-sua-arquitetura-1965622f96bb?source=rss----c9197bc611ac---4</link>
            <guid isPermaLink="false">https://medium.com/p/1965622f96bb</guid>
            <category><![CDATA[opentelemetry]]></category>
            <category><![CDATA[devops]]></category>
            <category><![CDATA[observability]]></category>
            <category><![CDATA[signoz]]></category>
            <category><![CDATA[tecnologia]]></category>
            <dc:creator><![CDATA[Victor da Cunha]]></dc:creator>
            <pubDate>Wed, 10 Dec 2025 18:16:07 GMT</pubDate>
            <atom:updated>2025-12-10T18:16:06.096Z</atom:updated>
            <content:encoded><![CDATA[<p>Imagine que você tem uma única aplicação em um servidor. Quando algo falha (lentidão, erro inesperado, pico de CPU), basta abrir a máquina, olhar os logs e resolver. Rápido, simples, direto.</p><p><strong>Agora avance alguns capítulos.</strong></p><p>Seu ambiente virou um cluster cheio de serviços distribuídos: APIs, jobs assíncronos, filas, caches, diferentes bancos, sidecars, gateways, integrações externas. Tudo ocorre dinamicamente, cada requisição segue um caminho diferente, e qualquer ponto pode falhar sem aviso.</p><p><strong>E quando algo dá errado?</strong></p><p>A equipe cai em uma verdadeira “caça ao tesouro”: logs desconexos, métricas isoladas, sintomas que não se explicam. Perde-se tempo, e controle, tentando descobrir onde o problema realmente começou.</p><p>É aí que a telemetria deixa de ser opcional. Sem ela, você está operando às cegas.</p><p>Neste artigo, vou mostrar como implementar telemetria com <a href="https://signoz.io/">SigNoz</a> + <a href="https://opentelemetry.io/">OpenTelemetry</a>, e quais ganhos isso traz para o seu ambiente. E o melhor: tudo isso sem alterar uma linha de código da aplicação.</p><h3>Preparando o ambiente</h3><p>Para este exemplo utilizaremos:</p><ul><li>Linux Ubuntu,</li><li>Docker,</li><li>Git,</li><li>SigNoz,</li><li>Aplicação .NET e banco SQL Server.</li></ul><p>Começaremos instalando o SigNoz. Basta clonar o repositório oficial e usar o instalador nativo:</p><pre>git clone -b main https://github.com/SigNoz/signoz.git &amp;&amp; cd signoz/deploy/<br><br>./install.sh</pre><p>Em poucos minutos teremos os seguintes containers rodando:</p><ul><li>signoz-otel-collector</li><li>signoz-signoz</li><li>signoz-clickhouse</li><li>signoz-zookeeper-1</li></ul><p>Esses componentes são responsáveis por receber os dados, armazená-los, correlacioná-los e exibi-los.</p><p>Acessando localhost:8080, já podemos visualizar o SigNoz instalado e funcionando:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*1c2kIYFwauUEmZ1VsGXgIw.png" /></figure><h3>Instrumentando a aplicação</h3><p>Agora vamos habilitar o OpenTelemetry no Docker da aplicação .NET.</p><p>No Dockerfile, adicionamos:</p><pre># Instalar OpenTelemetry Auto-Instrumentation<br>ENV OTEL_DOTNET_AUTO_HOME=/otel-dotnet-auto<br>RUN apt-get update &amp;&amp; apt-get install -y curl unzip &amp;&amp; \<br>    curl -sSfL https://github.com/open-telemetry/opentelemetry-dotnet-instrumentation/releases/download/v1.8.0/otel-dotnet-auto-install.sh -O &amp;&amp; \<br>    sh ./otel-dotnet-auto-install.sh &amp;&amp; \<br>    rm otel-dotnet-auto-install.sh &amp;&amp; \<br>    apt-get clean &amp;&amp; rm -rf /var/lib/apt/lists/*<br><br># Configuração obrigatória do CLR Profiler<br>ENV CORECLR_ENABLE_PROFILING=1 \<br>    CORECLR_PROFILER={918728DD-259F-4A6A-AC2B-B85E1B658318} \<br>    CORECLR_PROFILER_PATH=/otel-dotnet-auto/linux-x64/OpenTelemetry.AutoInstrumentation.Native.so \<br>    DOTNET_STARTUP_HOOKS=/otel-dotnet-auto/net/OpenTelemetry.AutoInstrumentation.StartupHook.dll \<br>    DOTNET_ADDITIONAL_DEPS=/otel-dotnet-auto/AdditionalDeps \<br>    DOTNET_SHARED_STORE=/otel-dotnet-auto/store \<br>    OTEL_DOTNET_AUTO_HOME=/otel-dotnet-auto \<br>    DOTNET_EnableDiagnostics=1</pre><p>E no Docker Compose, adicionamos variáveis de identificação, exportação e habilitação dos recursos:</p><pre># Identificação do serviço e ambiente:<br>- OTEL_SERVICE_NAME=eshoponweb-web<br>- OTEL_RESOURCE_ATTRIBUTEyS=service.version=1.0.0,deployment.environment=development,service.namespace=eshoponweb<br><br># Conexão com Signoz<br>- OTEL_EXPORTER_OTLP_ENDPOINT=http://signoz-otel-collector:4317<br>- OTEL_EXPORTER_OTLP_PROTOCOL=grpc<br>- OTEL_TRACES_EXPORTER=otlp<br>- OTEL_METRICS_EXPORTER=otlp<br>- OTEL_LOGS_EXPORTER=otlp<br><br># O que será coletado:<br><br># Traces<br>- OTEL_DOTNET_AUTO_TRACES_ASPNETCORE_INSTRUMENTATION_ENABLED=true<br>- OTEL_DOTNET_AUTO_TRACES_HTTPCLIENT_INSTRUMENTATION_ENABLED=true<br>- OTEL_DOTNET_AUTO_TRACES_ENTITYFRAMEWORKCORE_INSTRUMENTATION_ENABLED=true<br>- OTEL_DOTNET_AUTO_TRACES_SQLCLIENT_INSTRUMENTATION_ENABLED=true<br><br># Métricas<br>- OTEL_DOTNET_AUTO_METRICS_ASPNETCORE_INSTRUMENTATION_ENABLED=true<br>- OTEL_DOTNET_AUTO_METRICS_HTTPCLIENT_INSTRUMENTATION_ENABLED=true<br>- OTEL_DOTNET_AUTO_METRICS_NETRUNTIME_INSTRUMENTATION_ENABLED=true<br><br># Logs<br>- OTEL_DOTNET_AUTO_LOGS_ILOGGER_INSTRUMENTATION_ENABLED=true</pre><h3>Resultados</h3><p>Após subirmos a aplicação já poderemos visualizar no SigNoz:</p><ul><li>Saúde dos serviços, latência e volume de chamadas</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*4ubuTnszp21RbiMaRpZ5nA.gif" /></figure><ul><li>Logs centralizados e correlacionados com traces:</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*hmaVKuQ3-TqxPO3H2ilSvw.gif" /></figure><ul><li>Traces completos de rede, banco e execução interna:</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ovu9XvrBQF69nZoLwgN4Ng.gif" /></figure><ul><li>Métricas de infraestrutura (CPU, RAM, disco, rede):</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*UHh-YbGPC2oxSwAPfO2bxg.gif" /></figure><ul><li>Relação entre todos os serviços no cluster:</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*m4xGFG0_Mi2Ck9E8sgaiww.png" /></figure><ul><li>Dashboards customizados reunindo tudo em um só lugar:</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jZlJgHjlEdw4_bDglZZ3rw.gif" /></figure><h3>Conclusão</h3><p>Com uma configuração mínima, conseguimos mapear automaticamente todos os serviços, processos, requisições, consultas ao banco e métricas de infraestrutura, tudo correlacionado, em tempo real.</p><p>Agora, se um erro/lentidão aparecer, conseguimos identificar rapidamente:</p><ul><li>Quais processos estavam rodando,</li><li>Qual requisição gerou o problema,</li><li>Tempo de resposta da rede e banco,</li><li>O estado do servidor naquele exato instante,</li><li>…</li></ul><p>Como consequência, geramos valor na entrega de um serviço ao cliente e garantimos a confiabilidade do sistema.</p><p>E isso é apenas o básico da telemetria, podendo ser aplicada nos mais diversos ambientes (Kubernetes, Windows, Linux, …). Além disso, podemos criar alertas, automatizar ações e até monitorar métricas de negócio: vendas, emissões, transações, filas, heatmaps de acesso e muito mais.</p><h3>Glossário</h3><p><strong>Tracing (ou Traces)</strong><br>Rastreamento do caminho completo de uma requisição através de diversos serviços, mostrando tempos, falhas e gargalos.</p><p><strong>Logs</strong><br>Registros textuais de eventos emitidos por aplicações, serviços e sistemas, fundamentais para entender o que aconteceu.</p><p><strong>Métricas</strong><br>Dados numéricos coletados ao longo do tempo (CPU, RAM, latência, throughput, erros, etc).</p><p><strong>OpenTelemetry (OTEL)</strong><br>Padrão aberto para coletar métricas, logs e traces de qualquer aplicação, linguagem ou plataforma.</p><p><strong>SigNoz</strong><br>Plataforma open source de monitoramento e observabilidade que recebe os dados do OpenTelemetry e os apresenta em dashboards, gráficos e painéis correlacionados.</p><h3>Documentação:</h3><p><a href="https://signoz.io/docs/install/self-host/">https://signoz.io/docs/install/self-host/</a><br><a href="https://opentelemetry.io/docs/">https://opentelemetry.io/docs/zero-code/dotnet/</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1965622f96bb" width="1" height="1" alt=""><hr><p><a href="https://making.ndd.tech/como-implementar-e-quais-os-ganhos-da-telemetria-em-sua-arquitetura-1965622f96bb">Como implementar e quais os ganhos da telemetria em sua arquitetura</a> was originally published in <a href="https://making.ndd.tech">nddtech</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>