<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Lucien Risso Correia</title>
    <description>The latest articles on DEV Community by Lucien Risso Correia (@luciencorreia).</description>
    <link>https://dev.to/luciencorreia</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F670293%2F6c965f4c-994a-4398-98d4-c4a0052f9b4c.jpg</url>
      <title>DEV Community: Lucien Risso Correia</title>
      <link>https://dev.to/luciencorreia</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/luciencorreia"/>
    <language>en</language>
    <item>
      <title>Segurança na era da IA - como os ataques mudaram e como se defender</title>
      <dc:creator>Lucien Risso Correia</dc:creator>
      <pubDate>Fri, 13 Nov 2026 17:26:08 +0000</pubDate>
      <link>https://dev.to/luciencorreia/seguranca-na-era-da-ia-como-os-ataques-mudaram-e-como-se-defender-966</link>
      <guid>https://dev.to/luciencorreia/seguranca-na-era-da-ia-como-os-ataques-mudaram-e-como-se-defender-966</guid>
      <description>&lt;p&gt;Janeiro de 2024, escritório da Arup em Hong Kong. Um funcionário do financeiro recebe um e-mail do CFO, que fica em Londres, pedindo uma transação confidencial. Ele desconfia: parece phishing. Aí vem o convite para uma videochamada. Na tela estão o CFO e outros colegas que ele conhece, com rosto e voz de sempre. A dúvida some. Ele faz 15 transferências, cerca de US$ 25 milhões no total, para cinco contas.&lt;/p&gt;

&lt;p&gt;Todo mundo naquela chamada, menos ele, era deepfake, montado a partir de vídeos e áudios públicos dos executivos. A fraude só apareceu quando ele falou com a matriz por outro canal.&lt;/p&gt;

&lt;p&gt;Não teve malware nem exploit, e nenhum sistema da empresa foi comprometido. O ataque passou por um processo que dependia de "eu vi a pessoa, então é ela". Esse é o padrão da segurança com IA: ela quase não inventa ataque novo, mas deixa os antigos mais baratos, mais rápidos e mais convincentes, e cria uma superfície nova, que são os próprios sistemas de IA que você colocou em produção.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que a IA mudou para quem ataca
&lt;/h2&gt;

&lt;p&gt;Phishing, engenharia social, exploração de vulnerabilidade e movimentação lateral já existiam. O que mudou foi o custo de cada etapa:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Engenharia social sem erro&lt;/strong&gt;: o e-mail de phishing com português quebrado acabou. O modelo escreve no tom da empresa, cita o projeto certo (achado no LinkedIn) e responde às perguntas da vítima em tempo real. Clonar uma voz pede poucos segundos de áudio.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Escala&lt;/strong&gt;: o que antes precisava de um time de operadores agora roda em paralelo, contra dezenas de alvos, sem dormir.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Menos habilidade exigida&lt;/strong&gt;: quem não sabe escrever um exploit pede para o modelo escrever e corrigir até funcionar.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Velocidade&lt;/strong&gt;: o tempo entre a publicação de uma CVE e o primeiro exploit funcional encolhe, porque ler o diff do patch e montar a prova de conceito virou trabalho de máquina.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Para quem defende, a consequência prática é direta: &lt;strong&gt;qualquer controle que dependia do atacante ser lento, caro ou desleixado perdeu força.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Os ataques que já aconteceram
&lt;/h2&gt;

&lt;p&gt;Vale separar o que é caso real do que é previsão de fornecedor. Os casos abaixo têm relatório público.&lt;/p&gt;

&lt;h3&gt;
  
  
  Operação conduzida por agente
&lt;/h3&gt;

&lt;p&gt;Em novembro de 2025 a Anthropic publicou o relatório de uma campanha detectada em setembro daquele ano e atribuída a um grupo patrocinado pelo Estado chinês, que ela chamou de GTG-1002. O grupo usou o Claude Code como motor da operação contra cerca de 30 organizações, com um punhado de invasões confirmadas.&lt;/p&gt;

&lt;p&gt;Os humanos escolhiam os alvos e aprovavam os passos críticos. O agente fazia o resto: reconhecimento, busca de vulnerabilidades, geração de exploit, coleta de credenciais, escalada de privilégio, movimentação lateral e extração de dados. Para contornar as proteções do modelo, os atacantes quebraram o trabalho em tarefas pequenas e aparentemente inocentes, e se apresentaram como uma empresa de segurança fazendo teste autorizado.&lt;/p&gt;

&lt;p&gt;O mesmo relatório traz o limite: o modelo frequentemente exagerava resultados e às vezes inventava dados, como credenciais que não funcionavam. Pesquisadores de fora também questionaram o grau de autonomia alegado. Mesmo com o desconto, o recado fica: &lt;strong&gt;um operador com um agente faz o trabalho de uma equipe.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Malware que conversa com um LLM
&lt;/h3&gt;

&lt;p&gt;Em novembro de 2025 o Google Threat Intelligence Group descreveu famílias de malware que chamam um modelo durante a execução:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;PROMPTFLUX&lt;/strong&gt;: um dropper em VBScript que pede ao Gemini, via API, para reescrever o próprio código e escapar de assinatura. Experimental, sem uso confirmado em campanha.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PROMPTSTEAL&lt;/strong&gt;: usado pelo APT28 contra a Ucrânia. Em vez de trazer os comandos embutidos, pede a um LLM os comandos para coletar dados da máquina. Esse é o caso com uso real confirmado.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PROMPTLOCK&lt;/strong&gt;: ransomware que gera os scripts em tempo de execução. Chegou a ser noticiado como ameaça ativa, mas era uma prova de conceito de pesquisadores da NYU.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hoje essas amostras são fracas. O ponto é a direção: malware que não tem o comportamento fixo no binário fica muito mais difícil de pegar por assinatura.&lt;/p&gt;

&lt;h3&gt;
  
  
  A cadeia de suprimentos mirando ferramentas de IA
&lt;/h3&gt;

&lt;p&gt;Em agosto de 2025, versões maliciosas do Nx, um build system com milhões de downloads semanais no npm, foram publicadas no registro. O ataque ficou conhecido como s1ngularity. O script de instalação procurava CLIs de IA instaladas na máquina (Claude Code, Gemini CLI, Amazon Q) e as chamava com flags que desligam as confirmações, como &lt;code&gt;--dangerously-skip-permissions&lt;/code&gt; e &lt;code&gt;--yolo&lt;/code&gt;, pedindo para varrer o disco atrás de carteiras, chaves e arquivos &lt;code&gt;.env&lt;/code&gt;. O resultado era publicado num repositório no GitHub da própria vítima, usando o &lt;code&gt;gh&lt;/code&gt; já autenticado.&lt;/p&gt;

&lt;p&gt;Foi o primeiro caso conhecido de um atacante usando o agente de IA do desenvolvedor como ferramenta de reconhecimento. Seu agente de código tem acesso ao seu disco, ao seu terminal e às suas credenciais. &lt;strong&gt;Quem roda código na sua máquina pode rodar o seu agente também.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A nova superfície: o seu próprio sistema de IA
&lt;/h2&gt;

&lt;p&gt;Até aqui a IA era a arma. A outra metade do problema é a IA como alvo.&lt;/p&gt;

&lt;p&gt;Um LLM não separa dados de instruções. Tudo que entra no contexto é texto, e qualquer texto pode tentar mandar no modelo. Isso é &lt;strong&gt;prompt injection&lt;/strong&gt;, e na forma indireta a instrução maliciosa não vem do usuário: vem de um e-mail, de uma página web, de um PDF ou de uma issue que o agente leu durante o trabalho. Se o termo for novo, o &lt;a href="https://lucienrc.xyz/blog/dictionary-42298b72" rel="noopener noreferrer"&gt;Dicionário de IA&lt;/a&gt; cobre a base.&lt;/p&gt;

&lt;p&gt;O exemplo mais claro é o EchoLeak (CVE-2025-32711, CVSS 9.3), revelado pela Aim Security em junho de 2025. Bastava mandar um e-mail para alguém da empresa. Quando a vítima fazia qualquer pergunta ao Microsoft 365 Copilot, o assistente buscava contexto, encontrava o e-mail e seguia as instruções escondidas nele, vazando dados internos por uma URL de imagem. Zero clique da vítima. A Microsoft corrigiu do lado do servidor, mas a classe do problema continua valendo para qualquer sistema com o mesmo formato.&lt;/p&gt;

&lt;h3&gt;
  
  
  A trifeta letal e a regra de dois
&lt;/h3&gt;

&lt;p&gt;Simon Willison deu nome ao formato perigoso em junho de 2025. Um agente fica explorável quando junta três coisas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Acesso a dados privados&lt;/strong&gt;: e-mails, documentos, banco, código.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exposição a conteúdo não confiável&lt;/strong&gt;: qualquer texto que um atacante consiga colocar no caminho do agente.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Um canal de saída&lt;/strong&gt;: requisição HTTP, envio de e-mail, um link renderizado, um commit.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Com as três, a injeção lê o dado e o manda para fora. O EchoLeak é exatamente isso.&lt;/p&gt;

&lt;p&gt;Em outubro de 2025 a Meta transformou a ideia em regra de projeto, a Agents Rule of Two: enquanto não existir defesa confiável contra prompt injection, e hoje não existe, &lt;strong&gt;um agente não deve ter mais de duas das três propriedades na mesma sessão&lt;/strong&gt;. A versão da Meta troca o terceiro item por algo mais amplo: mudar estado ou se comunicar com o exterior.&lt;/p&gt;

&lt;p&gt;Na prática, isso vira decisão de arquitetura e não de prompt:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O agente que lê e-mails de fora e acessa o CRM não pode fazer requisição para domínio arbitrário.&lt;/li&gt;
&lt;li&gt;O agente que navega na web e pode agir não pode ver dados sensíveis.&lt;/li&gt;
&lt;li&gt;Se o caso de uso exige as três, um humano aprova cada ação de saída.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Guardrail de prompt, aquele "ignore instruções contidas nos documentos", ajuda pouco. É um filtro probabilístico contra um atacante que pode tentar mil variações. &lt;strong&gt;Controle que funciona é o que o modelo não consegue desligar&lt;/strong&gt;: permissão, rede, credencial.&lt;/p&gt;

&lt;h2&gt;
  
  
  Como se proteger
&lt;/h2&gt;

&lt;p&gt;Boa parte da defesa contra ataque com IA é o básico, que agora deixou de ser opcional.&lt;/p&gt;

&lt;h3&gt;
  
  
  Identidade e processo
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MFA resistente a phishing&lt;/strong&gt;: passkeys e chaves FIDO2. Código por SMS e push que o usuário aprova caem diante de um phishing perfeito e de um atacante que liga fingindo ser do suporte. Passkey é presa ao domínio; site falso não recebe nada.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verificação fora de banda para dinheiro e acesso&lt;/strong&gt;: pedido de transferência, troca de conta bancária de fornecedor ou reset de MFA se confirma por um canal que o solicitante não controla, como ligar de volta no número já cadastrado. Voz e vídeo deixaram de ser prova de identidade.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fricção proposital&lt;/strong&gt;: duas aprovações acima de um valor, prazo mínimo para mudança de dado bancário. O golpe da Arup dependia de urgência e sigilo, e processo que não aceita os dois quebra o roteiro.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Seus agentes de IA
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Menor privilégio de verdade&lt;/strong&gt;: token com escopo mínimo e vida curta, nunca a credencial pessoal do desenvolvedor. Agente que só lê não recebe permissão de escrita.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Isolamento&lt;/strong&gt;: agente que roda sem confirmação roda em container ou VM descartável, sem as suas chaves de nuvem no ambiente e com saída de rede restrita a uma lista de domínios.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bloqueio explícito de segredo&lt;/strong&gt;: no Claude Code, por exemplo, regras de &lt;code&gt;deny&lt;/code&gt; no &lt;code&gt;settings.json&lt;/code&gt; do projeto impedem a leitura de arquivos sensíveis e o uso de comandos de rede, independente do que o modelo decidir:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;"permissions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;"deny"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="s2"&gt;"Read(./.env)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"Read(./.env.*)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"Read(./secrets/**)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"Bash(curl:*)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"Bash(wget:*)"&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Humano no circuito para o irreversível&lt;/strong&gt;: deploy, envio para fora, exclusão, pagamento. O agente propõe, a pessoa confirma.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Log de toda chamada de ferramenta&lt;/strong&gt;: com argumentos, fora do alcance do agente. Sem isso não existe investigação depois.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cadeia de suprimentos e patch
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Lockfile e instalação reprodutível&lt;/strong&gt;: &lt;code&gt;npm ci&lt;/code&gt; no CI, versões fixas, e &lt;code&gt;ignore-scripts&lt;/code&gt; onde o projeto aguentar, já que o s1ngularity rodou no script de instalação.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Publicação com proveniência&lt;/strong&gt;: pacotes internos publicados pelo CI com token de curta duração (trusted publishing), não com token pessoal guardado num &lt;code&gt;.npmrc&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Janela de patch curta&lt;/strong&gt;: se o exploit sai em horas, o ciclo mensal de atualização ficou largo demais para o que é exposto à internet. Comece pelo perímetro.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  IA como defesa contínua
&lt;/h2&gt;

&lt;p&gt;O mesmo ganho de escala vale para o lado de cá. A diferença é usar a IA onde ela amplia o time sem ganhar poder demais.&lt;/p&gt;

&lt;h3&gt;
  
  
  Achar a falha antes do atacante
&lt;/h3&gt;

&lt;p&gt;Em julho de 2025 o Google anunciou que o Big Sleep, agente do Project Zero com o DeepMind, encontrou a CVE-2025-6965 no SQLite, uma corrupção de memória corrigida na 3.50.2. A inteligência de ameaças do Google tinha sinais de que alguém preparava um zero-day mas não sabia qual era a falha. O agente localizou o bug, e o patch saiu antes da exploração. Segundo o Google, foi a primeira vez que um agente ajudou a frustrar um exploit em campo.&lt;/p&gt;

&lt;p&gt;Você não precisa de um Big Sleep para aplicar a ideia no seu código:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Revisão de segurança em todo pull request&lt;/strong&gt;: um agente lê o diff procurando injeção, autorização faltando, segredo commitado, desserialização insegura. O Claude Code já traz o &lt;code&gt;/security-review&lt;/code&gt;, e dá para rodar o mesmo no CI. Ele não substitui o SAST: o SAST acha o padrão conhecido com precisão, e o LLM lê intenção e contexto, achando o endpoint que esqueceu de checar se o pedido é do usuário logado.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Triagem do que o scanner já acha&lt;/strong&gt;: o problema da maioria dos times não é falta de alerta, é excesso. Usar o modelo para explicar se a CVE da dependência é alcançável pelo seu código corta o ruído de forma relevante.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Red team contínuo do seu próprio agente&lt;/strong&gt;: uma suíte de prompt injection (documentos, e-mails e páginas com instruções escondidas) rodando no CI a cada mudança de prompt, ferramenta ou modelo. Ferramentas como o promptfoo fazem isso. Trate como teste de regressão: o ataque que passou uma vez vira caso fixo.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Detectar comportamento, não assinatura
&lt;/h3&gt;

&lt;p&gt;A Anthropic não pegou a GTG-1002 por assinatura. Pegou por padrão de uso: sequência de chamadas de ferramenta, ritmo das requisições, persistência da operação entre sessões sem relação. É o mesmo princípio que vale contra malware que se reescreve: &lt;strong&gt;se o artefato muda toda hora, o que você monitora é o comportamento.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No seu ambiente, isso significa ter linha de base e alertar no desvio. Uma conta de serviço que nunca listou buckets e de repente lista todos. Um agente de atendimento que passa a gerar URLs para domínios externos. Um desenvolvedor cujo token do GitHub cria repositório às três da manhã.&lt;/p&gt;

&lt;h3&gt;
  
  
  O SOC com agentes
&lt;/h3&gt;

&lt;p&gt;A divisão de trabalho que funciona hoje:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A IA faz&lt;/strong&gt;: triagem do alerta, enriquecimento (quem é o usuário, o que o IP já fez, o que mudou no host), correlação entre fontes, resumo do incidente, rascunho do relatório.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;O humano faz&lt;/strong&gt;: decide contenção, isola máquina, desativa conta, fala com o cliente.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;O agente do SOC lê log, que é conteúdo controlado pelo atacante. Ele tem acesso a dado sensível. Se também puder agir sozinho, você montou a trifeta letal dentro da sua defesa. &lt;strong&gt;Dê ao agente de defesa duas das três propriedades, e a terceira fica com uma pessoa.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Onde colocar o esforço primeiro
&lt;/h2&gt;

&lt;p&gt;Se o orçamento só dá para começar por um lado, a ordem que mais reduz risco é:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Primeiro, identidade e processo&lt;/strong&gt;: passkeys e verificação fora de banda. Custam pouco, e é por onde a maior parte dos ataques com IA entra, porque engenharia social foi o que mais barateou.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Segundo, os seus agentes&lt;/strong&gt;: inventário de onde há IA com acesso a dados e ferramentas, e aplicação da regra de dois em cada um. É a superfície que cresce mais rápido e a que menos gente audita.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Terceiro, IA na defesa&lt;/strong&gt;: revisão de PR e triagem de alerta primeiro, porque devolvem tempo do time sem dar poder de ação ao modelo. Automação de resposta fica por último, quando você já tem log e linha de base para saber o que é normal.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;O critério para qualquer decisão no meio do caminho é o mesmo dos dois lados: a IA é ótima para ler, resumir e sugerir, e perigosa quando tem acesso, entrada não confiável e capacidade de agir ao mesmo tempo. Isso vale para o agente que te ataca, para o que você coloca em produção e para o que você usa para se defender.&lt;/p&gt;

</description>
      <category>security</category>
      <category>ai</category>
      <category>llm</category>
      <category>cybersecurity</category>
    </item>
    <item>
      <title>Modernizando Java legado com IA - o que funciona e o que dá errado</title>
      <dc:creator>Lucien Risso Correia</dc:creator>
      <pubDate>Fri, 30 Oct 2026 21:20:09 +0000</pubDate>
      <link>https://dev.to/luciencorreia/modernizando-java-legado-com-ia-o-que-funciona-e-o-que-da-errado-371a</link>
      <guid>https://dev.to/luciencorreia/modernizando-java-legado-com-ia-o-que-funciona-e-o-que-da-errado-371a</guid>
      <description>&lt;p&gt;Você herdou um sistema. Java 8, Spring 4 com metade da configuração em XML, Hibernate com &lt;code&gt;hbm.xml&lt;/code&gt;, um &lt;code&gt;pom.xml&lt;/code&gt; com dependências que não recebem atualização desde 2017 e um scanner de segurança apontando dezenas de CVEs. Ninguém do time original está mais na empresa. Não tem teste, ou tem uns vinte que ninguém roda porque metade quebra.&lt;/p&gt;

&lt;p&gt;A tentação em 2026 é abrir um agente de IA, apontar para o repositório e pedir "migra isso para Java 21 e Spring Boot 3". Dá para fazer. O resultado compila, às vezes até sobe. E aí, três semanas depois, o financeiro reclama que um relatório está arredondando centavos diferente.&lt;/p&gt;

&lt;p&gt;Esse post é sobre como usar IA nesse trabalho sem cair nisso: onde ela rende muito, onde ferramenta determinística é melhor, e o que precisa existir antes de qualquer linha mudar.&lt;/p&gt;

&lt;h2&gt;
  
  
  O problema real não é o código
&lt;/h2&gt;

&lt;p&gt;Sistema legado não é sinônimo de código feio. Código feio que tem teste e documentação se refatora numa tarde. O que torna um sistema legado difícil é outra coisa:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Conhecimento perdido&lt;/strong&gt;: regras de negócio que só existem no código, às vezes num &lt;code&gt;if&lt;/code&gt; dentro de um service de três mil linhas, sem comentário nem ticket.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nenhuma rede de segurança&lt;/strong&gt;: sem teste, qualquer mudança é aposta.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dependências mortas&lt;/strong&gt;: bibliotecas abandonadas, versões fora de suporte, APIs do JDK que deixaram de existir.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Medo&lt;/strong&gt;: ninguém mexe porque ninguém sabe o que quebra, então o sistema envelhece mais rápido.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Repara que digitar código não aparece na lista. &lt;strong&gt;O gargalo de uma modernização é entender o sistema, não escrever o código novo.&lt;/strong&gt; E é justamente aí que a IA mais ajuda, muito mais do que na geração de código em si.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fase 1: arqueologia
&lt;/h2&gt;

&lt;p&gt;Antes de mudar qualquer coisa, use a IA para ler. Um modelo com janela de contexto grande, rodando como agente dentro do repositório (Claude Code, Cursor, Copilot no modo agente, o que seu time usar), consegue fazer em uma hora o que levaria uma semana de leitura manual.&lt;/p&gt;

&lt;p&gt;Coisas que valem pedir, uma por vez:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Mapa de módulos&lt;/strong&gt;: quais pacotes existem, quem depende de quem, onde estão os pontos de entrada (servlets, controllers, jobs agendados, listeners de fila).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fluxos de ponta a ponta&lt;/strong&gt;: "siga o que acontece quando um pedido é cancelado, do endpoint até o banco, e liste cada efeito colateral". Esse tipo de pergunta revela as regras escondidas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tradução de configuração&lt;/strong&gt;: XML do Spring, mapeamentos do Hibernate, &lt;code&gt;web.xml&lt;/code&gt;, filtros. A IA explica o que cada bean faz e de onde vem cada injeção.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SQL e stored procedures&lt;/strong&gt;: muita regra de negócio de sistema antigo mora no banco. Peça a explicação de cada procedure e quais tabelas ela altera.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;O resultado dessa fase é documentação: um arquivo por módulo, diagramas em Mermaid, uma lista de regras de negócio encontradas. &lt;strong&gt;Revise tudo&lt;/strong&gt;. A IA vai errar em alguns pontos, principalmente onde o código usa reflexão, configuração externa ou convenção que não aparece no fonte. Mas corrigir um documento errado é muito mais rápido que escrever do zero, e o ato de revisar já te ensina o sistema.&lt;/p&gt;

&lt;p&gt;Guarde o que for confirmado num arquivo de contexto do projeto (&lt;code&gt;CLAUDE.md&lt;/code&gt;, &lt;code&gt;AGENTS.md&lt;/code&gt; ou equivalente). Toda sessão futura do agente começa sabendo o que você já descobriu, em vez de redescobrir e errar de novo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fase 2: travar o comportamento atual
&lt;/h2&gt;

&lt;p&gt;Essa é a fase que todo mundo quer pular e a mais importante do post.&lt;/p&gt;

&lt;p&gt;Você não vai migrar um sistema sem teste. Mas também não vai escrever testes unitários bonitos para código que você ainda não entende. O que você precisa é de &lt;strong&gt;testes de caracterização&lt;/strong&gt;: testes que registram o que o sistema faz hoje, certo ou errado, e quebram se esse comportamento mudar.&lt;/p&gt;

&lt;p&gt;A técnica também é chamada de golden master. Você roda o código atual com um conjunto de entradas, salva a saída, e o teste compara execuções futuras com essa saída salva:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CalculoFreteCaracterizacaoTest&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// Entradas reais, anonimizadas, tiradas de produção.&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;Stream&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Pedido&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;pedidos&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;CarregadorFixture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ler&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"fixtures/pedidos.json"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@ParameterizedTest&lt;/span&gt;
    &lt;span class="nd"&gt;@MethodSource&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"pedidos"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;freteContinuaIgual&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Pedido&lt;/span&gt; &lt;span class="n"&gt;pedido&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;frete&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CalculoFreteService&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;calcular&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pedido&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Compara com o valor gravado na primeira execução, contra o código antigo.&lt;/span&gt;
        &lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Golden&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;valor&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"frete"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pedido&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getId&lt;/span&gt;&lt;span class="o"&gt;()),&lt;/span&gt; &lt;span class="n"&gt;frete&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toPlainString&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Repara no &lt;code&gt;toPlainString()&lt;/code&gt;. Comparar &lt;code&gt;BigDecimal&lt;/code&gt; com &lt;code&gt;equals&lt;/code&gt; considera a escala (&lt;code&gt;1.0&lt;/code&gt; é diferente de &lt;code&gt;1.00&lt;/code&gt;), e é exatamente esse tipo de diferença que você quer pegar.&lt;/p&gt;

&lt;p&gt;A IA é ótima para gerar esses testes em volume. Peça para ela identificar os caminhos de cada método crítico, montar entradas que cubram cada ramo e escrever o teste. Dois cuidados:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;O teste trava o comportamento atual, inclusive os bugs.&lt;/strong&gt; Se o agente "corrigir" algo enquanto escreve o teste, o teste deixa de servir. Deixe isso explícito no pedido.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rode contra o código antigo primeiro.&lt;/strong&gt; Todo teste de caracterização tem que passar antes de qualquer migração. Se não passa, ele está errado, não o sistema.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Com isso no lugar, você tem algo que não tinha antes: um jeito de saber se quebrou.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fase 3: migração mecânica com ferramenta determinística
&lt;/h2&gt;

&lt;p&gt;Agora sim, mudar código. E aqui vai a regra que mais economiza dor de cabeça: &lt;strong&gt;o que é mecânico vai para ferramenta determinística, e a IA fica com o que exige julgamento.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Trocar &lt;code&gt;javax.persistence&lt;/code&gt; por &lt;code&gt;jakarta.persistence&lt;/code&gt; em quatrocentos arquivos não exige inteligência. Exige consistência. Um LLM fazendo isso arquivo por arquivo vai acertar 98% e errar 2% de forma diferente a cada vez. Uma ferramenta de refatoração baseada em AST acerta 100%, ou falha de um jeito previsível.&lt;/p&gt;

&lt;p&gt;A ferramenta padrão para isso no mundo Java é o &lt;a href="https://docs.openrewrite.org" rel="noopener noreferrer"&gt;OpenRewrite&lt;/a&gt;. Ele trabalha sobre a árvore sintática com tipos resolvidos, não sobre texto, e vem com receitas prontas para os saltos mais comuns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.openrewrite.maven&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;rewrite-maven-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;&lt;span class="c"&gt;&amp;lt;!-- versão atual no Maven Central --&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;activeRecipes&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;recipe&amp;gt;&lt;/span&gt;org.openrewrite.java.migrate.UpgradeToJava21&lt;span class="nt"&gt;&amp;lt;/recipe&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;recipe&amp;gt;&lt;/span&gt;org.openrewrite.java.migrate.jakarta.JavaxToJakarta&lt;span class="nt"&gt;&amp;lt;/recipe&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/activeRecipes&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.openrewrite.recipe&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;rewrite-migrate-java&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;&lt;span class="c"&gt;&amp;lt;!-- versão atual --&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mvn rewrite:dryRun   &lt;span class="c"&gt;# gera um patch em target/rewrite/ sem tocar no código&lt;/span&gt;
mvn rewrite:run      &lt;span class="c"&gt;# aplica&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para Spring Boot existe a família de receitas &lt;code&gt;UpgradeSpringBoot_3_x&lt;/code&gt; no módulo &lt;code&gt;rewrite-spring&lt;/code&gt;. Confira com &lt;code&gt;mvn rewrite:discover&lt;/code&gt; quais estão disponíveis na versão que você instalou, porque a lista cresce a cada release.&lt;/p&gt;

&lt;p&gt;Outra opção, se você está na AWS, é o Amazon Q Developer, que faz o salto de Java 8, 11 ou 17 para 17 ou 21 combinando receitas determinísticas com IA. A limitação prática é que o projeto precisa buildar com Maven, então projeto em Ant ou Gradle fica de fora.&lt;/p&gt;

&lt;p&gt;Rode a migração em passos pequenos, um salto por vez, com os testes de caracterização entre cada um. Java 8 para 11 é um salto com problemas próprios (os módulos de JAXB, JAX-WS e CORBA saíram do JDK no 11). De 11 para 17 o encapsulamento forte das APIs internas do JDK quebra bibliotecas que usavam reflexão. De 17 para 21 costuma ser tranquilo. Fazer tudo de uma vez transforma três problemas conhecidos em um problema misterioso.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fase 4: a IA no que sobra
&lt;/h2&gt;

&lt;p&gt;As receitas cobrem talvez 70 a 80% do trabalho. O resto é onde a IA brilha:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bibliotecas abandonadas&lt;/strong&gt;: aquela lib de geração de PDF que parou em 2016 e não tem versão compatível. A IA sugere substitutos e reescreve as chamadas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;APIs removidas sem substituto direto&lt;/strong&gt;: Nashorn saiu no Java 15, o &lt;code&gt;SecurityManager&lt;/code&gt; foi depreciado no 17 e desativado de vez no 24. Código que dependia disso precisa ser repensado, não traduzido.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Erros de compilação e de runtime pós-migração&lt;/strong&gt;: cole o stack trace, deixe o agente investigar. Ele lê o código ao redor, o changelog da dependência, e propõe a correção.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Código reflexivo e configuração por convenção&lt;/strong&gt;: onde o OpenRewrite não enxerga porque a referência está numa string.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;O fluxo que funciona com agente é sempre o mesmo loop curto:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Uma tarefa pequena e bem definida ("faça o módulo de faturamento compilar no Java 17").&lt;/li&gt;
&lt;li&gt;O agente edita.&lt;/li&gt;
&lt;li&gt;Build e testes de caracterização rodam, de preferência pelo próprio agente.&lt;/li&gt;
&lt;li&gt;Você revisa o diff antes de aceitar.&lt;/li&gt;
&lt;li&gt;Commit. Próxima tarefa.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;PRs pequenos não são preciosismo, são a única forma de a revisão humana continuar funcionando.&lt;/strong&gt; Um diff de três mil linhas gerado por IA não é revisado, é aprovado. E aprovar sem revisar é como os bugs silenciosos chegam em produção.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fase 5: modernizar de verdade
&lt;/h2&gt;

&lt;p&gt;Compilar no Java 21 não é modernizar, é só sair da zona de risco. Depois que o sistema está estável na versão nova, vem a parte que melhora o código.&lt;/p&gt;

&lt;p&gt;Um exemplo típico: um DAO com JDBC cru, do jeito que se escrevia em 2012.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Cliente&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;buscarAtivos&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Cliente&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;lista&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Cliente&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;();&lt;/span&gt;
    &lt;span class="nc"&gt;Connection&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nc"&gt;PreparedStatement&lt;/span&gt; &lt;span class="n"&gt;ps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nc"&gt;ResultSet&lt;/span&gt; &lt;span class="n"&gt;rs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dataSource&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getConnection&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;ps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;prepareStatement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SELECT id, nome, email FROM cliente WHERE ativo = 1"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;rs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ps&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;executeQuery&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;Cliente&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Cliente&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setId&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getLong&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
            &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setNome&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"nome"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
            &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setEmail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
            &lt;span class="n"&gt;lista&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SQLException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;RuntimeException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// três blocos try/catch fechando rs, ps e conn&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;lista&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Com um &lt;code&gt;record&lt;/code&gt; e o &lt;code&gt;JdbcClient&lt;/code&gt; do Spring 6.1:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;Cliente&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Cliente&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;buscarAtivos&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;jdbcClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SELECT id, nome, email FROM cliente WHERE ativo = 1"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Cliente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;list&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esse tipo de reescrita a IA faz muito bem, e o teste de caracterização garante que a lista devolvida continua igual. Mas tenha critério: &lt;code&gt;record&lt;/code&gt; é imutável, então se algum lugar do sistema chama &lt;code&gt;setNome&lt;/code&gt; no objeto devolvido, a troca quebra. É o tipo de coisa que você pede para o agente verificar antes, com uma busca por todos os usos.&lt;/p&gt;

&lt;p&gt;Vale o mesmo para os outros recursos novos. Pattern matching e &lt;code&gt;sealed&lt;/code&gt; ajudam onde existe hierarquia de tipos com &lt;code&gt;instanceof&lt;/code&gt; espalhado. Virtual threads ajudam em código que bloqueia muito em I/O. Nenhum deles precisa estar em todo lugar só porque existe.&lt;/p&gt;

&lt;p&gt;Para extrair partes do monólito, o padrão continua sendo o strangler fig: um módulo novo assume uma fatia do comportamento, o tráfego migra aos poucos, o código antigo morre por último. A IA ajuda a sugerir onde cortar, mapeando quais classes conversam entre si e quais tabelas cada fluxo toca. &lt;strong&gt;A decisão de onde fica a fronteira é sua&lt;/strong&gt;, porque depende de coisas que não estão no código: time, deploy, quem é dono de qual regra.&lt;/p&gt;

&lt;h2&gt;
  
  
  Onde dá errado
&lt;/h2&gt;

&lt;p&gt;Os problemas que aparecem quase sempre:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;API alucinada&lt;/strong&gt;: o modelo usa um método que existe em outra versão da biblioteca, ou que nunca existiu. O compilador pega a maioria. Os que passam costumam estar em código chamado por reflexão ou em configuração.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mudança silenciosa de comportamento&lt;/strong&gt;: o código compila, os testes unitários passam, e o resultado mudou. Os suspeitos clássicos são &lt;code&gt;BigDecimal&lt;/code&gt; com escala diferente, &lt;code&gt;equals&lt;/code&gt; e &lt;code&gt;hashCode&lt;/code&gt; reescritos, fuso horário na troca de &lt;code&gt;Date&lt;/code&gt; para &lt;code&gt;java.time&lt;/code&gt;, e charset. Desde o Java 18 o charset padrão é UTF-8 em qualquer sistema operacional, então um &lt;code&gt;new String(bytes)&lt;/code&gt; que rodava em Windows com Cp1252 passa a ler diferente. É exatamente para isso que existe a fase 2.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ordem de iteração&lt;/strong&gt;: código que dependia, sem saber, da ordem de um &lt;code&gt;HashMap&lt;/code&gt; ou &lt;code&gt;HashSet&lt;/code&gt;. A ordem nunca foi garantida, mas o código funcionava por coincidência e para de funcionar quando a implementação muda.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Diffs gigantes&lt;/strong&gt;: já falei, mas repito porque é o erro mais comum. Agente com tarefa grande produz diff grande, e diff grande não é revisado.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Código proprietário saindo da empresa&lt;/strong&gt;: mandar o código-fonte para uma API externa é decisão de compliance, não de desenvolvedor. Verifique o contrato do provedor (retenção de dados, uso para treino), e se o sistema processa dados pessoais, a LGPD entra na conversa. Muitas empresas resolvem com planos corporativos ou modelos rodando em nuvem própria.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Por onde começar amanhã
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Rode um agente em modo só leitura e gere a documentação dos módulos. Revise e guarde no arquivo de contexto do projeto.&lt;/li&gt;
&lt;li&gt;Escolha os cinco fluxos que mais doem se quebrarem e escreva testes de caracterização para eles.&lt;/li&gt;
&lt;li&gt;Confirme que esses testes passam no código atual.&lt;/li&gt;
&lt;li&gt;Configure o OpenRewrite e rode &lt;code&gt;rewrite:dryRun&lt;/code&gt; só para ver o tamanho do patch.&lt;/li&gt;
&lt;li&gt;Migre um salto de versão por vez, com os testes entre cada um.&lt;/li&gt;
&lt;li&gt;Use a IA no que sobrar das receitas, sempre em tarefas pequenas, com build e teste no loop.&lt;/li&gt;
&lt;li&gt;Revise todo diff. Se está grande demais para revisar, a tarefa estava grande demais.&lt;/li&gt;
&lt;li&gt;Só depois de estável na versão nova, modernize o código de verdade.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;O trade-off no fim é simples. A IA reduz drasticamente o custo de entender e de reescrever, mas não reduz em nada o custo de errar em produção. Se você não tem como saber que algo quebrou, a velocidade da IA só te leva mais rápido para o problema. &lt;strong&gt;Invista o tempo economizado na rede de segurança&lt;/strong&gt;, e a migração que antes levava um ano de medo cabe em alguns meses de trabalho controlado.&lt;/p&gt;

</description>
      <category>java</category>
      <category>ai</category>
      <category>refactoring</category>
      <category>programming</category>
    </item>
    <item>
      <title>CSRF - Cross-Site Request Forgery</title>
      <dc:creator>Lucien Risso Correia</dc:creator>
      <pubDate>Mon, 03 Aug 2026 14:07:06 +0000</pubDate>
      <link>https://dev.to/luciencorreia/csrf-cross-site-request-forgery-2lp7</link>
      <guid>https://dev.to/luciencorreia/csrf-cross-site-request-forgery-2lp7</guid>
      <description>&lt;p&gt;Se você já criou um formulário no Laravel, com certeza esbarrou naquela diretiva &lt;code&gt;@csrf&lt;/code&gt; que a gente coloca sem nem pensar muito. Mas você já parou pra pensar o que ela realmente faz e por que, se você esquecer dela, o Laravel te devolve um belo de um erro &lt;code&gt;419 Page Expired&lt;/code&gt;? Pois é, tudo isso gira em torno de um ataque chamado CSRF, e é sobre ele que vamos falar.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que é CSRF?
&lt;/h2&gt;

&lt;p&gt;CSRF significa &lt;em&gt;Cross-Site Request Forgery&lt;/em&gt;, ou "falsificação de requisição entre sites". A ideia do ataque é simples e por isso mesmo perigosa: fazer o navegador da vítima enviar uma requisição para um site no qual ela já está autenticada, &lt;strong&gt;sem que ela perceba&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;O ponto central que torna esse ataque possível é o comportamento dos cookies no navegador. Quando você faz login em &lt;code&gt;banco.com&lt;/code&gt;, o servidor te devolve um cookie de sessão. A partir daí, &lt;strong&gt;toda&lt;/strong&gt; requisição que o seu navegador fizer para &lt;code&gt;banco.com&lt;/code&gt; vai levar esse cookie junto, automaticamente. E aqui está o pulo do gato: o navegador não liga de onde a requisição partiu. Se um site totalmente diferente disparar uma requisição para &lt;code&gt;banco.com&lt;/code&gt;, o cookie de sessão vai junto do mesmo jeito.&lt;/p&gt;

&lt;h2&gt;
  
  
  Como o ataque funciona na prática
&lt;/h2&gt;

&lt;p&gt;Imagina que o seu banco tem um endpoint de transferência que funciona assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"https://banco.com/transferir"&lt;/span&gt; &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;"POST"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"valor"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"destino"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&amp;gt;&lt;/span&gt;Transferir&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Você está logado no seu banco em uma aba. Em outra aba, você abre um site qualquer que recebeu de um e-mail suspeito. O que você não sabe é que esse site malicioso tem escondido nele algo assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"https://banco.com/transferir"&lt;/span&gt; &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;"POST"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"ataque"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"hidden"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"valor"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"10000"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"hidden"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"destino"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"conta-do-atacante"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
    &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ataque&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Quando a página carrega, o JavaScript envia o formulário sozinho. O navegador faz a requisição para &lt;code&gt;banco.com&lt;/code&gt;, e como é uma requisição para o domínio do banco, &lt;strong&gt;ele anexa o seu cookie de sessão automaticamente&lt;/strong&gt;. Do ponto de vista do servidor do banco, é uma requisição perfeitamente autenticada, vinda de um usuário logado. E lá se vão os seus dez mil.&lt;/p&gt;

&lt;p&gt;O nome "falsificação de requisição entre sites" faz todo sentido: um site (o malicioso) forja uma requisição que parece ter vindo de você para outro site (o banco).&lt;/p&gt;

&lt;h2&gt;
  
  
  Qual o objetivo de se proteger contra isso?
&lt;/h2&gt;

&lt;p&gt;O objetivo da proteção CSRF é garantir que uma requisição que altera estado (um POST, PUT, PATCH ou DELETE) tenha &lt;strong&gt;realmente partido da sua aplicação&lt;/strong&gt;, e não de um terceiro se aproveitando da sessão ativa do usuário.&lt;/p&gt;

&lt;p&gt;Repara que o problema não é autenticação. A vítima está autenticada de verdade, o cookie é legítimo. O problema é a &lt;strong&gt;intenção&lt;/strong&gt;: como o servidor prova que foi o usuário quem, de fato, quis fazer aquela ação, e não um site externo agindo por baixo dos panos? É exatamente esse buraco que o token CSRF fecha.&lt;/p&gt;

&lt;h2&gt;
  
  
  Como o Laravel resolve isso
&lt;/h2&gt;

&lt;p&gt;A estratégia usada pelo Laravel (e pela maioria dos frameworks) é o padrão do &lt;strong&gt;token sincronizador&lt;/strong&gt;. A lógica é a seguinte: para cada sessão de usuário, o Laravel gera um token secreto e aleatório. Esse token fica guardado na sessão, no lado do servidor.&lt;/p&gt;

&lt;p&gt;Toda vez que você gera um formulário, precisa embutir esse mesmo token dentro dele. É aí que entra a diretiva &lt;code&gt;@csrf&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;"POST"&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"/perfil"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    @csrf
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"nome"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&amp;gt;&lt;/span&gt;Salvar&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Essa diretiva simplesmente expande para um campo escondido com o token:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"hidden"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"_token"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"a-string-aleatoria-e-secreta-da-sessao"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Quando o formulário é enviado, o middleware &lt;code&gt;VerifyCsrfToken&lt;/code&gt; entra em ação. Ele compara o &lt;code&gt;_token&lt;/code&gt; que veio no corpo da requisição com o token guardado na sessão. Se os dois baterem, a requisição segue. Se não baterem, ou se o token não vier, o Laravel barra tudo com aquela resposta &lt;code&gt;419&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;E por que isso funciona? Porque o site malicioso &lt;strong&gt;não tem como saber qual é o seu token&lt;/strong&gt;. Ele está guardado na sua sessão e só é entregue nas páginas que o próprio banco renderiza pra você. Por conta da &lt;em&gt;Same-Origin Policy&lt;/em&gt;, o site do atacante não consegue ler o conteúdo das páginas de &lt;code&gt;banco.com&lt;/code&gt; para roubar o token. Sem o token correto, a requisição forjada morre no middleware.&lt;/p&gt;

&lt;h2&gt;
  
  
  Onde o token é verificado
&lt;/h2&gt;

&lt;p&gt;No Laravel moderno, o middleware &lt;code&gt;VerifyCsrfToken&lt;/code&gt; já vem ativado por padrão no grupo &lt;code&gt;web&lt;/code&gt;. Você não precisa configurar nada pra ele funcionar, ele simplesmente está lá protegendo suas rotas.&lt;/p&gt;

&lt;p&gt;Vale reforçar: a verificação só acontece em métodos que alteram estado (&lt;code&gt;POST&lt;/code&gt;, &lt;code&gt;PUT&lt;/code&gt;, &lt;code&gt;PATCH&lt;/code&gt;, &lt;code&gt;DELETE&lt;/code&gt;). Requisições &lt;code&gt;GET&lt;/code&gt; não são verificadas, e nem deveriam ser, já que por convenção &lt;code&gt;GET&lt;/code&gt; não muda nada no servidor. Essa é justamente a razão de nunca colocarmos ações destrutivas atrás de um simples link &lt;code&gt;GET&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  E quando é uma requisição via JavaScript?
&lt;/h2&gt;

&lt;p&gt;Nem sempre a gente usa formulário tradicional. Quando você faz uma chamada AJAX ou usa Axios, não tem um &lt;code&gt;@csrf&lt;/code&gt; no HTML. Nesses casos, o Laravel também disponibiliza o token de outras formas.&lt;/p&gt;

&lt;p&gt;Uma opção clássica é colocar o token em uma meta tag no &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"csrf-token"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"{{ csrf_token() }}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E então mandar ele no cabeçalho da requisição:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;meta[name="csrf-token"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/perfil&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;X-CSRF-TOKEN&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;nome&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Lucien&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O middleware sabe procurar o token tanto no campo &lt;code&gt;_token&lt;/code&gt; do corpo quanto no cabeçalho &lt;code&gt;X-CSRF-TOKEN&lt;/code&gt;. Se você usa Axios com o starter kit do Laravel, boa parte disso já vem configurada automaticamente, inclusive a leitura do cookie &lt;code&gt;XSRF-TOKEN&lt;/code&gt; que o framework envia.&lt;/p&gt;

&lt;h2&gt;
  
  
  E as APIs? Precisam de token CSRF?
&lt;/h2&gt;

&lt;p&gt;Essa é uma dúvida comum. APIs &lt;em&gt;stateless&lt;/em&gt;, autenticadas por token (tipo Sanctum com tokens de acesso ou JWT), &lt;strong&gt;não precisam&lt;/strong&gt; de proteção CSRF. E o motivo é direto: CSRF só é um problema quando a autenticação depende de algo que o navegador envia sozinho, como o cookie de sessão.&lt;/p&gt;

&lt;p&gt;Quando a autenticação é feita por um header &lt;code&gt;Authorization: Bearer &amp;lt;token&amp;gt;&lt;/code&gt;, o navegador não anexa esse cabeçalho automaticamente. O site malicioso teria que conhecer o token e adicioná-lo na mão, e se ele já tem o token, o CSRF é o menor dos seus problemas. Por isso as rotas do arquivo de API do Laravel ficam fora do middleware &lt;code&gt;web&lt;/code&gt; e não passam pela verificação de token.&lt;/p&gt;

&lt;p&gt;O cuidado com CSRF vale principalmente para aplicações que usam sessão baseada em cookie, que é o caso da maioria das aplicações web tradicionais com Blade.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resumindo
&lt;/h2&gt;

&lt;p&gt;CSRF é um ataque que abusa do fato de o navegador enviar seus cookies de sessão automaticamente, permitindo que um site malicioso forje requisições autenticadas em seu nome. A defesa é o token sincronizador: um segredo que só a sua aplicação conhece e que precisa acompanhar toda requisição que altera estado.&lt;/p&gt;

&lt;p&gt;No Laravel isso é praticamente transparente pra gente. Basta lembrar do &lt;code&gt;@csrf&lt;/code&gt; nos formulários e mandar o token nos cabeçalhos das requisições via JavaScript, que o middleware &lt;code&gt;VerifyCsrfToken&lt;/code&gt; cuida do resto. Da próxima vez que aparecer aquele &lt;code&gt;419 Page Expired&lt;/code&gt;, você já sabe: alguém esqueceu de mandar o token.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>php</category>
      <category>security</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Property Hooks no PHP 8.4</title>
      <dc:creator>Lucien Risso Correia</dc:creator>
      <pubDate>Tue, 08 Oct 2024 19:55:12 +0000</pubDate>
      <link>https://dev.to/luciencorreia/property-hooks-no-php-84-2jld</link>
      <guid>https://dev.to/luciencorreia/property-hooks-no-php-84-2jld</guid>
      <description>&lt;p&gt;O PHP 8.4, lançado em 21 de novembro de 2024, trouxe um recurso muito aguardado pela comunidade: os property hooks! Inspirado por outras linguagens como C#, Swift e Kotlin esse novo recurso tira a gambiarra dos métodos mágicos &lt;code&gt;__set()&lt;/code&gt; e &lt;code&gt;__get()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Vou mostrar um exemplo de como faz atualmente para termos getter e setters sem precisar criar a propriedade como privativa e criar dois novos métodos com nomes diferentes da propriedades.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Foo&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="nv"&gt;$bar&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$value&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s2"&gt;"!!!"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;"!!!"&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Usando o &lt;code&gt;__get()&lt;/code&gt; e &lt;code&gt;__set()&lt;/code&gt; consigo deixar o $bar público quando defino valor e quando busco o valor, porém com implementação diferente e sem ter que criar métodos com nomes distintos da propriedade. Em exemplo visual ficaria assim o uso:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;
&lt;span class="nv"&gt;$foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Foo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nv"&gt;$foo&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"new release"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// aqui o valor que ficará salvo seria "new release!!!"&lt;/span&gt;

&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$foo&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// aqui retornaria "!!!new release!!!"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora imagine como ficaria o &lt;code&gt;__get()&lt;/code&gt; e &lt;code&gt;__set()&lt;/code&gt; com outras propriedades, uma confusão total. Outra maneira de fazer isso seria criando um método &lt;code&gt;getBar()&lt;/code&gt; e um outro &lt;code&gt;setBar()&lt;/code&gt;, mas isso considerando apenas uma propriedade e no uso ficaria diferente do anterior:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Foo&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="nv"&gt;$bar&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;setBar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$value&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s2"&gt;"!!!"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getBar&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;"!!!"&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nv"&gt;$foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Foo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nv"&gt;$foo&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setBar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'new release'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// aqui o valor que ficará salvo seria "new release!!!"&lt;/span&gt;

&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$foo&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getBar&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// aqui retornaria "!!!new release!!!"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Eu particularmente acho meio chato criar novos métodos para esse caso de uso, prefiro muito usar a chamada direta da propriedade tanto para pegar quando definir seu valor. Esse novo recurso chega para resolver essa bagunça e permitir definir o &lt;code&gt;get&lt;/code&gt; e &lt;code&gt;set&lt;/code&gt; individualmente junto com a declaração na classe.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Foo&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$bar&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$value&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s2"&gt;"!!!"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"!!!"&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esse novo código faz a mesma coisa, só que direto na propriedade, sem criar novos métodos nem usar &lt;code&gt;__get()&lt;/code&gt; e &lt;code&gt;__set()&lt;/code&gt;, que precisam de tratamento para cada propriedade da classe. Na forma curta do &lt;code&gt;set&lt;/code&gt;, o valor da expressão é o que fica gravado na propriedade.&lt;/p&gt;

&lt;p&gt;Para ver todos os detalhes, como hooks em interfaces e propriedades virtuais, leia a &lt;a href="https://www.php.net/manual/pt_BR/language.oop5.property-hooks.php" rel="noopener noreferrer"&gt;documentação oficial de property hooks&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>php</category>
      <category>release</category>
    </item>
    <item>
      <title>Laravel 11</title>
      <dc:creator>Lucien Risso Correia</dc:creator>
      <pubDate>Tue, 12 Mar 2024 12:22:45 +0000</pubDate>
      <link>https://dev.to/luciencorreia/laravel-11-31c9</link>
      <guid>https://dev.to/luciencorreia/laravel-11-31c9</guid>
      <description>&lt;p&gt;Laravel 11 chegou com algumas mudanças que posso dizer "finalmente" e umas outras "pra que isso?".&lt;/p&gt;




&lt;h4&gt;
  
  
  Controller simplificado
&lt;/h4&gt;

&lt;p&gt;O controller base foi simplificado e não estende mais o Controller interno do Laravel, sendo assim quando precisar do &lt;code&gt;AuthorizesRequests&lt;/code&gt; ou do &lt;code&gt;ValidatesRequests&lt;/code&gt; precisará adicionar a cada controller que for utilizar.&lt;/p&gt;

&lt;h4&gt;
  
  
  Rate limit em segundos
&lt;/h4&gt;

&lt;p&gt;Agora é possível definir rate limits em segundos em vez de minutos, utilizando o &lt;code&gt;Limit::perSecond()&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Novos comandos de criação do artisan
&lt;/h4&gt;

&lt;p&gt;Agora temos comando para criação de class, enum, interface e trait:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan make:class
php artisan make:enum
php artisan make:interface
php artisan make:trait
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Helper once
&lt;/h4&gt;

&lt;p&gt;Agora você pode cachear um retorno de função e sempre ter o mesmo retorno nas chamadas subsequentes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;once&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;random_int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 123&lt;/span&gt;
&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 123 (cached result)&lt;/span&gt;
&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 123 (cached result)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Menos arquivos padrões
&lt;/h4&gt;

&lt;p&gt;Se olhar a pasta &lt;code&gt;app/Http&lt;/code&gt; vai ver somente o controller agora, sem o &lt;code&gt;Kernel.php&lt;/code&gt; e a pasta &lt;code&gt;Middlewares&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Campo 'password' pode ser com outro nome agora
&lt;/h4&gt;

&lt;p&gt;Finalmente, depois de anos de espera os Devs BRs que caíram num projeto que o banco é em português poderão utilizar o nome da coluna senha na tabela de usuario como 'senha' em vez de 'password'. O método &lt;code&gt;getAuthPasswordName()&lt;/code&gt; foi adicionado ao &lt;code&gt;Authenticatable&lt;/code&gt; permitindo alterar o nome da propriedade da senha.&lt;/p&gt;

&lt;h4&gt;
  
  
  Migrations de alterações ficaram mais chatinhas
&lt;/h4&gt;

&lt;p&gt;Agora toda vez que alterar uma coluna pela migration precisará reescrever todas as alterações anteriores novamente para não voltar ao padrão. Digamos que na criação foi adicionado um comentário na coluna, e em uma migration posterior você altera para ter um valor padrão, para não perder o comentário terá que chamar o método novamente ou irá voltar para o padrão que é sem comentário. Particularmente achei isso ruim.&lt;/p&gt;

&lt;h4&gt;
  
  
  MariaDB
&lt;/h4&gt;

&lt;p&gt;Agora o Laravel possui um driver específico pro MariaDB, em vez de utilizar o driver do MySQL agora pode utilizar o mariadb nas configurações do banco. O que isso muda por enquanto é em relação ao &lt;code&gt;uuid&lt;/code&gt;, mas futuramente deverá ter mais coisas específicas pro banco.&lt;/p&gt;

&lt;h4&gt;
  
  
  Carbon 3
&lt;/h4&gt;

&lt;p&gt;Agora o Laravel suporta tanto o Carbon 2 quanto o Carbon 3, é só atualizar nas dependências do composer e fazer os ajustes conforme a documentação do Carbon no que precisar.&lt;/p&gt;

&lt;h4&gt;
  
  
  Registro de Providers
&lt;/h4&gt;

&lt;p&gt;Agora o registro de providers foi movido para o arquivo &lt;code&gt;bootstrap/providers.php&lt;/code&gt; e retirado do &lt;code&gt;config/app.php&lt;/code&gt;. Para packages que criavam arquivos nessa pasta agora é preciso atualizar o método para o &lt;code&gt;ServiceProvider::addProviderToBootstrapFile()&lt;/code&gt;.&lt;/p&gt;




&lt;p&gt;Essas são as mudanças que achei interessante comentar, pra saber de todas é só ler o &lt;a href="https://laravel.com/docs/11.x/releases" rel="noopener noreferrer"&gt;release notes&lt;/a&gt; e o &lt;a href="https://laravel.com/docs/11.x/upgrade" rel="noopener noreferrer"&gt;upgrade guide&lt;/a&gt; na documentação do Laravel.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>php</category>
      <category>backend</category>
    </item>
    <item>
      <title>Gerência de Estado no Flutter</title>
      <dc:creator>Lucien Risso Correia</dc:creator>
      <pubDate>Mon, 05 Feb 2024 20:09:48 +0000</pubDate>
      <link>https://dev.to/luciencorreia/gerencia-de-estado-no-flutter-1828</link>
      <guid>https://dev.to/luciencorreia/gerencia-de-estado-no-flutter-1828</guid>
      <description>&lt;p&gt;O ano era 2021 e a comunidade Flutter estava agitada demais com algumas tretas envolvendo o time do Flutter e desenvolvedores da comunidade, nessa mesma época o tal state management estava no hype de assuntos da comunidade. Na época escrevi um texto tirando sarro dessas polêmicas e satirizando os principais packages de gerenciamento de estado do Flutter.&lt;/p&gt;

&lt;p&gt;Em projetos futuros a esse texto ainda continuou a discussão sobre qual package utilizar para isso, e a treta sempre foi grande. Chegamos em 2024 e sinto que isso deixou de ser uma rixa e finalmente os devs Flutter entenderam que no final tudo é Streams ou Observers, ou talvez não...&lt;/p&gt;




&lt;h3&gt;
  
  
  Observer
&lt;/h3&gt;

&lt;p&gt;O Observer Pattern, também conhecido como Publish/Subscribe, é um padrão de design que define um mecanismo de comunicação entre objetos. Nesse padrão, um objeto, chamado Subject, mantém uma lista de objetos Observers que dependem dele. Quando o estado do Subject muda, ele notifica todos os Observers, que podem então atualizar suas próprias interfaces.&lt;/p&gt;

&lt;p&gt;No Flutter esse padrão é implementado no ChangeNotifier, onde se pode criar uma classe com as propriedades desejadas pro estado que quer gerenciar e métodos que manipulam e notificam a mudança de estado pros Observers. Veja um exemplo de uso básico de gerenciamento de estado com Observer em Flutter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyState&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;ChangeNotifier&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;incrementCount&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;notifyListeners&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyWidget&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;StatefulWidget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;_MyWidgetState&lt;/span&gt; &lt;span class="n"&gt;createState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_MyWidgetState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;_MyWidgetState&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MyWidget&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;MyState&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MyState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;initState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;initState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addListener&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;{});&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BuildContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Count: &lt;/span&gt;&lt;span class="si"&gt;${state.count}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nesse exemplo, a classe MyState é um Subject. Ela define uma interface para registrar e remover Observers (o método addListener()) e notifica os Observers quando seu estado muda (o método notifyListeners()).&lt;/p&gt;

&lt;p&gt;A classe MyWidget é um Observer. Ela se registra como um Observer da classe MyState no método initState(). Quando o estado da classe MyState muda, o método update() da classe MyWidget é chamado, o que faz com que o widget seja reconstruído.&lt;/p&gt;

&lt;p&gt;Com o Provider podemos simplificar a parte de widget e retirar a parte de implementação do trecho do &lt;code&gt;initState&lt;/code&gt;, já que o próprio widget dele já faz essa reconstrução quando recebe notificação que o estado mudou. Com isso temos pequenas mudanças no código de widget e ele ficaria assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyWidget&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;StatelessWidget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BuildContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ChangeNotifierProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;create:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;MyState&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Consumer&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MyState&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;builder:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;child&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nl"&gt;children:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
              &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Count: &lt;/span&gt;&lt;span class="si"&gt;${state.count}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
              &lt;span class="n"&gt;ElevatedButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nl"&gt;onPressed:&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;incrementCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Incrementar'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
              &lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="p"&gt;],&lt;/span&gt;
          &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lembre-se: o Provider tem como foco ser uma biblioteca para injeção de dependência utilizando a arvore de widgets, a classe Consumer auxilia no uso das dependências injetadas no contexto de Widget, o foco do Provider não é gerenciar estado.  &lt;/p&gt;




&lt;h3&gt;
  
  
  Stream
&lt;/h3&gt;

&lt;p&gt;Stream é uma sequência assíncrona de eventos. Ela pode ser usada para representar dados que mudam ao longo do tempo, como a localização do usuário, a entrada do teclado ou a saída de um sensor.&lt;/p&gt;

&lt;p&gt;Um exemplo de uso se Stream para gerenciar estado no Flutter com um contador progressivo que incrementa o valor a cada segundo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyState&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="n"&gt;Stream&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="n"&gt;countStream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="n"&gt;Stream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;periodic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;seconds:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyWidget&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;StatelessWidget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;MyState&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MyState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BuildContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;StreamBuilder&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;stream:&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;countStream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;builder:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;snapshot&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;snapshot&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hasData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Count: &lt;/span&gt;&lt;span class="si"&gt;${snapshot.data}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Aguardando...'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nesse exemplo usamos o &lt;code&gt;StremBuilder&lt;/code&gt; para poder atualizar o widget a cada troca de valor, mas também podemos fazer sem ele com o famoso &lt;code&gt;setState&lt;/code&gt; escutando os eventos da Stream com o &lt;code&gt;listen&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyWidget&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;StatefulWidget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;_MyWidgetState&lt;/span&gt; &lt;span class="n"&gt;createState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_MyWidgetState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;_MyWidgetState&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MyWidget&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;MyState&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MyState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;initState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;initState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;countStream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;{});&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BuildContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Count: &lt;/span&gt;&lt;span class="si"&gt;${state.count}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;E é sobre isso que venho lembrar e ajudar a fixar na cabecinha dos devs iniciantes em Flutter: quem gerencia o estado é você e não o package. O que quero lembrar é que independente de está usando BLoC ou MobX, Riverpod ou Solidart, GetX ou setState, o resultado final dependerá de como você escreveu a solução. E se não gostou de nenhuma implementação de Observer dos packages, crie sua própria, no final ou é feito em cima de Stream ou em cima de Observer.&lt;/p&gt;

&lt;p&gt;Vou listar qual usa o quê pra exemplificar:&lt;/p&gt;

&lt;h4&gt;
  
  
  Packages que utilizam Stream:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;BLoC&lt;/li&gt;
&lt;li&gt;RxDart&lt;/li&gt;
&lt;li&gt;GetX&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Packages que utilizam Observer:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;MobX&lt;/li&gt;
&lt;li&gt;ChangeNotifier&lt;/li&gt;
&lt;li&gt;Flutter Hooks&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Por trás dos panos eles utilizam basicamente a mesma lógica, porém com implementações diferentes que mudam como será escrito o código. Mas igualmente, quem faz o gerenciamento é quem escreve a aplicação em si. Além disso o que ocorre muito é confundirem state managment com dependencie injection, no caso de GetX ou Provider por exemplo, que possuem essa implementação a mais para compor o package e tornar mais completo. São coisas que costumam serem necessitas juntamente porém já não são mais em si state managment.&lt;/p&gt;




&lt;p&gt;Bom códigos e best reguards!&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
    </item>
    <item>
      <title>Kubernetes: criando seu primeiro Pod</title>
      <dc:creator>Lucien Risso Correia</dc:creator>
      <pubDate>Wed, 10 Jan 2024 19:21:21 +0000</pubDate>
      <link>https://dev.to/luciencorreia/kubernetes-criando-seu-primeiro-pod-4jc0</link>
      <guid>https://dev.to/luciencorreia/kubernetes-criando-seu-primeiro-pod-4jc0</guid>
      <description>&lt;p&gt;Segundo a documentação do Kubernetes um Pod é a menor unidade computacional que você pode criar e gerenciar no Kubernetes. É um encapsulamento de um ou mais containers que utilizam recursos de hardware e rede compartilhados entre si, como se essas aplicações estivessem rodando em uma mesma máquina em servidores VPS por exemplo.&lt;/p&gt;

&lt;p&gt;Vamos subir um Pod simples com o nginx primeiramente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Pod&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para aplicar as alterações vamos salvar esse código em um arquivo pod.yaml e rodar o comando do kubectl: &lt;code&gt;kubectl apply -f pod.yaml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Para verificar se terminou certinho podemos rodar &lt;code&gt;kubectl get pods&lt;/code&gt; e o resultado deve ser algo parecido com:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;NAME    READY   STATUS    RESTARTS   AGE
nginx   1/1     Running   0          20s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora temos um Pod rodando um container que utiliza a imagem do nginx, ou seja, se entrar dentro dele e fizermos uma requisição pro localhost deve retornar a página default do nginx. Para facilitar a visualização vamos permitir o acesso do pod externamente pela porta 8080 com o comando &lt;code&gt;kubectl port-forward pod/nginx 8080:80&lt;/code&gt;. O &lt;code&gt;port-forward&lt;/code&gt; funciona igual no minikube, sem nenhum comando extra. Com isso podemos ver a página default do nginx acessando localhost:8080&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>docker</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
