<?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>Forem: Textos em Português</title>
    <description>The latest articles on Forem by Textos em Português (@portugues).</description>
    <link>https://forem.com/portugues</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.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F1900%2F6d33d18b-8d25-46ca-bc4c-8773d949376f.png</url>
      <title>Forem: Textos em Português</title>
      <link>https://forem.com/portugues</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/portugues"/>
    <language>en</language>
    <item>
      <title>Como eu uso IA de graça para transformar podcasts em lições práticas</title>
      <dc:creator>Fabio Hiroki</dc:creator>
      <pubDate>Thu, 18 Sep 2025 15:43:45 +0000</pubDate>
      <link>https://forem.com/portugues/como-eu-uso-ia-de-graca-para-transformar-podcasts-em-licoes-praticas-32k7</link>
      <guid>https://forem.com/portugues/como-eu-uso-ia-de-graca-para-transformar-podcasts-em-licoes-praticas-32k7</guid>
      <description>&lt;p&gt;Vamos ser honestos: &lt;strong&gt;o quanto do último podcast que você ouviu você realmente lembra?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Se você é como a maioria das pessoas, a resposta provavelmente é "não muito". Passamos horas toda semana consumindo conselhos incríveis e transformadores das pessoas mais inteligentes do mundo, apenas para que tudo desapareça de nossas mentes em 48 horas. A lacuna entre ouvir e fazer é gigantesca.&lt;/p&gt;

&lt;p&gt;Aqui está o truque de IA gratuito que eu uso para consertar isso.&lt;/p&gt;

&lt;h2&gt;
  
  
  O Truque: De Podcast a Plano de Ação em 60 Segundos
&lt;/h2&gt;

&lt;p&gt;Aqui está o único passo que você precisa:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Pegue a URL do YouTube&lt;/strong&gt; do podcast que você quer analisar.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Abra o &lt;a href="https://notebooklm.google.com/" rel="noopener noreferrer"&gt;NotebookLM do Google&lt;/a&gt;&lt;/strong&gt; e clique em “Create New“ (Criar Novo).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Clique em “Youtube” e cole a URL&lt;/strong&gt; como uma nova fonte.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use este prompt&lt;/strong&gt; no chat:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Você é um analista de tecnologia especialista em traduzir conceitos amplos em conselhos acionáveis para engenheiros de software. Meu objetivo é extrair as ideias mais relevantes e aplicáveis desta fonte para o meu trabalho.

Instruções:
Analise a fonte fornecida da perspectiva de um engenheiro de software. Identifique os 3 principais conceitos, modelos mentais ou estratégias que são mais aplicáveis ao campo da engenharia de software.

Para cada conceito que você identificar, apresente-o usando a seguinte estrutura clara e concisa. Não me faça perguntas; forneça a informação diretamente.

🚀 Conceito 1: [Nome do Conceito]

Explicação Simples: Em 1-2 frases, o que é este conceito em termos simples, de acordo com o podcast? Forneça uma citação direta do palestrante que melhor encapsula a ideia.

Relevância para Engenheiros: Por que este conceito é particularmente relevante para o desenvolvimento de software, dinâmica de equipe, resolução de problemas ou arquitetura de sistemas?

Aplicação Prática: Forneça um exemplo concreto de como posso aplicar este conceito no meu trabalho esta semana. (ex: uma pergunta a ser feita em uma revisão de código, um princípio para projetar uma nova funcionalidade, uma maneira de me comunicar com minha equipe).
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A verdadeira mágica aqui está na primeira linha: "Você é um especialista..." Isso é chamado de "prompt com persona", e é a chave para obter resultados hiper-relevantes.&lt;/p&gt;

&lt;p&gt;Você pode, e deve, alterar isso para se adequar à sua própria vida e trabalho. Dica Pro: Você pode usar uma LLM para editar o prompt para você.&lt;/p&gt;

&lt;h2&gt;
  
  
  Colocando à Prova: Um Exemplo do Mundo Real
&lt;/h2&gt;

&lt;p&gt;Eu executei exatamente esse fluxo de trabalho em um podcast recente de Lenny Rachitsky sobre o Mercado Livre:&lt;br&gt;
  &lt;iframe src="https://www.youtube.com/embed/puY_dxVKEwU"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Aqui está o resultado do NotebookLM:&lt;/p&gt;

&lt;p&gt;Como um analista de tecnologia especialista, analisei a fonte fornecida para identificar os conceitos mais relevantes e aplicáveis para engenheiros de software. Aqui estão os três principais, apresentados com conselhos práticos para o seu trabalho:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🚀 Conceito 1: Propriedade Integrada de Produto e Engenharia&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Explicação Simples&lt;/strong&gt;: No Mercado Livre, há uma indefinição deliberada das linhas entre as funções de engenharia e produto, com uma forte ênfase nos engenheiros assumindo uma propriedade significativa das decisões de produto. O objetivo não é determinar a propriedade pelo cargo, mas por quem é mais adequado para a função, muitas vezes os próprios líderes de engenharia. Como afirma Sebastian Barrios, “é difícil separar onde a engenharia para e o produto começa, e não sentimos que apenas ter um título deveria determinar quem é o dono”.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Relevância para Engenheiros:&lt;/strong&gt; Este conceito é profundamente relevante para o desenvolvimento de software porque impulsiona os engenheiros para além da mera implementação técnica, para uma compreensão holística do produto, dos usuários e das necessidades do negócio. Ele fomenta um senso mais profundo de responsabilidade pelo sucesso do produto, garantindo que a viabilidade técnica se alinhe perfeitamente com o valor para o usuário e os objetivos de negócio. Espera-se que os engenheiros combinem a compreensão do “que é tecnicamente possível” com “quais são as necessidades do negócio, quais são as necessidades dos usuários, o que os usuários estão fazendo, como vou medir isso”.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Aplicação Prática:&lt;/strong&gt; Ao projetar ou implementar uma nova funcionalidade esta semana, &lt;strong&gt;envolva-se ativamente com seu contexto de negócio e de usuário&lt;/strong&gt;. Antes de escrever o código, pergunte a si mesmo: “Como o usuário experimentará esse fluxo, e ele o está entendendo?”. Considere o impacto pretendido da funcionalidade no usuário e como seu sucesso seria medido, em vez de focar apenas nos requisitos técnicos.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;🚀 Conceito 2: Viés por Expertise Técnica Profunda&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Explicação Simples:&lt;/strong&gt; O Mercado Livre valoriza muito os engenheiros que possuem conhecimento técnico profundo e estão intimamente familiarizados com os detalhes da tecnologia que usam. Há um “forte viés para a engenharia, para ser técnico, para estar a fundo nos detalhes”. Isso significa uma baixa tolerância para compreensão superficial ou para depender de outros para especificidades técnicas.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Relevância para Engenheiros:&lt;/strong&gt; Para engenheiros de software, este modelo mental enfatiza a importância crítica do domínio técnico. Ele promove a construção de sistemas robustos e escaláveis e permite que os engenheiros liderem discussões de forma eficaz, sem precisar consultar outros para obter informações técnicas fundamentais. Essa compreensão técnica profunda é crucial para a resolução eficiente de problemas, decisões de arquitetura e manutenção de uma alta qualidade nas implantações.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Aplicação Prática:&lt;/strong&gt; Em sua próxima discussão técnica ou revisão de código, esteja preparado para articular os detalhes técnicos subjacentes da sua solução ou de um componente que você está revisando. Em vez de dizer “preciso verificar com fulano para entender os detalhes,” esforce-se para fornecer você mesmo uma explicação abrangente da tecnologia, suas escolhas e suas implicações.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🚀 &lt;strong&gt;Conceito 3: Incentivo à Tomada de Risco e Aprendizado com Falhas de 'Mercado'&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Explicação Simples:&lt;/strong&gt; A empresa fomenta uma cultura onde as equipes são encorajadas a correr riscos e não são penalizadas por lançar funcionalidades que possam falhar devido à recepção do mercado ou a ideias falhas. Sebastian Barrios afirma, “nós realmente empoderamos nossas equipes para cometer erros, tipo, ninguém vai ser demitido por lançar algo que não funcionou no sentido de que talvez o mercado não estivesse pronto ou tivéssemos a ideia errada sobre onde implementar”. Isso contrasta com uma baixa tolerância a falhas relacionadas à má qualidade ou a interrupções do sistema.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Relevância para Engenheiros:&lt;/strong&gt; Essa estratégia é vital para a inovação no desenvolvimento de software. Ela permite que os engenheiros experimentem novas ideias e funcionalidades, fomentando a criatividade e um ciclo de aprendizado rápido, sem o medo paralisante de repercussões negativas por resultados fora da qualidade técnica. Ela apoia diretamente uma “alta velocidade de execução” em um mercado dinâmico, priorizando o aprendizado e a adaptação.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Aplicação Prática:&lt;/strong&gt; Esta semana, ao propor uma nova funcionalidade ou uma mudança significativa, enquadre-a como um experimento com hipóteses claras sobre a recepção do usuário ou do mercado. Seja explícito sobre as suposições que estão sendo testadas e como o sucesso ou o fracasso (em termos de adequação ao mercado, não de qualidade técnica) fornecerá um aprendizado valioso para iterações futuras. Essa abordagem encoraja visões ousadas e pivôs rápidos se as suposições iniciais se mostrarem incorretas.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Apenas a Ponta do Iceberg
&lt;/h2&gt;

&lt;p&gt;E esse é o cerne do truque. É um sistema simples e repetível para transformar o consumo passivo em crescimento ativo.&lt;/p&gt;

&lt;p&gt;O NotebookLM é uma ferramenta poderosa que pode fazer muito mais, mas eu queria manter este artigo curto e focado no único fluxo de trabalho que mais me deu resultados.&lt;/p&gt;

&lt;p&gt;Se você achou isso útil e está interessado em mais conteúdo como este, por favor, me avise! A melhor maneira de fazer isso é deixar um comentário ou clicar no botão 👏 abaixo.&lt;/p&gt;

&lt;p&gt;Ficarei feliz em compartilhar mais dicas e truques sobre como uso IA para aprendizado e produtividade. Me diga o que você gostaria de ver a seguir.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>learning</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Perseguindo uma Vida Melhor: Como Consegui um Emprego em Tecnologia no Exterior</title>
      <dc:creator>Fabio Hiroki</dc:creator>
      <pubDate>Tue, 17 Jun 2025 15:43:54 +0000</pubDate>
      <link>https://forem.com/portugues/perseguindo-uma-vida-melhor-como-consegui-um-emprego-em-tecnologia-no-exterior-2h7k</link>
      <guid>https://forem.com/portugues/perseguindo-uma-vida-melhor-como-consegui-um-emprego-em-tecnologia-no-exterior-2h7k</guid>
      <description>&lt;p&gt;Você já sonhou em se mudar para outro país — começar do zero em um lugar novo, com novas oportunidades e uma melhor qualidade de vida? Para muitos engenheiros de software, a ideia de trabalhar no exterior é ao mesmo tempo empolgante e intimidadora. Eu sei, porque já passei por isso.&lt;/p&gt;

&lt;p&gt;Nasci e cresci no Brasil, um país em desenvolvimento onde, mesmo como engenheiro de software, a vida traz seus próprios desafios. Embora a profissão possa oferecer um salário confortável, o dia a dia era frequentemente ofuscado por preocupações com segurança — coisas simples como usar o celular em público ou caminhar para casa à noite se tornavam fontes de ansiedade. Quando comecei a pensar em formar uma família, essas preocupações cresceram ainda mais. Eu sabia que não queria que meu filho crescesse em um lugar onde a segurança estivesse sempre na minha mente.&lt;/p&gt;

&lt;p&gt;Então veio a pandemia, que só aumentou minha frustração e sensação de inquietação. Foi então que tomei uma decisão: buscar oportunidades no exterior, em países que oferecessem não apenas um emprego, mas uma vida mais segura e equilibrada.&lt;/p&gt;

&lt;p&gt;Neste artigo, compartilharei minha jornada, desde o planejamento e a preparação até a busca por emprego — até o momento em que recebi minha primeira oferta. Se você já considerou fazer uma mudança semelhante, ou se está apenas curioso sobre o que é necessário para se mudar como engenheiro de software, espero que minha história inspire e oriente você.&lt;/p&gt;

&lt;h2&gt;
  
  
  Planejamento e Pesquisa: Mantendo Simples
&lt;/h2&gt;

&lt;p&gt;Olhando para trás, admito que minha fase de planejamento não foi tão meticulosa quanto alguns recomendariam. Não passei meses comparando todos os países ou construindo planilhas detalhadas. Em vez disso, adotei uma abordagem mais direta — alguns diriam até imprudente.&lt;/p&gt;

&lt;p&gt;Meus principais critérios eram simples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Empresas em países desenvolvidos&lt;/li&gt;
&lt;li&gt;Patrocínio de visto disponível&lt;/li&gt;
&lt;li&gt;Bom equilíbrio entre trabalho e vida pessoal&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Com esses filtros em mente, concentrei minha busca de emprego na Europa. Pulei as análises profundas de comparações de custo de vida e caminhos complexos de imigração — pelo menos no início. Minha prioridade era encontrar empresas dispostas a patrocinar meu visto, já que esse era o maior obstáculo para a mudança.&lt;/p&gt;

&lt;p&gt;Claro, à medida que comecei a receber respostas de empregadores e aprendi mais sobre o processo, comecei a pesquisar os detalhes — como salários locais, sistema de saúde e como seria a vida em cada cidade. Mas, no começo, deixei meu desejo por uma vida mais segura e equilibrada me guiar, mantendo o planejamento intencionalmente simples para evitar me sentir sobrecarregado.&lt;/p&gt;

&lt;p&gt;Olhando para trás, percebo que, embora um plano mais detalhado pudesse ter ajudado, às vezes tomar ação é o passo mais importante. Para quem está pensando em fazer uma mudança semelhante, não deixe o perfeccionismo te impedir de começar. Você sempre pode refinar seu plano ao longo do caminho.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preparação e Busca de Emprego: Preparando-se e Agindo
&lt;/h2&gt;

&lt;p&gt;Com a Europa como meu alvo e o patrocínio de visto como uma exigência, meu próximo passo foi preparar meus materiais de candidatura e começar a buscar oportunidades.&lt;/p&gt;

&lt;h3&gt;
  
  
  Atualizando Meu Currículo e Presença Online
&lt;/h3&gt;

&lt;p&gt;Eu sabia que um currículo forte e um perfil no LinkedIn eram cruciais para chamar a atenção dos recrutadores. Atualizei ambos para incluir métricas específicas que demonstravam o impacto do meu trabalho. Em vez de apenas listar responsabilidades, adicionei números e resultados — como melhorias no desempenho de aplicativos, redução de tempo de inatividade ou aumento no engajamento de usuários. Isso ajudou a mostrar aos recrutadores não apenas o que fiz, mas como meu trabalho fez a diferença.&lt;/p&gt;

&lt;h3&gt;
  
  
  Focando em Empresas que Patrocinam Vistos
&lt;/h3&gt;

&lt;p&gt;Concentrei minha busca de emprego em empresas na Europa que ofereciam patrocínio de visto. Usei quadros de empregos e filtros para identificar essas oportunidades e prestei atenção às avaliações de empresas e ao equilíbrio entre trabalho e vida pessoal.&lt;/p&gt;

&lt;h3&gt;
  
  
  Começando Antes de Me Sentir Totalmente Preparado
&lt;/h3&gt;

&lt;p&gt;Embora eu não me sentisse 100% preparado para as entrevistas, decidi começar a me candidatar mesmo assim. Sabia que esperar o “momento perfeito” poderia significar perder oportunidades reais. Todas as minhas entrevistas foram em inglês, que não é minha língua materna, então essas primeiras entrevistas se tornaram sessões de prática extremamente valiosas. Elas me ajudaram a ficar confortável falando sobre minha experiência e habilidades em um ambiente profissional — algo que eu não fazia muito antes. Essa experiência aumentou minha confiança e habilidades de comunicação, mesmo enquanto continuava a estudar e melhorar. Reconheço que essa abordagem não funciona para todas as empresas, especialmente aquelas com processos de recrutamento longos ou altamente competitivos. Mas, para mim, agir cedo foi uma forma de aprender fazendo, em vez de esperar até me sentir completamente pronto.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lidando com Candidaturas e Entrevistas: Aprendendo na Prática
&lt;/h2&gt;

&lt;p&gt;Uma vez que comecei a me candidatar, o processo real começou. Cada candidatura exigia atenção cuidadosa, mas as entrevistas foram onde as coisas ficaram interessantes — e, às vezes, desafiadoras.&lt;/p&gt;

&lt;h3&gt;
  
  
  O Processo de Candidatura
&lt;/h3&gt;

&lt;p&gt;Sempre que havia a opção de enviar uma carta de apresentação, eu aproveitava para personalizá-la de acordo com os produtos, missão e objetivos da empresa. Aprendi que uma carta de apresentação bem elaborada e personalizada pode fazer uma grande diferença — ela ajuda você a se destacar entre outros candidatos e mostra aos recrutadores que você fez sua lição de casa e está genuinamente interessado em contribuir para o sucesso da empresa.&lt;/p&gt;

&lt;h3&gt;
  
  
  Experiências em Entrevistas
&lt;/h3&gt;

&lt;p&gt;Todas as minhas entrevistas foram em inglês, o que adicionou uma camada extra de complexidade. Meu inglês estava longe de ser “perfeito”, e às vezes eu não entendia completamente o que o entrevistador dizia. Mesmo assim, consegui me comunicar bem o suficiente para transmitir minhas ideias. Na maioria das vezes, os entrevistadores foram pacientes e compreensivos.&lt;/p&gt;

&lt;p&gt;Essa experiência me ensinou que você não precisa esperar até que seu inglês esteja perfeito para começar a fazer entrevistas. O que importa é ser capaz de se expressar com clareza e confiança, mesmo que cometa erros ao longo do caminho.&lt;/p&gt;

&lt;p&gt;Enquanto me candidatava, também estudava todos os dias — praticar algoritmos, estruturas de dados, design de sistemas e perguntas comportamentais se tornou parte da minha rotina. Durante as entrevistas, prestei muita atenção à linguagem corporal e às reações dos entrevistadores. Se uma resposta minha não gerava uma reação positiva ou parecia errada, eu considerava isso um feedback indireto. Isso me ajudou a identificar áreas onde precisava melhorar e a focar meus estudos para entrevistas futuras.&lt;/p&gt;

&lt;h3&gt;
  
  
  Aprendendo com Rejeições
&lt;/h3&gt;

&lt;p&gt;Nem toda entrevista resultou em uma oferta. Houve rejeições, e às vezes o feedback era difícil de ouvir. Mas tentei ver cada uma como uma oportunidade de aprendizado. Prestei atenção às perguntas com as quais tive dificuldade e as usei para guiar minhas sessões de estudo. Com o tempo, fiquei melhor em antecipar o que os entrevistadores queriam e como me apresentar como um candidato forte.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fadint2smq3f8jq8vznfj.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fadint2smq3f8jq8vznfj.webp" alt="Photo by Pablo Heimplatz on Unsplash" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Recebendo uma Oferta e Reflexões
&lt;/h2&gt;

&lt;p&gt;Após semanas de candidaturas, entrevistas e muito estudo, finalmente recebi uma oferta de uma empresa na Europa. Esse momento marcou um marco importante na minha jornada — não apenas porque significava que eu poderia me mudar, mas porque validou todo o esforço e persistência que investi.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Oferta e o Que Ela Significou
&lt;/h3&gt;

&lt;p&gt;Quando a oferta chegou, senti uma mistura de empolgação e alívio. Depois de tanta incerteza — especialmente como alguém que nunca havia vivido ou trabalhado no exterior antes —, foi reconfortante saber que minhas habilidades e experiência foram reconhecidas. A empresa estava disposta a patrocinar meu visto, o que significava que eu poderia finalmente começar a planejar minha mudança e um novo capítulo para minha família.&lt;/p&gt;

&lt;h3&gt;
  
  
  Olhando para Trás no Processo
&lt;/h3&gt;

&lt;p&gt;Olhando para trás, percebi o quanto aprendi — não apenas sobre tópicos técnicos, mas sobre mim mesmo e do que sou capaz. Superei barreiras linguísticas, me adaptei a diferentes estilos de entrevista e lidei com rejeições com resiliência. Cada passo, mesmo os mais difíceis, me tornou mais forte e mais preparado para os desafios à frente.&lt;/p&gt;

&lt;h3&gt;
  
  
  Principais Lições
&lt;/h3&gt;

&lt;p&gt;Aqui estão as lições mais importantes que aprendi ao longo do caminho:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Comece Antes de Estar Pronto: Não espere o “momento perfeito”. Comece a se candidatar e fazer entrevistas o quanto antes — você aprenderá e melhorará com cada experiência.&lt;/li&gt;
&lt;li&gt;Personalize Sua Candidatura: Sempre envie uma carta de apresentação personalizada quando possível. Mostre aos recrutadores que você entende a empresa e como pode contribuir.&lt;/li&gt;
&lt;li&gt;Use Entrevistas como Prática: Mesmo que esteja nervoso ou seu inglês não seja perfeito, use cada entrevista como uma chance de aprender e crescer.&lt;/li&gt;
&lt;li&gt;Preste Atenção ao Feedback: Observe as reações dos entrevistadores e use-as como feedback indireto para guiar seus estudos e preparação.&lt;/li&gt;
&lt;li&gt;Permaneça Persistente: Rejeições fazem parte do processo. Aprenda com elas, ajuste sua abordagem e continue.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Este artigo é uma visão geral da minha experiência em conseguir um emprego no exterior. Se você quiser que eu mergulhe mais fundo em alguma parte específica — como estudei, como organizei minhas candidaturas, como gerenciei meu tempo enquanto trabalhava em tempo integral, ou qualquer outro tópico —, por favor, deixe um comentário! Seu feedback me ajudará a decidir no que focar em artigos futuros.&lt;/p&gt;

&lt;p&gt;Vamos aprender e crescer juntos!&lt;/p&gt;

</description>
      <category>career</category>
      <category>beginners</category>
      <category>watercooler</category>
      <category>interview</category>
    </item>
    <item>
      <title>Curso gratuito de Typescript 2025 - Aula 002</title>
      <dc:creator>Leandro Lopes</dc:creator>
      <pubDate>Sun, 05 Jan 2025 20:17:40 +0000</pubDate>
      <link>https://forem.com/portugues/curso-gratuito-de-typescript-2025-aula-002-2df6</link>
      <guid>https://forem.com/portugues/curso-gratuito-de-typescript-2025-aula-002-2df6</guid>
      <description>&lt;p&gt;Na aula anterior, configuramos nosso ambiente de desenvolvimento e mergulhamos nos &lt;code&gt;Tipos Primitivos&lt;/code&gt; do Typescript.&lt;/p&gt;

&lt;p&gt;Na aula de hoje, vamos aprender a trabalhar com &lt;code&gt;Objetos&lt;/code&gt; e &lt;code&gt;Arrays&lt;/code&gt; em Typescript.&lt;/p&gt;




&lt;h2&gt;
  
  
  Introdução
&lt;/h2&gt;

&lt;p&gt;Nessa aula, vamos aprender sobre &lt;code&gt;Objetos&lt;/code&gt; e &lt;code&gt;Arrays&lt;/code&gt; em Typescript. Vamos explorar diferentes formas de como podemos criar objetos e arrays em nossos projetos com Typescript.&lt;/p&gt;

&lt;h2&gt;
  
  
  Objetos Literais
&lt;/h2&gt;

&lt;p&gt;Uma das formas mais simples de criar um &lt;code&gt;objeto&lt;/code&gt; é através de &lt;code&gt;objetos literais&lt;/code&gt;. Essa abordagem é particularmente útil quando você já tem conhecimento prévio das propriedades do objeto, uma vez que não é possível adicionar novas propriedades posteriormente.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;objeto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;chaveA&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;value&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;chaveB&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;value&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="nx"&gt;objeto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chaveC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;value&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frot0jhws6rzg6kym9qt5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frot0jhws6rzg6kym9qt5.png" alt="Imagem de um código de exemplo de um objeto literal" width="800" height="296"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Index Signature
&lt;/h2&gt;

&lt;p&gt;Uma forma de criar objetos dinâmicos é utilizando &lt;code&gt;Index Signature&lt;/code&gt;. Essa abordagem é especialmente útil quando não sabemos antecipadamente quais serão as propriedades do objeto.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;objeto&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="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;chaveA&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;value A&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;chaveB&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;value B&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="nx"&gt;objeto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chaveC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;value C&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;objeto&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb9i19y5apu4zmreey7sj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb9i19y5apu4zmreey7sj.png" alt="Imagem de um código de exemplo de um Index Signature" width="800" height="534"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Record
&lt;/h2&gt;

&lt;p&gt;Outra forma que temos de criar objetos dinâmicos em Typescript é utilizando &lt;code&gt;Record&lt;/code&gt;. O &lt;code&gt;Record&lt;/code&gt; é um dos &lt;code&gt;Utility Type&lt;/code&gt; da caixa de ferramentas do Typescript. Vamos explorar mais sobre os Utility Types mais adiante. Por enquanto, o que você precisa saber é que ao utilizar &lt;code&gt;Record&lt;/code&gt;, precisamos especificar o tipo para a &lt;code&gt;chave (key)&lt;/code&gt; e para o &lt;code&gt;valor (value)&lt;/code&gt; do objeto entre &lt;code&gt;&amp;lt;&amp;gt;&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;objeto&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;chaveA&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;value A&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;chaveB&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;value B&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;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8nhqwxe046umycn3j1xl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8nhqwxe046umycn3j1xl.png" alt="Imagem de um código de exemplo criando um objeto com Record" width="800" height="534"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Array Literais
&lt;/h2&gt;

&lt;p&gt;A forma mais simples de criar um array é usando um &lt;code&gt;array literal&lt;/code&gt;, que é uma lista de elementos separados por vírgulas dentro de colchetes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;arrayDeNumeros&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&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;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;arrayDeString&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&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;Josh&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;Patrick&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;Lamar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;arrayDeStringENumeros&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)[]&lt;/span&gt; &lt;span class="o"&gt;=&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Alice&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;55&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arrayDeString&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arrayDeNumeros&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arrayDeStringENumeros&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1pl4as15owboi4q3lpwe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1pl4as15owboi4q3lpwe.png" alt="Imagem de um código de exemplo de um array literal" width="800" height="465"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Array Constructor
&lt;/h2&gt;

&lt;p&gt;Você também pode usar o &lt;code&gt;construtor Array&lt;/code&gt; para criar um novo array.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;arrayDeNumeros&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&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;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;arrayDeString&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&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;Josh&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;Patrick&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;Lamar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;arrayDeStringENumeros&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Alice&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;55&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arrayDeString&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arrayDeNumeros&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arrayDeStringENumeros&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhfa8fs8nzgzx3d7lnsz8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhfa8fs8nzgzx3d7lnsz8.png" alt="Imagem de um código de exemplo de um array utilizando constructor" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Você pode acessar o código da aula, acessando o link abaixo: &lt;br&gt;
&lt;a href="https://github.com/d3vlopes/curso-typescript/tree/aula-002" rel="noopener noreferrer"&gt;https://github.com/d3vlopes/curso-typescript/tree/aula-002&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Próxima aula
&lt;/h2&gt;

&lt;p&gt;Na próxima aula, vamos explorar as &lt;code&gt;funções&lt;/code&gt; em Typescript. Vamos aprender como definir o tipo dos parâmetros, tipo de retorno e muito mais!&lt;/p&gt;

&lt;p&gt;Deixe um comentário e compartilhe essa publicação com sua rede para dar uma força e ajudar mais pessoas a aprender Typescript.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>braziliandevs</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Curso gratuito de Typescript 2025</title>
      <dc:creator>Leandro Lopes</dc:creator>
      <pubDate>Sun, 05 Jan 2025 19:52:08 +0000</pubDate>
      <link>https://forem.com/portugues/curso-gratuito-de-typescript-2025-5b3c</link>
      <guid>https://forem.com/portugues/curso-gratuito-de-typescript-2025-5b3c</guid>
      <description>&lt;p&gt;Para ajudar você a conquistar seus objetivos em 2025 como Desenvolvedor de Software, estou disponibilizando um curso completo de Typescript totalmente GRATUITO!&lt;/p&gt;

&lt;p&gt;📚 O que você vai aprender?&lt;br&gt;
🔷 Aula 001 - Tipos Primitivos&lt;br&gt;
🔷 Aula 002 - Objetos e Arrays&lt;br&gt;
🔷 Aula 003 - Funções&lt;br&gt;
🔷 Aula 004 - Outros tipos&lt;br&gt;
🔷 Aula 005 - Union Types, Type Assertion e Literal Types&lt;br&gt;
🔷 Aula 006 - Inferência de tipo&lt;br&gt;
🔷 Aula 007 - Interface e Types&lt;br&gt;
🔷 Aula 008 - Generics&lt;br&gt;
🔷 Aula 009 - Utility Types&lt;br&gt;
🔷 Aula 010 - Classes (Parte 1)&lt;br&gt;
🔷 Aula 011 - Classes (Parte 2)&lt;br&gt;
🔷 Aula 012 - Dicas Extras&lt;br&gt;
🔷 Aula 013 - Desafio prático&lt;/p&gt;

&lt;p&gt;Você vai aprender tudo que você mais vai utilizar ao trabalhar com Typescript no seu dia a dia de forma prática.&lt;/p&gt;

&lt;p&gt;Se você já conhece Javascript, o Typescript será um divisor de águas na sua carreira, trazendo mais segurança e escalabilidade ao seu código.&lt;/p&gt;
&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;Antes de iniciar a aula, precisamos primeiro configurar o setup do nosso ambiente de desenvolvimento, instalando e configurando algumas ferramentas que vamos utilizar.&lt;/p&gt;
&lt;h3&gt;
  
  
  Instalação do Node
&lt;/h3&gt;

&lt;p&gt;Se você não tiver o Node instalado em sua máquina, você pode acessar &lt;a href="https://nodejs.org/en/download" rel="noopener noreferrer"&gt;https://nodejs.org/en/download&lt;/a&gt; e fazer a instalação conforme o seu sistema operacional.&lt;/p&gt;
&lt;h3&gt;
  
  
  Instalação do VS Code
&lt;/h3&gt;

&lt;p&gt;Irei utilizar o VS Code como editor, você pode baixar ele acessando &lt;a href="https://code.visualstudio.com" rel="noopener noreferrer"&gt;https://code.visualstudio.com&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Instalação do Typescript
&lt;/h3&gt;

&lt;p&gt;Com o Node instalado, podemos inciar o projeto e configurar o Typescript.&lt;/p&gt;

&lt;p&gt;Crie uma pasta e abra o terminal nessa pasta recém criada e rode o seguinte comando pressionando &lt;code&gt;ENTER&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm init &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; code &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsffv2l8mcwhynve3zh5u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsffv2l8mcwhynve3zh5u.png" alt="Imagem do terminal" width="800" height="318"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O comando irá criar um arquivo &lt;code&gt;package.json&lt;/code&gt; e abrir o VS Code na pasta. No VS Code click em &lt;code&gt;View &amp;gt; Terminal&lt;/code&gt; para abir o terminal integrado.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkjhs67tqwv53cu3nvu4m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkjhs67tqwv53cu3nvu4m.png" alt="Imagem do VS Code" width="800" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Agora, no terminal integrado do VS Code, rode o seguinte comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i &lt;span class="nt"&gt;-D&lt;/span&gt; typescript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flp3xgqy3ayw6ptl7x7n3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flp3xgqy3ayw6ptl7x7n3.png" alt="Imagem do terminal com o comando npm i -D typescript" width="800" height="259"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Esse comando vai instalar o &lt;code&gt;Typescript&lt;/code&gt; como uma dependência de desenvolvimento no nosso &lt;code&gt;package.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Crie um arquivo chamado &lt;code&gt;tsconfig.json&lt;/code&gt; e adicione a seguinte configuração ao arquivo:&lt;br&gt;
&lt;/p&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="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"compilerOptions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"rootDir"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./src"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"outDir"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./dist"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ES2020"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"strict"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"noEmitOnError"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpcwfd8d4xy6e6bgai6lf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpcwfd8d4xy6e6bgai6lf.png" alt="Imagem do arquivo tsconfig.json" width="800" height="281"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O arquivo &lt;code&gt;tsconfig.json&lt;/code&gt; serve para configurar o compilador do Typescript, existe diversas configurações que podemos fazer, nesse momento estamos interessado apenas nas seguintes configurações:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;rootDir&lt;/code&gt; - Define o caminho para os arquivos Typescript.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;outDir&lt;/code&gt; -  Define a pasta de saida para os arquivos Javascript.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;target&lt;/code&gt; -  Define a versão do Javascript que o compilador deve utilizar para compilar os arquivos.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;strict&lt;/code&gt; -  Habilita o strict mode.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;noEmitOnError&lt;/code&gt; - Não executa a compilação, caso tenha algum erro de tipo.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Você pode conhecer todas as opções disponíveis, acessando &lt;a href="https://www.typescriptlang.org/docs/handbook/compiler-options.html" rel="noopener noreferrer"&gt;https://www.typescriptlang.org/docs/handbook/compiler-options.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Acesse o arquivo &lt;code&gt;package.json&lt;/code&gt; e crie um novo script para build com o comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx tsc &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; node ./dist/index.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fouim9fmwy4m3qbntsms0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fouim9fmwy4m3qbntsms0.png" alt="Imagem do package.json" width="800" height="521"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;O navegador assim como o Node não entende Typescript, precisamos compilar o código Typescript para Javascript para que ele possa entender e executar. Esse comando vai compilar nosso código Typescript para Javascript para que a gente possa executar ele no Node.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Lembre-se, no fim todo o nosso código Typescript vai virar Javascript. Typescript é apenas uma ferramenta utilizada no desenvolvimento para melhorar a segurança de tipo e escalabilidade do nosso código.&lt;/p&gt;

&lt;p&gt;Para finalizar, crie uma pasta chamada &lt;code&gt;src&lt;/code&gt; e um arquivo &lt;code&gt;index.ts&lt;/code&gt; com o seguinte código:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello World&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1rnvh9xof2g2qp6frbc5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1rnvh9xof2g2qp6frbc5.png" alt="Imagem do arquivo index.ts" width="800" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Agora, vamos testar se está tudo funcionado. Abra o terminal e rode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8rravh12mlupssusg2lb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8rravh12mlupssusg2lb.png" alt="Imagem do terminal executando o comando npm run build" width="800" height="210"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ao rodar, se tudo estiver certo, você deve ver no terminal &lt;code&gt;Hello World&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvqxl4uzubr76pucktga9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvqxl4uzubr76pucktga9.png" alt="Imagem do terminal mostrando a saída do comando npm run build" width="800" height="318"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sempre que quiser ver algo no console, vai ser preciso rodar esse comando para compilar o arquivo para Javascript, beleza?&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Tipos primitivos
&lt;/h2&gt;

&lt;p&gt;Em TypeScript, existem seis tipos primitivos que são: &lt;code&gt;string&lt;/code&gt;, &lt;code&gt;number&lt;/code&gt;, &lt;code&gt;boolean&lt;/code&gt;, &lt;code&gt;symbol&lt;/code&gt;, &lt;code&gt;bigint&lt;/code&gt;, &lt;code&gt;null&lt;/code&gt; e &lt;code&gt;undefined&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nome&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Leandro&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Qualquer tipo de string: '' "" ``&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;idade&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 10, 1.57, -5.55&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;adulto&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// true ou false&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;simbolo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;symbol&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Symbol&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;symbol-id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;big&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nulo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;indefinido&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  String
&lt;/h3&gt;

&lt;p&gt;Uma string é qualquer coisa entre aspas. Pode ser &lt;code&gt;aspas simples ('’)&lt;/code&gt;, &lt;code&gt;duplas ("”)&lt;/code&gt; ou &lt;code&gt;crase (&lt;/code&gt;&lt;code&gt;)&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Number
&lt;/h3&gt;

&lt;p&gt;Aqui não tem distinção: inteiros, decimais, positivos, negativos, tudo é tratado como &lt;code&gt;number&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Boolean
&lt;/h3&gt;

&lt;p&gt;O clássico &lt;code&gt;verdadeiro ou falso&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Symbol
&lt;/h3&gt;

&lt;p&gt;Um pouco abstrato, mas &lt;code&gt;symbol&lt;/code&gt; é um identificador único. Pense nele como uma impressão digital para objetos.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bigint
&lt;/h3&gt;

&lt;p&gt;Se um number já é grande, o &lt;code&gt;bigint&lt;/code&gt; é quase infinito. Use para lidar com números que nem calculadora científica resolve.&lt;/p&gt;

&lt;h3&gt;
  
  
  Null
&lt;/h3&gt;

&lt;p&gt;Representa uma variável que não possui valor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Undefined
&lt;/h3&gt;

&lt;p&gt;Representa um valor não inicializado.&lt;/p&gt;




&lt;p&gt;Você pode acessar o código da aula, acessando o link abaixo: &lt;br&gt;
&lt;a href="https://github.com/d3vlopes/curso-typescript/tree/aula-001" rel="noopener noreferrer"&gt;https://github.com/d3vlopes/curso-typescript/tree/aula-001&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Próxima aula
&lt;/h2&gt;

&lt;p&gt;Na próxima aula, vamos aprender sobre &lt;code&gt;Objetos&lt;/code&gt; e &lt;code&gt;Arrays&lt;/code&gt; em Typescript.&lt;/p&gt;

&lt;p&gt;💡 Dúvidas ou problemas?&lt;br&gt;
Teve algum problema com a configuração do setup? Ficou com alguma dúvida sobre a aula? Coloca aqui nos comentários, vamos juntos construir um material de qualidade e acessível a todos.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>braziliandevs</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Usei o Android sem apps Google por dois meses 📱</title>
      <dc:creator>Higor Silva</dc:creator>
      <pubDate>Wed, 27 Dec 2023 01:21:35 +0000</pubDate>
      <link>https://forem.com/portugues/usei-o-android-sem-apps-google-por-dois-meses-5en0</link>
      <guid>https://forem.com/portugues/usei-o-android-sem-apps-google-por-dois-meses-5en0</guid>
      <description>&lt;p&gt;&lt;em&gt;Texto originalmente escrito em 29 de janeiro de 2022&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;No dia 27 de novembro, comecei minha jornada um tanto estranha para quem é de fora do mundo da tecnologia: Comecei a usar o Android (que é um sistema da Google) sem os apps da Google. O quão bizarro ou maravilhoso pode ser usar o sistema do robozinho verde mais privativo? Essas são minhas conclusões:&lt;/p&gt;

&lt;h3&gt;
  
  
  Mas afinal, qual o motivo dessa experiência?
&lt;/h3&gt;

&lt;p&gt;O ponto é simples: abra o “My Activity” da sua conta na Google e veja tudo o que você fez. Reconhece aqueles aplicativos que você abriu? Como o Google sabe de tudo isso? Como ele coleta esses dados e pra quê ele usa isso?&lt;/p&gt;

&lt;p&gt;Existe uma forma para que a Google pare de coletar meus dados? A resposta é sim, mas exige alguns passos mais avançados. Então basta eu trocar meu sistema operacional, certo? Bem…&lt;/p&gt;

&lt;p&gt;Quando o assunto é sistemas operacionais mobile, você deve imaginar em apenas dois nomes: O Android e o iOS (também conhecido como “o do iPhone”). Ambos são muito práticos e são os sistemas que todas as pessoas estão acostumadas a usar no seu dia a dia. Mas existem outros também, embora sejam mais para nichos e usos específicos.A maioria deles são baseados em Linux, como o &lt;a href="https://ubuntu-touch.io/"&gt;Ubuntu Touch&lt;/a&gt;, o &lt;a href="https://pureos.net/"&gt;PureOS&lt;/a&gt; da Librem, &lt;a href="https://sailfishos.org/"&gt;Sailfish OS&lt;/a&gt; e o &lt;a href="https://postmarketos.org/"&gt;postmarketOS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Mas uma coisa que esses sistemas alternativos pecam é na comodidade. Vários apps não possuem uma versão para aquele sistema operacional. WhatsApp, Uber, entre outros não existem. Você pode instalar uma camada de compatibilidade do Android, mas envolve processos mais avançados e em casos extremos, é necessário até patchear/recompilar o kernel.&lt;/p&gt;

&lt;p&gt;Agora se você usar Android, nem precisa se preocupar com isso. Basta baixar o app e usar. Mas o Google vai continuar coletando dados. É aqui que temos o pulo do gato.&lt;/p&gt;

&lt;h3&gt;
  
  
  Segundo ponto: Privacidade sem largar a comodidade
&lt;/h3&gt;

&lt;p&gt;Muitos aplicativos necessitam do Google Play Services, um app da Google que funciona como um conjunto de bibliotecas para os apps funcionarem… Ok, vejamos de outro modo.&lt;/p&gt;

&lt;p&gt;Para alguns apps funcionarem, eles necessitam de alguns códigos que só existem no Google Play Services. Acesso a GPS, uso de alguns serviços na nuvem, etc. Sem o Google Play Services, o seu Uber não vai detectar sua localização e seu WhatsApp não vai receber notificação. Você só receberá mensagens quando abrir o app. Bem incoveniente, né?&lt;/p&gt;

&lt;p&gt;Para contornar esse problema, existe um substituto ao Play Services: O Projeto MicroG, mantido pelo desenvolvedor alemão Marvin Wißfeld. Essa implementação é de código aberto e não conta com os rastreadores da Google. Existem algumas formas de instalação, mas…&lt;/p&gt;

&lt;h3&gt;
  
  
  Terceiro ponto: O sistema funcionaria de forma idêntica ao original. Porém…
&lt;/h3&gt;

&lt;p&gt;Entrando em termos mais técnicos, o que fiz foi: Baixar a variante da &lt;a href="https://lineageos.org/"&gt;LineageOS&lt;/a&gt; (sistema operacional baseado no &lt;a href="https://source.android.com/"&gt;Android Open Source Project&lt;/a&gt;) chamada &lt;a href="https://lineage.microg.org/"&gt;LineageOS for MicroG&lt;/a&gt;. Explico mais sobre como fazer isso em um post futuro.&lt;/p&gt;

&lt;p&gt;Baixando o LineageOS for MicroG, tudo já vinha configurado. Bastava “flashear” o sistema e tudo certo. E… Foi exatamente isso que aconteceu. Não foi necessário configurar mais nada, só precisei logar minha conta da Google para o YouTube.&lt;/p&gt;

&lt;p&gt;A loja de aplicativos não é a Play Store, mas por padrão vem o &lt;a href="https://f-droid.org/"&gt;F-Droid&lt;/a&gt;: Uma loja de aplicativos Android com o diferencial de ter apenas aplicativos de código aberto. E não, você não encontrará o WhatsApp, por exemplo. Para isso, é necessário o download de outra loja: &lt;a href="https://auroraoss.com/"&gt;Aurora Store&lt;/a&gt;. Nele, você pode logar em uma conta anônima e usar a Play Store sem rastreio algum. Todos os aplicativos estão lá.&lt;/p&gt;

&lt;p&gt;Inclusive, caso queira substituir aplicativos proprietários para código aberto, você pode conferir esse &lt;a href="https://github.com/higorslva/foss-android"&gt;guia no GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Após algumas semanas usando o Android dessa maneira, algumas coisas curiosas aconteciam. App do Uber simplesmente parou de pegar minha localização. Minha cidade não é lá tão grande mas caso eu estivesse em um local desconhecido, teria que usar métodos neandertais para me localizar: Pedir informação.&lt;/p&gt;

&lt;p&gt;Da mesma maneira que o Uber me deixou na mão, o WhatsApp parou de receber notificação. Algumas mensagens urgentes eu simplesmente não via pois não tenho costume de abrir o WhatsApp a não ser que eu receba notificação ou queira mandar mensagem pra alguém. Mas notificações não chegavam, o que me forçava abrir o app algumas vezes e me deparar com mensagens de uma hora atrás no limbo.&lt;/p&gt;

&lt;p&gt;Como quis me desapegar de aplicativos do Google, usei outros alternativos daquela lista lá. Todos funcionam muito bem e alguns uso até hoje depois da experiência. Mas eu uso bastante meu computador e os serviços da Google funciona tudo pela nuvem. Um texto que escrevi no Google Keep poderá ser acessado depois no meu computador e vice versa. Eu tive que abrir mão disso e foi bem sofrido.&lt;/p&gt;

&lt;p&gt;Outro ponto negativo foi que o app que gerencia o MicroG simplesmente não abria mais. Caso eu quisesse adicionar uma nova conta do Google, não poderia. Ligar/desligar algumas funções? Esquece.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusão: Valeu a pena?
&lt;/h3&gt;

&lt;p&gt;Se você quiser mais privacidade e considera o uso das bibliotecas da Google pelo MicroG, esteja ciente que tem altas chances de que nem tudo irá funcionar. Algumas vezes é necessário apenas marcar uma opção nas configurações, outras nem solução você terá. Não tenho nada contra a Google e uso seus serviços sem problema nenhum.&lt;/p&gt;

&lt;p&gt;Na minha experiência houve mais contras do que prós, então não tive problema em voltar a usar meu celular como sempre usei. Inclusive, em um próximo post eu mostro como é meu celular, meus aplicativos e como organizo minha vida digital.&lt;/p&gt;

&lt;p&gt;Abraços e se cuidem.&lt;/p&gt;

</description>
      <category>security</category>
      <category>android</category>
      <category>microg</category>
    </item>
    <item>
      <title>Autenticação no Next.js com Usuário e Senha e criando Rotas Privadas.</title>
      <dc:creator>Paulo Ricardo F. S. Junior</dc:creator>
      <pubDate>Mon, 20 Jun 2022 19:46:51 +0000</pubDate>
      <link>https://forem.com/portugues/autenticacao-no-nextjs-com-usuario-e-senha-e-criando-rotas-privadas-137</link>
      <guid>https://forem.com/portugues/autenticacao-no-nextjs-com-usuario-e-senha-e-criando-rotas-privadas-137</guid>
      <description>&lt;h2&gt;
  
  
  Introdução
&lt;/h2&gt;

&lt;p&gt;Autenticação de usuários e acesso restrito a rotas privadas é fundamental para qualquer aplicação, neste artigo/guia vou descrever o passo a passo para realizar a autenticação de usuários que estejam cadastrados na sua base de dados, e que seja necessário realizar o login através de um backend personalizado ou API externa com um login de e-mail e senha. &lt;/p&gt;

&lt;p&gt;Recentemente estava desenvolvendo um projeto, onde surgiu essa necessidade, e pesquisando sobre o assunto, notei que não existem conteúdos com exemplos claros, principalmente se precisar tratar os erros do backend personalizado na sua pagina de login, então decidi juntar essas informações em um único artigo.&lt;/p&gt;

&lt;p&gt;Para iniciar o exemplo, vou partir da premissa de que você já possui uma aplicação Next.js com a estrutura do NextAuth. Caso não, você pode iniciar um novo projeto e configura-lo de forma simples com esse guia:&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://next-auth.js.org/getting-started/example" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fnext-auth.js.org%2Fimg%2Flogo%2Flogo-xs.png" height="auto" class="m-0"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://next-auth.js.org/getting-started/example" rel="noopener noreferrer" class="c-link"&gt;
          Getting Started | NextAuth.js
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;p class="truncate-at-3"&gt;
          The example code below describes how to add authentication to a Next.js app.
        &lt;/p&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fnext-auth.js.org%2Fimg%2Ffavicon.ico"&gt;
        next-auth.js.org
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Estrutura de Pastas
&lt;/h2&gt;

&lt;p&gt;Seguindo os padrões do Next.js você tem:&lt;/p&gt;

&lt;p&gt;📁 pages&lt;/p&gt;

&lt;p&gt;📁 api&lt;/p&gt;

&lt;p&gt;📁 auth &lt;/p&gt;

&lt;p&gt;[…nextauth].ts&lt;/p&gt;

&lt;h2&gt;
  
  
  Login com Email e Senha
&lt;/h2&gt;

&lt;h3&gt;
  
  
  pages/api/auth/[…nextauth].ts
&lt;/h3&gt;

&lt;p&gt;O arquivo nextauth é o responsável por realizar o login, nele vamos configurar os providers, no caso do exemplo, vamos utilizar o Credentials Provider, pode ser configurado outros providers junto com o Credentials Provider, você pode consultar em: &lt;a href="https://next-auth.js.org/providers/" rel="noopener noreferrer"&gt;Next&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Precisamos adicionar no arquivo […nextauth].js, cada parte será explicada posteriormente:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nc"&gt;NextAuth&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nc"&gt;CredentialProvider&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;credentials&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Email: exemplo@exemplo.com&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;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Senha&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password&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;authorize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/users/getByEmail&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;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&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="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userAccount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;userAccount&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="kc"&gt;null&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="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&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="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&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="na"&gt;callbacks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;jwt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &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="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="nx"&gt;user&lt;/span&gt;&lt;span class="p"&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="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&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="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;session&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;session&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="o"&gt;=&amp;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="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&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="nx"&gt;session&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="na"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;jwttoken&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;pages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;signIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/login&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/login&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;jwt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;jwttoken&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="p"&gt;});&lt;/span&gt;



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

&lt;/div&gt;

&lt;p&gt;&lt;u&gt;Name:&lt;/u&gt; Nome a ser exibido no formulário de login;&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Credentials:&lt;/u&gt; As credenciais são usadas para gerar o formulário na pagina de login, se não tiver uma pagina de login personalizada, o NextAuth cria uma pagina, basta acessar: &lt;a href="http://localhost:3000/api/auth/SignIn" rel="noopener noreferrer"&gt;localhost:3000/api/auth/SignIn&lt;/a&gt;. Pode Especificar os campos que espera que sejam enviados ex.: dominio, nome de usuario, senha etc. Essa pagina é padrão do Next Auth. Se possuir uma pagina de login personalizada redirecionaremos o usuário posteriormente.&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Authorize:&lt;/u&gt; Função que faz a chamada API para realizar o login, é nessa função que vai a lógica para consultar o backend personalizado, ou até mesmo acessar uma rota criada nas API Routes da sua aplicação Next.js&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Nessa função o retorno caso a resposta do seu backend ou API sejam inválidos, deve ser nulo.&lt;/li&gt;
&lt;li&gt;O Next Auth espera no retorno dessa função um objeto de User ou NULO.&lt;/li&gt;
&lt;li&gt;No exemplo eu realizei a consulta na rota definida dentro de um TRY CATCH, faço uma verificação condicional, se existir o usuário eu retorno ele, se não, retorno nulo.&lt;/li&gt;
&lt;li&gt;No meu caso, a minha rota de backend retorna um json com error caso o usuário ou senha sejam inválidos, eu capturo esse erro no CATCH e por padrão do Next Auth o usuário sera redirecionado para a pagina de erro, assim como o a pagina de login personalizada, esse comportamento sera tratado a seguir.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;u&gt;Callbacks:&lt;/u&gt; Nesse ponto é criado o Token JWT utilizando o ID do usuário, lembrando que minha API retorna um Objeto de User com ID, EMAIL e NOME.&lt;/p&gt;

&lt;p&gt;Nessa mesma lógica é gerado uma SESSION utilizando o Token gerado, essa sessão fica salva no Cookies e é verificada sempre que o usuário acessar a aplicação, quando o usuário realizar o signOut ou o token expirar a sessão é encerrada.&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Pages:&lt;/u&gt; Nesse objeto vamos realizar os redirecionamentos para as paginas personalizadas prevenindo o comportamento padrão.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SignIn: Pagina padrão gerada pelo Next Auth, aqui vamos indicar o caminho para a nossa pagina de Login personalizada. No exemplo eu tenho uma pagina em pages/login.tsx&lt;/li&gt;
&lt;li&gt;Error: Essa é a pagina que o usuário será redirecionado caso seja rejeitado o retorno da chamada API com erro. Como estamos enviando o erro, eu redireciono o usuário para a pagina de login, e iremos capturar esse erro na nossa pagina de login personalizada.&lt;/li&gt;
&lt;li&gt;SignOut: Pode ter uma pagina personalizada caso queira redirecionar o usuário quando ele realizar Logout da sua aplicação, ou para a pagina de Login.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Pagina de Login Personalizada
&lt;/h2&gt;

&lt;p&gt;Nesse exemplo utilizarei uma pagina de login personalizada, pode ser encontrada em “pages/login.tsx”.&lt;/p&gt;

&lt;p&gt;A pagina foi criada utilizando ChakraUI com YUP para validação dos campos e React Hook Form para manipular o formulário.&lt;/p&gt;

&lt;p&gt;Você pode criar interfaces com Chakra UI acessando: &lt;a href="https://chakra-ui.com/guides/first-steps" rel="noopener noreferrer"&gt;ChakraUi&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A sua pagina de login personalizada terá um manipulador de envio de formulario que usará a função signIn do Next Auth para realizar o login do usuário. No meu caso, tenho a função handle signIn, estou utilizando SubmitHandler do useForm.&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;handleSignIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SubmitHandler&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;SignInFormData&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;signIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;credentials&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;redirect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;callbackUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt;&lt;span class="p"&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;toast&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;isClosable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&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;&lt;u&gt;signIn: &lt;/u&gt;Essa função recebe como parâmetro o nome do Provider, definido em “name” no tópico anterior, e um objeto com propriedades.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;redirect: false, por padrão essa propriedade é true, setamos ela como false, para conseguir capturar a resposta da Função signIn.

&lt;ul&gt;
&lt;li&gt;Ela retorna uma Promise com a seguinte estrutura:&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

{
    error: string || undefined,
    status: number,
    ok: boolean,
    url: url || null
}


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

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Email e Password: Enviamos os valores esperados no Provider.&lt;/li&gt;
&lt;li&gt;CallbackUrl: Especifica para qual URL o usuário será redirecionado após entrar.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Como definimos redirect como false, ele não irá redireicionar o usuário caso o login seja bem sucedido, por isso fazemos uma verificação condicional se existe uma URL, se sim, utilizamos o Router.push, passando a URL, definida em CallbackURL.&lt;/p&gt;

&lt;p&gt;Se houver erro no login, que esta sendo enviado do Provider, recebemos ele, e mostramos em um Toast.&lt;/p&gt;

&lt;h2&gt;
  
  
  Logout da Aplicação.
&lt;/h2&gt;

&lt;p&gt;Para realizar o logout, utilize o método signOut(), para que seja concluído o fluxo de saída e encerrada a sessão do usuario.&lt;/p&gt;

&lt;p&gt;Esse metodo recarrega a pagina quando concluído, e o usuário será redirecionado para pagina de Login. É possivel especificar uma URL para redirecionar o usuário como no exemplo a seguir:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;signOut&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next-auth/react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 
    &lt;span class="nf"&gt;signOut&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;callbackUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:3000/login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Sign&lt;/span&gt; &lt;span class="nx"&gt;out&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Session Provider
&lt;/h3&gt;

&lt;p&gt;Na sua pagina do _app.ts deverá envolver o seu componente com o Session Provider para garantir que todas paginas tenha acesso ao Next Auth:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SessionProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next-auth/client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pageProps&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="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;SessionProvider&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;pageProps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nx"&gt;pageProps&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/SessionProvider&lt;/span&gt;&lt;span class="err"&gt;&amp;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;h1&gt;
  
  
  Rotas Privadas
&lt;/h1&gt;

&lt;p&gt;A proteção de rotas é crucial em qualquer aplicação que possa ser acessada apenas com Login, a seguir iremos criar rotas protegidas utilizando a lógica do Next Auth.&lt;/p&gt;

&lt;p&gt;Existem algumas formas de verificar se o usuário possui uma sessão ativa e então exibir o conteúdo da pagina, porém a forma como o Next.js trata getServerSideProps e getInitialProps, todo carregamento de página protegida irá realizar uma solicitação do lado do servidor para determinar se a sessão é válida anter de gerar a página solicitada(SSR), isso aumenta a carga do servidor, mas há uma opção para fazer solicitações do cliente, se nenhuma sessão for identificada após o carregento inicial, você determinará a ação apropriada.&lt;/p&gt;
&lt;h2&gt;
  
  
  Função Auth
&lt;/h2&gt;

&lt;p&gt;Vamos modificar o arquivo _app.js:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SessionProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useSession&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;signIn&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next-auth/react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;pageProps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;pageProps&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="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;SessionProvider&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Auth&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nx"&gt;pageProps&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Auth&lt;/span&gt;&lt;span class="err"&gt;&amp;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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nx"&gt;pageProps&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;)}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/SessionProvider&lt;/span&gt;&lt;span class="err"&gt;&amp;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;function&lt;/span&gt; &lt;span class="nf"&gt;Auth&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useSession&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;
  &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;loading&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isUser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;signIn&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="nx"&gt;isUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;status&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="nx"&gt;isUser&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="nx"&gt;children&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;


  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Loading&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;A Sessão esta sendo buscada, se não houver nenhum usuário o useEffect vai redirecionar. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Se o status for loading, a condicional não faz nada enquanto estiver no estado de carregamento.&lt;/li&gt;
&lt;li&gt;Se o usuário não estiver autenticado, o usuário é forçado a entrar na pagina de Login, através da função signIn().&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Manipulação da Sessão do Cliente personalizada.
&lt;/h3&gt;

&lt;p&gt;Dessa forma será exibido um status de carregamento na verificação inicial e todas transições de paginas serão do lado do cliente, eliminando a necessidade de verificar com o servidor e gerar novamente as páginas. &lt;/p&gt;

&lt;p&gt;Nas paginas protegidas é só adicionar:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Dashboard&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useSession&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Pagina&lt;/span&gt; &lt;span class="nx"&gt;Protegida&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;Dashboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Estamos usando Dashboard.auth = true para verificar se o usuário está autenticado, para todas as paginas que queremos proteger é só adicionar auth = true.&lt;/p&gt;

&lt;p&gt;Referências: &lt;a href="https://cloudcoders.xyz/blog/create-protected-routes-in-nextjs/" rel="noopener noreferrer"&gt;Protected Routes&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Espero que esse guia possa te ajudar!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>nextjs</category>
      <category>webdev</category>
      <category>braziliandevs</category>
    </item>
    <item>
      <title>Concorrência em banco de dados explicada de forma simples</title>
      <dc:creator>Fabio Hiroki</dc:creator>
      <pubDate>Tue, 15 Feb 2022 18:18:54 +0000</pubDate>
      <link>https://forem.com/portugues/concorrencia-em-banco-de-dados-explicada-de-forma-simples-47ka</link>
      <guid>https://forem.com/portugues/concorrencia-em-banco-de-dados-explicada-de-forma-simples-47ka</guid>
      <description>&lt;p&gt;Nesse artigo vou mostrar conceitos básicos para lidar com requisições simultâneas criando uma aplicação web de um banco. Quando estamos programando tem algumas armadilhas que precisamos nos atentar especialmente porque não são cenários fáceis de testar.&lt;/p&gt;

&lt;h2&gt;
  
  
  Escopo da aplicação do banco
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0qt83osbrcnvedb9o9ud.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0qt83osbrcnvedb9o9ud.gif" alt="caixa eletrônico perdendo dinheiro" width="500" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nossa aplicação de exemplo armazenará contas bancárias que poderão transferir dinheiro entre elas. Ela será construída usando PHP, Symfony e o mapeamento objeto-relacional (ORM) Doctrine, mas você não precisa conhecer essas tecnologias, apenas o banco de dados Postgres.&lt;/p&gt;

&lt;h2&gt;
  
  
  Entidade conta bancária (Account)
&lt;/h2&gt;

&lt;p&gt;A conta bancária guardará o nome do dono e a quantidade final de dinheiro.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="nv"&gt;"public"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;"bank_account"&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nv"&gt;"id"&lt;/span&gt; &lt;span class="n"&gt;int4&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nv"&gt;"name"&lt;/span&gt; &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nv"&gt;"amount"&lt;/span&gt; &lt;span class="n"&gt;int4&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;"id"&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;h2&gt;
  
  
  API para transferência de dinheiro
&lt;/h2&gt;

&lt;p&gt;O endpoint para transferir dinheiro entre duas contas irá receber três variáveis por query parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;from&lt;/code&gt;: id da conta origem&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;to&lt;/code&gt;: id da conta destino&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;amount&lt;/code&gt;: quantidade a ser transferida&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Então para transferir 100 da conta 1 para conta 2, podemos usar a seguinte requisição:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;http://localhost:8000/move?from&lt;span class="o"&gt;=&lt;/span&gt;1&amp;amp;to&lt;span class="o"&gt;=&lt;/span&gt;2&amp;amp;amount&lt;span class="o"&gt;=&lt;/span&gt;100
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Repositório Conta Bancária
&lt;/h2&gt;

&lt;p&gt;Para que o endpoint acima funcione, precisamos do seguinte repositório:&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;BankAccountRepository&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;ServiceEntityRepository&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;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ManagerRegistry&lt;/span&gt; &lt;span class="nv"&gt;$registry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;parent&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$registry&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;BankAccount&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&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;transferAmount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$amount&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Busca as contas bancárias a serem atualizadas&lt;/span&gt;
        &lt;span class="nv"&gt;$fromAccount&lt;/span&gt; &lt;span class="o"&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="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$from&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$toAccount&lt;/span&gt; &lt;span class="o"&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="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$to&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Atualiza a quantidade delas&lt;/span&gt;
        &lt;span class="nv"&gt;$fromAccount&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setAmount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$fromAccount&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getAmount&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;$amount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$toAccount&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setAmount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$toAccount&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getAmount&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;$amount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Persiste as duas entidades&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="nf"&gt;getEntityManager&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;persist&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$fromAccount&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="nf"&gt;getEntityManager&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;persist&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$toAccount&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="nf"&gt;getEntityManager&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;flush&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;Traduzindo para SQL, temos o seguinte (editado a partir do SQL gerado pelo Doctrine para fins de legibilidade):&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;bank_account&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;-- origem&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;bank_account&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;-- destino&lt;/span&gt;
&lt;span class="k"&gt;START&lt;/span&gt; &lt;span class="n"&gt;TRANSACTION&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;bank_account&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;-- origem&lt;/span&gt;
&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;bank_account&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;-- destino&lt;/span&gt;
&lt;span class="k"&gt;COMMIT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Controlador Conta
&lt;/h2&gt;

&lt;p&gt;Do lado do controlador, temos que extrair os query parameters da requisição e repassá-los para o repositório:&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;BankAccountController&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;AbstractController&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;#[Route('/move', name: 'bank_account')]&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;transfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;BankAccountRepository&lt;/span&gt; &lt;span class="nv"&gt;$repository&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;Response&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$from&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'from'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$to&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'to'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'amount'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$repository&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;transferAmount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$amount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'from %s to %s amount %s'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$amount&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;h2&gt;
  
  
  Vamos testar!
&lt;/h2&gt;

&lt;p&gt;Vamos criar contas de teste no banco de dados:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="nv"&gt;"public"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;"bank_account"&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;"id"&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;"amount"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;VALUES&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="s1"&gt;'Alice'&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Bob'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;E transferir 100 de Alice para Bob:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://localhost:8000/move?from&lt;span class="o"&gt;=&lt;/span&gt;1&amp;amp;to&lt;span class="o"&gt;=&lt;/span&gt;2&amp;amp;amount&lt;span class="o"&gt;=&lt;/span&gt;100
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Verificando os dados no banco podemos observar que o resultado está correto:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;| id | name  | amount |
|----|-------|--------|
|  1 | Alice |    900 |
|  2 | Bob   |    100 |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Fácil, certo? A partir de agora podemos melhorar essa implementação criando testes unitários, de integração e tudo continuará funcionando corretamente.&lt;/p&gt;
&lt;h2&gt;
  
  
  O que tem de errado?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6fgw3ek0tx7ogxx8z5u7.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6fgw3ek0tx7ogxx8z5u7.gif" alt="Alguém perguntando qual é o problema" width="480" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Para identificar o problema, vamos usar o &lt;a href="https://httpd.apache.org/docs/2.4/programs/ab.html" rel="noopener noreferrer"&gt;Apache HTTP server benchmarking tool (ab)&lt;/a&gt; para fazer várias requisições na nossa aplicação.&lt;/p&gt;

&lt;p&gt;O primeiro teste terá o seguinte cenário:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Alice começa com o montante 1000&lt;/li&gt;
&lt;li&gt;Bob começa com o montante 1000&lt;/li&gt;
&lt;li&gt;Alice faz 10 transferências de 100 para Bob, uma de cada vez&lt;/li&gt;
&lt;li&gt;Resultado final esperado: 

&lt;ul&gt;
&lt;li&gt;Alice: 0&lt;/li&gt;
&lt;li&gt;Bob: 1000&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nós podemos usar o seguinte comando, onde o parâmetro &lt;code&gt;n&lt;/code&gt; é o número total de requisições e &lt;code&gt;c&lt;/code&gt; é o número de requisições simultâneas:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ab &lt;span class="nt"&gt;-n&lt;/span&gt; 10 &lt;span class="nt"&gt;-c&lt;/span&gt; 1 &lt;span class="s1"&gt;'http://localhost:8000/move?from=1&amp;amp;to=2&amp;amp;amount=100'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Você terá que confiar em mim agora, mas posso garantir que ao rodar o comando acima Alice terá 0 e Bob terá 1000.&lt;/p&gt;

&lt;p&gt;O segundo cenário será bem parecido, mas faremos 10 requisições simultâneas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Alice começa com 1000&lt;/li&gt;
&lt;li&gt;Bob começa com 0&lt;/li&gt;
&lt;li&gt;Alice faz 10 transferências &lt;strong&gt;simultâneas&lt;/strong&gt; com o montante de 100 para Bob&lt;/li&gt;
&lt;li&gt;Resultado final esperado: 

&lt;ul&gt;
&lt;li&gt;Alice: 0&lt;/li&gt;
&lt;li&gt;Bob: 1000&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Preciamos alterar o parâmetro &lt;code&gt;c&lt;/code&gt; para 10:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ab &lt;span class="nt"&gt;-n&lt;/span&gt; 10 &lt;span class="nt"&gt;-c&lt;/span&gt; 10 &lt;span class="s1"&gt;'http://localhost:8000/move?from=1&amp;amp;to=2&amp;amp;amount=100'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;O resultado nada agradável:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;| id | name  | amount |
|----|-------|--------|
|  1 | Alice |    300 |
|  2 | Bob   |    700 |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3vigsg9lt8ivdw43haan.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3vigsg9lt8ivdw43haan.gif" alt="Os resultados não são bons" width="480" height="327"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Mas por quê? Basicamente há processos atualizando o montante enquanto há outros que estão lendo e mantendo o valor antigo na memória. Vamos imaginar dois processos concorrentes A e B atualizando apenas a conta de Alice: &lt;/p&gt;

&lt;p&gt;1 - Processo A lê o valor 1000 na conta de Alice&lt;br&gt;
2 - Processo B lê o valor 1000 na conta de Alice&lt;br&gt;
3 - Processo A escreve 900 na conta de Alice&lt;br&gt;
4 - Processo B escreve 900 na conta de Alice (deveria ser 800, que vergonha!)&lt;/p&gt;
&lt;h2&gt;
  
  
  Como corrigir?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7v5bbgvyaw72c3hm3xad.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7v5bbgvyaw72c3hm3xad.gif" alt="Alguém tentando achar a correção" width="480" height="368"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Há mais de uma solução, mas a que eu vou mostrar será utilizando &lt;code&gt;Pessimistic Locking&lt;/code&gt; para escritas e leituras. Isso significa que o banco de dados só permitirá uma escrita ou uma leitura por recurso, que nesse caso é a nossa entidade conta.&lt;/p&gt;

&lt;p&gt;No Doctrine podemos fazer isso utilizando o seguinte código no repositório:&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;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;transferAmountConcurrently&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$amount&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&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="nf"&gt;getEntityManager&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;beginTransaction&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nv"&gt;$fromAccount&lt;/span&gt; &lt;span class="o"&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="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;LockMode&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;PESSIMISTIC_WRITE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$toAccount&lt;/span&gt; &lt;span class="o"&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="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;LockMode&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;PESSIMISTIC_WRITE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nv"&gt;$fromAccount&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setAmount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$fromAccount&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getAmount&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;$amount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$toAccount&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setAmount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$toAccount&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getAmount&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;$amount&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="nf"&gt;getEntityManager&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;persist&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$fromAccount&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="nf"&gt;getEntityManager&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;persist&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$toAccount&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="nf"&gt;getEntityManager&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;flush&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="nf"&gt;getEntityManager&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;commit&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;Agora temos que explicitamente demarcar o início da transação antes de adquirir o lock, o que faz sentido uma vez que o Doctrine não consegue saber quando a transação deveria ter começado.&lt;/p&gt;

&lt;p&gt;Finalmente, a mesma solução em SQL:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;START&lt;/span&gt; &lt;span class="n"&gt;TRANSACTION&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;bank_account&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt; &lt;span class="n"&gt;origem&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;bank_account&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt; &lt;span class="n"&gt;destino&lt;/span&gt;
&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;bank_account&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt; &lt;span class="n"&gt;origem&lt;/span&gt;
&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;bank_account&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt; &lt;span class="n"&gt;destno&lt;/span&gt;
&lt;span class="k"&gt;COMMIT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Para testar, vou criar uma nova rota no controlador existente &lt;code&gt;BankAccountController&lt;/code&gt;:&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="na"&gt;#[Route('/move-concurrently', name: 'bank_account_concurrent')]&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;transferConcurrently&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;BankAccountRepository&lt;/span&gt; &lt;span class="nv"&gt;$repository&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;Response&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$from&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'from'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$to&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'to'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'amount'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nv"&gt;$repository&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;transferAmountConcurrently&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$amount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'from %s to %s amount %s'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$amount&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 agora podemos testar usando o Apache benchmarking tool&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ab &lt;span class="nt"&gt;-n&lt;/span&gt; 10 &lt;span class="nt"&gt;-c&lt;/span&gt; 10 &lt;span class="s1"&gt;'http://localhost:8000/move-concurrently?from=1&amp;amp;to=2&amp;amp;amount=100'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Pode confiar em mim, está funcionando agora: Alice possui 0 e Bob possui 1000.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flgcpbutytaqjmr0nb6io.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flgcpbutytaqjmr0nb6io.gif" alt="Alguém celebrando que está funcionando" width="400" height="200"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  O fim
&lt;/h2&gt;

&lt;p&gt;Ao usar a estratégia de locking nós garantimos que o processo que adquiriu o lock está lendo o valor mais atualizado e então atualizando dado consitente baseado na última leitura. O código final está no &lt;a href="https://github.com/fabiothiroki/symfony-bank-transaction" rel="noopener noreferrer"&gt;Github&lt;/a&gt;.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/fabiothiroki" rel="noopener noreferrer"&gt;
        fabiothiroki
      &lt;/a&gt; / &lt;a href="https://github.com/fabiothiroki/symfony-bank-transaction" rel="noopener noreferrer"&gt;
        symfony-bank-transaction
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;Obrigado pela leitura e espero que tenha gostado!&lt;/p&gt;

</description>
      <category>braziliandevs</category>
      <category>php</category>
      <category>database</category>
      <category>sql</category>
    </item>
    <item>
      <title>Introdução ao RabbitMQ e Symfony</title>
      <dc:creator>Fabio Hiroki</dc:creator>
      <pubDate>Tue, 11 Jan 2022 17:26:09 +0000</pubDate>
      <link>https://forem.com/portugues/introducao-ao-rabbitmq-e-symfony-33hg</link>
      <guid>https://forem.com/portugues/introducao-ao-rabbitmq-e-symfony-33hg</guid>
      <description>&lt;p&gt;Um dia eu estava tentando aprender os conceitos avançados do RabbitMQ, os casos de uso e as diferenças para os outros &lt;em&gt;message brokers&lt;/em&gt;. Comecei lendo a &lt;a href="https://www.rabbitmq.com/getstarted.html" rel="noopener noreferrer"&gt;boa documentação&lt;/a&gt; e então eu estava ansioso para experimentar em uma aplicação real.&lt;/p&gt;

&lt;p&gt;Entretanto não foi tão simples de criar uma aplicação &lt;a href="https://symfony.com/" rel="noopener noreferrer"&gt;Symfony&lt;/a&gt; e conectar com o RabbitMQ. Os resultados da busca do Google não eram tão precisos e eu ainda precisei da ajuda do StackOverflow para instalar dependências adicionais.&lt;/p&gt;

&lt;p&gt;Espero que eu tenha conseguido condensar toda a informação aqui e mostrá-la de uma forma simples e divertida.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que eu vou construir?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8pkag7k4y00yr47494yt.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8pkag7k4y00yr47494yt.gif" alt="Um homem confuso" width="480" height="364"&gt;&lt;/a&gt;&lt;br&gt;
Inicialmente eu pensei em criar uma aplicação web para explorar os diferentes padrões do RabbitMQ. Depois de sofrer com a integração do RabbitMQ com framework web popular, eu decidi dar um passo para trás e simplesmente só criar um endpoint que publica uma mensagem, e um consumidor que loga o conteúdo recebido. Então vamos construir!&lt;/p&gt;

&lt;p&gt;Código final no github:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/fabiothiroki" rel="noopener noreferrer"&gt;
        fabiothiroki
      &lt;/a&gt; / &lt;a href="https://github.com/fabiothiroki/php-symfony-rabbitmq" rel="noopener noreferrer"&gt;
        php-symfony-rabbitmq
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;php-symfony-rabbitmq&lt;/h1&gt;

&lt;/div&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/fabiothiroki/php-symfony-rabbitmq" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;h2&gt;
  
  
  Symfony
&lt;/h2&gt;

&lt;p&gt;Mas por que Symfony? É um framework PHP popular e no final eu gostei de como ficou a integração e a arquitetura com o RabbitMQ.&lt;/p&gt;

&lt;p&gt;Primeiramente eu instalei o &lt;a href="https://symfony.com/download" rel="noopener noreferrer"&gt;Symfony CLI&lt;/a&gt; e através dele, criei uma aplicação web tradicional:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;symfony new &lt;span class="nt"&gt;--full&lt;/span&gt; php-symfony-rabbitmq
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Posso rodar minha aplicação através do seguinte comando no diretório do projeto:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;symfony serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Symfony messenger
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F58xxwe3qkse854z1zrbd.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F58xxwe3qkse854z1zrbd.gif" alt="Um carteiro mostrando uma carta" width="480" height="270"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://symfony.com/doc/current/messenger.html" rel="noopener noreferrer"&gt;Symfony Messenger&lt;/a&gt; é a abstração de mensageria provido por uma dependência separada. Vamos instalá-la!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require symfony/messenger
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Seguindo a boa documentação, eu criei uma classe simples para encapsular a mensagem a ser publicada:&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;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SampleMessage&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;__construct&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;$content&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="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getContent&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&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;content&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 a sua respectiva classe &lt;em&gt;handler&lt;/em&gt;:&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;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SampleMessangeHandler&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;MessageHandlerInterface&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;__invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;SampleMessage&lt;/span&gt; &lt;span class="nv"&gt;$message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// magically invoked when an instance of SampleMessage is dispatched&lt;/span&gt;
        &lt;span class="nb"&gt;print_r&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Handler handled the message!'&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;Agora para verificar que tudo está funcionando até agora, eu adicionei um &lt;em&gt;endpoint&lt;/em&gt; simples para enviar uma mensagem:&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;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SampleController&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;AbstractController&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;#[Route('/sample', name: 'sample')]&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;sample&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;MessageBusInterface&lt;/span&gt; &lt;span class="nv"&gt;$bus&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;Response&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$message&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;SampleMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'content'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$bus&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Message with content %s was published'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$message&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getContent&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;Ao testar o &lt;em&gt;endpoint&lt;/em&gt;, verifico que a saída impressa pelo &lt;em&gt;handler&lt;/em&gt; e pela resposta http está correta:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://localhost:8000/sample

Handler handled the message!Message with content content was published
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Onde está o RabbitMQ?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feiiizw7xwe1rxgeq0b8w.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feiiizw7xwe1rxgeq0b8w.gif" alt="Gif de um coelho" width="499" height="361"&gt;&lt;/a&gt;&lt;br&gt;
Até agora não temos nem um sinal do RabbitMQ, mas não se preocupe porque deixei todo o terreno preparado para introduzi-lo.&lt;/p&gt;
&lt;h2&gt;
  
  
  Instalação das dependências
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Imagem docker
&lt;/h3&gt;

&lt;p&gt;Vou utilizar o docker para subir uma instância do RabbitMQ porque é muito fácil dessa forma. Só é preciso instalar o &lt;a href="https://docs.docker.com/compose/install/" rel="noopener noreferrer"&gt;Docker Compose&lt;/a&gt; e então editar o arquivo &lt;code&gt;.docker-compose.yml&lt;/code&gt; no diretório do projeto PHP para adicionar um novo serviço:&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;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3'&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;rabbitmq&lt;/span&gt;&lt;span class="pi"&gt;:&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;rabbitmq:3.9-management&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="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;5672:5672'&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;15672:15672'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ao rodar &lt;code&gt;docker-compose up&lt;/code&gt; é possível verificar que a instância do RabbitMQ está rodando.&lt;/p&gt;

&lt;h3&gt;
  
  
  Extensão PECL AMQP
&lt;/h3&gt;

&lt;p&gt;AMQP (Advanced Message Queuing Protocol), é o protocolo que sustenta o RabbitMQ. A instalação da sua extensão utilizando PECL (PHP Extension Community Language) foi um pouco difícil, pelo menos no MacOS:&lt;/p&gt;

&lt;p&gt;Primeiro, instalei o &lt;a href="https://brew.sh/" rel="noopener noreferrer"&gt;HomeBrew&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/bin/bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depois instalei &lt;code&gt;rabbitmq-c&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;rabbitmq-c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O que por fim permitiu a instalação da extensão:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pecl &lt;span class="nb"&gt;install &lt;/span&gt;amqp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Quando foi pedido para digitar o caminho para &lt;code&gt;librabbitmq&lt;/code&gt;, você precisa verificar qual é a versão instalada dentro do diretório &lt;code&gt;/usr/local/Cellar/rabbitmq-c/&lt;/code&gt;. A minha versão era a &lt;code&gt;0.11.0&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Set the path to librabbitmq &lt;span class="nb"&gt;install &lt;/span&gt;prefix &lt;span class="o"&gt;[&lt;/span&gt;autodetect] : /usr/local/Cellar/rabbitmq-c/0.11.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finalmente a última dependência:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require symfony/amqp-messenger 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Que alívio! Agora posso voltar a programar.&lt;/p&gt;

&lt;h2&gt;
  
  
  Utilizando o poder da assincronicidade
&lt;/h2&gt;

&lt;p&gt;Por padrão, o usuário e a senha criados na imagem docker são &lt;code&gt;guest&lt;/code&gt;, o que coincidentemente é a linha exata que eu preciso descomentar no arquivo &lt;code&gt;.env&lt;/code&gt;, que expõe a conexão ao RabbitMQ como uma variável de ambiente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;###&amp;gt; symfony/messenger ###&lt;/span&gt;
&lt;span class="c"&gt;# Choose one of the transports below&lt;/span&gt;
&lt;span class="c"&gt;# MESSENGER_TRANSPORT_DSN=doctrine://default&lt;/span&gt;
 &lt;span class="nv"&gt;MESSENGER_TRANSPORT_DSN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;amqp://guest:guest@localhost:5672/%2f/messages
&lt;span class="c"&gt;# MESSENGER_TRANSPORT_DSN=redis://localhost:6379/messages&lt;/span&gt;
&lt;span class="c"&gt;###&amp;lt; symfony/messenger ###&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora com essa nova variável, eu preciso dizer a aplicação quais mensagens deveriam ser tratadas por esse transporte.&lt;/p&gt;

&lt;p&gt;Então no arquivo &lt;code&gt;config/packages/messanger.yaml&lt;/code&gt; eu defino um novo &lt;code&gt;transport&lt;/code&gt; e o tipo de mensagem a ser tratada:&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;framework&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;messenger&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;transports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# https://symfony.com/doc/current/messenger.html#transport-configuration&lt;/span&gt;
            &lt;span class="na"&gt;async&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;%env(MESSENGER_TRANSPORT_DSN)%'&lt;/span&gt;

        &lt;span class="na"&gt;routing&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# Route your messages to the transports&lt;/span&gt;
            &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;App\Message\SampleMessage'&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;async&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nesse ponto eu posso testar o endpoint novamente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://localhost:8000/sample
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E em outro terminal eu ligo o consumidor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php bin/console messenger:consume async &lt;span class="nt"&gt;-vv&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esse comando imprime várias mensagens bem verbosas, mas as partes importantes são:&lt;br&gt;
:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;messenger] Received message App&lt;span class="se"&gt;\M&lt;/span&gt;essage&lt;span class="se"&gt;\S&lt;/span&gt;ampleMessage
&lt;span class="o"&gt;[&lt;/span&gt;messenger] App&lt;span class="se"&gt;\M&lt;/span&gt;essage&lt;span class="se"&gt;\S&lt;/span&gt;ampleMessage was handled successfully &lt;span class="o"&gt;(&lt;/span&gt;acknowledging to transport&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;messenger] Message App&lt;span class="se"&gt;\M&lt;/span&gt;essage&lt;span class="se"&gt;\S&lt;/span&gt;ampleMessage handled by App&lt;span class="se"&gt;\M&lt;/span&gt;essageHandler&lt;span class="se"&gt;\S&lt;/span&gt;ampleMessangeHandler
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E para ter certeza que a aplicação está realmente usando o RabbitMQ, eu posso acessar o admin no endereço &lt;a href="http://localhost:15672" rel="noopener noreferrer"&gt;http://localhost:15672&lt;/a&gt; e verificar esse gráfico bonito:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnwbszsz53h8wsh7tjdy0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnwbszsz53h8wsh7tjdy0.png" alt="Gráfico mostrando as mensagens enviadas" width="800" height="308"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmwvk6mfylrr4bd9sytrw.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmwvk6mfylrr4bd9sytrw.gif" alt="Gif de alguém feliz" width="480" height="366"&gt;&lt;/a&gt;&lt;br&gt;
Finalmente eu tenho um &lt;em&gt;setup&lt;/em&gt; básico do RabbitMQ e Symfony! Agora eu posso dar vida a vários &lt;em&gt;side projects&lt;/em&gt; e explorar os padrões de mensageria. Espero que tenha gostado e também aprendido algo!&lt;/p&gt;

</description>
      <category>braziliandevs</category>
      <category>php</category>
      <category>webdev</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Padrão de projeto Adapter em PHP</title>
      <dc:creator>Fabio Hiroki</dc:creator>
      <pubDate>Mon, 06 Dec 2021 20:38:40 +0000</pubDate>
      <link>https://forem.com/portugues/padrao-de-projeto-adapter-em-php-2kci</link>
      <guid>https://forem.com/portugues/padrao-de-projeto-adapter-em-php-2kci</guid>
      <description>&lt;p&gt;Os usuários e usuárias estão amando sua aplicação e você quer dar a eles mais alegria. O que poderia trazer mais felicidade do que notificações por email?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff3fngu6kix221b3nw4jw.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff3fngu6kix221b3nw4jw.gif" alt="Alguém sentindo alegria" width="427" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Vamos dar boas vindas!
&lt;/h2&gt;

&lt;p&gt;Nós queremos que nossos usuários e usuárias se sintam bem depois de se cadastrarem na nossa aplicação, então por que não enviar um email de boas vindas? Você já conhece um serviço de email confiável que tem um SDK fácil de instalar utilizando Composer. Tudo parece estar correndo bem até agora.&lt;/p&gt;

&lt;p&gt;Infelizmente, ao integrar o SDK você nota que as classes não se encaixam muito bem. &lt;code&gt;SignUpService&lt;/code&gt; contém apenas o destinatário e o conteúdo, enquanto &lt;code&gt;ThirdPartyEmailClient&lt;/code&gt; espera parâmetros de configuração.&lt;/p&gt;

&lt;p&gt;Nosso SDK hipotético possui a seguinte estrutura:&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;ThirdPartyEmailClient&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;__construct&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;$apiKey&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;$region&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="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;sendEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$recipient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nb"&gt;sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Using apiKey %s and region %s"&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;apiKey&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;region&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nb"&gt;sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Sending email to %s and content %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$recipient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$content&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;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl175txvyywsa6dcn5jwl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl175txvyywsa6dcn5jwl.png" alt="Diagrama das classes SignUpService e ThirdPartyEmailClient" width="649" height="321"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Faça funcionar
&lt;/h2&gt;

&lt;p&gt;Se &lt;code&gt;ThirdPartyEmailClient&lt;/code&gt; está pedindo por uma &lt;code&gt;apiKey&lt;/code&gt; e &lt;code&gt;region&lt;/code&gt;, vamos satisfazer seus pedidos. Nós podemos simplesmente injetar os dois parâmetros na classe &lt;code&gt;SignUpService&lt;/code&gt;, ou mesmo colocando eles diretamente no código (&lt;em&gt;hardcoding&lt;/em&gt;). Não seria um problema até você precisar depois enviar um email após o usuário atualizar o seu perfil, implementado em outra classe chamada &lt;code&gt;ProfileService&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Bom, por enquanto você só está preocupado em implementar a funcionalidade corretamente porque você é um bom profissional e quer entregar o prometido. A solução por agora é copiar e colar os parâmetros na classe &lt;code&gt;SignUpService&lt;/code&gt;. Bom trabalho!&lt;/p&gt;
&lt;h2&gt;
  
  
  Algo parece errado
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fir4jipkta6spc0yu0g5m.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fir4jipkta6spc0yu0g5m.gif" alt="Gif de alguém com insônia" width="480" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Naquela noite você não conseguiu dormir por causa daquele código duplicado. A &lt;code&gt;apiKey&lt;/code&gt; também está exposta em todos os lugares. Como resolver esse problema?&lt;/p&gt;
&lt;h2&gt;
  
  
  Faça funcionar melhor
&lt;/h2&gt;

&lt;p&gt;Eis então que você se lembra do padrão &lt;code&gt;Adapter&lt;/code&gt;. Ele serve para integrar classes que tem interfaces incompatíveis. O primeiro passo é criar a interface esperada pelo cliente:&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;interface&lt;/span&gt; &lt;span class="nc"&gt;EmailSenderAdapter&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;sendEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$recipient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$content&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&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;Agora você só precisa colocar &lt;code&gt;ThirdPartyEmailClient&lt;/code&gt; numa classe que implementa a interface 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="k"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ThirdPartyEmailSenderAdapter&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;EmailSenderAdapter&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;__construct&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;ThirdPartyEmailClient&lt;/span&gt; &lt;span class="nv"&gt;$emailClient&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="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;sendEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$recipient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$content&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&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;emailClient&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;sendEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$recipient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$content&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;&lt;code&gt;SignUpService&lt;/code&gt; agora está feliz porque tem um amigo que entende sua linguagem.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1208etxewd462mx89zr9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1208etxewd462mx89zr9.png" alt="Diagrama após a implementação do adapter" width="800" height="334"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;E para melhorar mais ainda, você decide adicionar um teste unitário!&lt;/p&gt;
&lt;h2&gt;
  
  
  Testando
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;testThirdPartyEmailSenderAdapterAdapterUsesCorrectClient&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$emailClient&lt;/span&gt; &lt;span class="o"&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="nf"&gt;createMock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ThirdPartyEmailClient&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nv"&gt;$emailAdapter&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;ThirdPartyEmailSenderAdapter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$emailClient&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nv"&gt;$emailClient&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;expects&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="nf"&gt;once&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'sendEmail'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'email@email.com'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'I love design patterns'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nv"&gt;$emailAdapter&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;sendEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s1"&gt;'email@email.com'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'I love design patterns'&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;h2&gt;
  
  
  Você conseguiu!
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhkms2storh0y81je8pcw.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhkms2storh0y81je8pcw.gif" alt="Programador feliz" width="400" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Suas classes estão bem integradas, testadas e se um dia você precisar alterar o provedor de email, seria só necessário criar uma implementação nova de &lt;code&gt;EmailSenderAdapter&lt;/code&gt;, e então a interface antiga pode ser trocada pela nova. Parabéns.&lt;/p&gt;

&lt;p&gt;&lt;a href="//github.com/fabiothiroki/php-design-patterns"&gt;Código no Github&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/fabiothiroki" rel="noopener noreferrer"&gt;
        fabiothiroki
      &lt;/a&gt; / &lt;a href="https://github.com/fabiothiroki/php-design-patterns" rel="noopener noreferrer"&gt;
        php-design-patterns
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A collection of design patterns written in PHP
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;php-design-patterns&lt;/h1&gt;

&lt;/div&gt;

&lt;p&gt;A collection of design patterns written in PHP&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/fabiothiroki/php-design-patterns/actions/workflows/php.yaml" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/fabiothiroki/php-design-patterns/actions/workflows/php.yaml/badge.svg" alt="PHP Composer"&gt;&lt;/a&gt; &lt;a href="https://coveralls.io/github/fabiothiroki/php-design-patterns?branch=main" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/4e0935b9b5bb7316b12e87eec75d34fb61a2e0f7038dfb6583470e1d2ca21682/68747470733a2f2f636f766572616c6c732e696f2f7265706f732f6769746875622f666162696f746869726f6b692f7068702d64657369676e2d7061747465726e732f62616467652e7376673f6272616e63683d6d61696e" alt="Coverage Status"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Creational&lt;/h2&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/fabiothiroki/php-design-patternsapp/creational/prototype" rel="noopener noreferrer"&gt;Prototype&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Structural&lt;/h2&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/fabiothiroki/php-design-patternsapp/structural/adapter" rel="noopener noreferrer"&gt;Adapter&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/fabiothiroki/php-design-patterns" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


</description>
      <category>braziliandevs</category>
      <category>php</category>
      <category>webdev</category>
      <category>oop</category>
    </item>
    <item>
      <title>Captura de argumentos em testes PHP</title>
      <dc:creator>Fabio Hiroki</dc:creator>
      <pubDate>Sat, 23 Oct 2021 08:10:30 +0000</pubDate>
      <link>https://forem.com/portugues/captura-de-argumentos-em-testes-php-281d</link>
      <guid>https://forem.com/portugues/captura-de-argumentos-em-testes-php-281d</guid>
      <description>&lt;p&gt;Você já está se sentindo confiante com suas habilidades de teste e os seus colegas te invejam ao ouvir você falar de mocks e stubs. Mas agora, um novo desafio surge e você só pode verificar certas propriedades de um argumento, caso contrário seus testes falharão miseravelmente.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3vigsg9lt8ivdw43haan.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3vigsg9lt8ivdw43haan.gif" alt="Gif mostrando alguém horrorizado" width="480" height="327"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Um novo dia começa
&lt;/h2&gt;

&lt;p&gt;Seu trabalho era implementar uma simples funcionalidade de cadastro de usuário. Como uma boa programadora, você planeja usar o padrão &lt;code&gt;Repositório&lt;/code&gt; para poder separar a camada de persistência e mocká-la em testes unitários caso necessário. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbnywbn55x3xdq7vyhtjv.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbnywbn55x3xdq7vyhtjv.gif" alt="Gif de alguém pensando que isso vai ser fácil" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Classe usuário
&lt;/h3&gt;

&lt;p&gt;Não poderia ser mais simples, certo?&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;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&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;__construct&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;$id&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;$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;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getId&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&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;id&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;getName&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&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;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;h3&gt;
  
  
  Repositório da entidade usuário
&lt;/h3&gt;

&lt;p&gt;Não está persistindo de fato, mas vamos fingir que sim.&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;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserRepository&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;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;User&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nb"&gt;sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Persistindo usuário com id %s e nome %s'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getId&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getName&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;h3&gt;
  
  
  Classe UserService
&lt;/h3&gt;

&lt;p&gt;Agora temos uma reviravolta! Um requisito maluco diz que o campo &lt;code&gt;id&lt;/code&gt; deve ser randômico. Bom, temos várias maneiras de fazer isso, então vamos prosseguir:&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;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserService&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;__construct&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;UserRepository&lt;/span&gt; &lt;span class="nv"&gt;$repository&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="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;createNewUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$user&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;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;uniqid&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;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&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;Legal, tudo está funcionando.&lt;/p&gt;

&lt;h2&gt;
  
  
  Não vamos nos esquecer dos testes
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm6r78ebury2olgq1tysd.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm6r78ebury2olgq1tysd.gif" alt="Gif de alguém lembrando de testar" width="480" height="366"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nós queremos verificar quando &lt;code&gt;UserService&lt;/code&gt; cria um &lt;code&gt;User&lt;/code&gt;, se o &lt;code&gt;UserRepostory&lt;/code&gt; está sendo chamado corretamente. Não nos importamos com a persistência agora, então podemos mockar o repositório e tudo deve funcionar.&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;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;testFailing&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$repository&lt;/span&gt; &lt;span class="o"&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="nf"&gt;createMock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UserRepository&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nv"&gt;$userService&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;UserService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$repository&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nv"&gt;$repository&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;expects&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="nf"&gt;once&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'save'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'id não randômico'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'user'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="nv"&gt;$userService&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;createNewUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'user'&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;Infelizmente isso não funciona. O teste falha porque &lt;code&gt;User&lt;/code&gt; com o id &lt;code&gt;id não randômico&lt;/code&gt; não corresponde ao argumento passado pelo &lt;code&gt;UserRepository&lt;/code&gt; que tem um id diferente cada vez que um novo usuário é criado.&lt;/p&gt;

&lt;h2&gt;
  
  
  Captura de argumento ao resgate!
&lt;/h2&gt;

&lt;p&gt;No Java, nós temos essa mesa funcionalidade provida pelo &lt;a href="https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html#15" rel="noopener noreferrer"&gt;Mockito&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Captura de argumento&lt;/code&gt; possibilita a verificação de apenas alguns valores do argumento ao invés de testar a equalidade do objeto inteiro.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;No nosso exemplo, nós não nos precisamos testar realmente o valor do &lt;code&gt;id&lt;/code&gt; porque ele é gerado randomicamente pelo próprio PHP através da função &lt;code&gt;uniqid&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;No final o teste usando &lt;code&gt;captura de argumento&lt;/code&gt; fica assim&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;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;testRepositoryShouldCreateUserWithCorrectName&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$repository&lt;/span&gt; &lt;span class="o"&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="nf"&gt;createMock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UserRepository&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nv"&gt;$userService&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;UserService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$repository&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nv"&gt;$repository&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;expects&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="nf"&gt;once&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'save'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;will&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="nf"&gt;returnCallback&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="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'user'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getName&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="p"&gt;}));&lt;/span&gt;

    &lt;span class="nv"&gt;$userService&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;createNewUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'user'&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;Obrigado por ler até aqui, espero que tenha gostado e boa sorte com seus testes!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgpkxfvdzl8ljd7neyyei.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgpkxfvdzl8ljd7neyyei.gif" alt="Good luck!" width="328" height="245"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>braziliandevs</category>
      <category>php</category>
      <category>webdev</category>
      <category>testing</category>
    </item>
    <item>
      <title>Padrão de projeto Prototype em PHP</title>
      <dc:creator>Fabio Hiroki</dc:creator>
      <pubDate>Sun, 10 Oct 2021 16:38:09 +0000</pubDate>
      <link>https://forem.com/portugues/padrao-de-projeto-prototype-em-php-38km</link>
      <guid>https://forem.com/portugues/padrao-de-projeto-prototype-em-php-38km</guid>
      <description>&lt;p&gt;Vamos imaginar que você está trabalhando em um eCommerce e recebeu a responsabilidade de implementar a seguinte funcionalidade:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Na tela do carrinho, o usuário deve ser capaz de adicionar mais de uma unidade de um produto já presente, e também alterar a sua cor.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Uma solução intuitiva nesse contexto poderia ser instanciar um novo objeto produto e setar todos os atributos iguais ao produto original. Mas isso parece ser muito verboso, e você precisaria saber todo o funcionamento interno da classe produto, o que parece quebrar o encapsulamento.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prototype ao resgate!
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7sh4ufs6bll6vi9lkli7.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7sh4ufs6bll6vi9lkli7.gif" alt="Gif de alguém sendo clonado" width="480" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Do &lt;a href="https://refactoring.guru/pt-br/design-patterns/prototype" rel="noopener noreferrer"&gt;refactoring.guru&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;O Prototype é um padrão de projeto criacional que permite copiar objetos existentes sem fazer seu código ficar dependente de suas classes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Isso significa que você não precisa usar o operador &lt;code&gt;new&lt;/code&gt; nem se preocupar em como configurar uma instância copiada perfeitamente. Só precisa o usar o operador &lt;code&gt;clone&lt;/code&gt; e o PHP vai resolver tudo sozinho.&lt;/p&gt;

&lt;h2&gt;
  
  
  Aplicação de exemplo
&lt;/h2&gt;

&lt;p&gt;Versão final do código está no &lt;a href="https://github.com/fabiothiroki/php-design-patterns" rel="noopener noreferrer"&gt;Github&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/fabiothiroki" rel="noopener noreferrer"&gt;
        fabiothiroki
      &lt;/a&gt; / &lt;a href="https://github.com/fabiothiroki/php-design-patterns" rel="noopener noreferrer"&gt;
        php-design-patterns
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A collection of design patterns written in PHP
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;
 

&lt;p&gt;A classe &lt;code&gt;Cart&lt;/code&gt; não faz parte do padrão de projeto, mas está presente aqui somente para demonstrar como o padrão se encaixaria numa aplicação real:&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;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Cart&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/**
     * @var ProductPrototype[]
     */&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$products&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;addProduct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ProductPrototype&lt;/span&gt; &lt;span class="nv"&gt;$product&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&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;products&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$product&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * @return ProductPrototype[]
     */&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;getProducts&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&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;products&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;Como podemos observar, somos capazes de adicionar um novo produto e verificar quais produtos já estão adicionados.&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;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProductPrototype&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$color&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;getId&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="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&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;getName&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&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;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;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getColor&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&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;color&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;setColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$color&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&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;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$color&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;PHP já implementa &lt;code&gt;Prototype&lt;/code&gt; nativamente porque todo objeto já aceita o operador &lt;code&gt;clone&lt;/code&gt; por padrão. Nesse exemplo, criei a classe &lt;code&gt;ProductPrototype&lt;/code&gt; só para ilustrar um caso real: para a classe &lt;code&gt;Cart&lt;/code&gt; não importa qual o tipo específico de produto será adicionado, contanto que tenha os atributos &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;name&lt;/code&gt; e &lt;code&gt;color&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Apenas para simplificar esse exemplo, vou mostrar dois tipos de produto: &lt;code&gt;Smartphone&lt;/code&gt; e &lt;code&gt;Laptop&lt;/code&gt;:&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;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Smartphone&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;ProductPrototype&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;__construct&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;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&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;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Smartphone'&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;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Default color'&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="k"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Laptop&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;ProductPrototype&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;__construct&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;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&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;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Smartphone'&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;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Default color'&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;h2&gt;
  
  
  Explicando Prototype com testes unitários
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7jyvx4z5cennono1icxl.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7jyvx4z5cennono1icxl.gif" alt="Gif de uma casa se multiplicando" width="480" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O que o operador &lt;code&gt;clone&lt;/code&gt; realmente faz? Ele copia uma instância com os mesmos atributos. Então no nosso exemplo, o produto clonado terá os mesmos valores de &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;nome&lt;/code&gt; e &lt;code&gt;cor&lt;/code&gt; do objeto original.&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;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;testSmartphoneClone&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$smartphone&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;Smartphone&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nv"&gt;$clonedSmartphone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;clone&lt;/span&gt; &lt;span class="nv"&gt;$smartphone&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$clonedSmartphone&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getId&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nv"&gt;$smartphone&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getId&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$clonedSmartphone&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getName&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nv"&gt;$smartphone&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getName&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$clonedSmartphone&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getColor&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nv"&gt;$smartphone&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getColor&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$clonedSmartphone&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$smartphone&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;assertNotSame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$clonedSmartphone&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$smartphone&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;Como podemos observar, se tivéssemos que clonar um objeto manualmente, teríamos que saber todas as propriedades a serem copiadas e como setá-las.&lt;/p&gt;

&lt;p&gt;Perceba que esse teste não precisaria ser escrito numa aplicação real porque podemos assumir que o operador &lt;code&gt;clone&lt;/code&gt; funciona corretamente, já que é provido pelo próprio PHP.&lt;/p&gt;

&lt;h2&gt;
  
  
  De volta ao nosso caso de uso
&lt;/h2&gt;

&lt;p&gt;Finalmente podemos dar ao &lt;code&gt;Cart&lt;/code&gt; a funcionalidade de aumentar a quantidade de um produto existente e alterar sua cor. &lt;code&gt;Cart&lt;/code&gt; ficará ainda mais feliz porque não precisa se preocupar se estará recebendo uma instância de &lt;code&gt;Laptop&lt;/code&gt; ou de &lt;code&gt;Smartphone&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;É só fazer uso do operador clone e adicionar o produto recém clonado:&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;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;testCartCanAddClonedProducts&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$laptop&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;Laptop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nv"&gt;$cart&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;Cart&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nv"&gt;$cart&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;addProduct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$laptop&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nv"&gt;$clonedLaptop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;clone&lt;/span&gt; &lt;span class="nv"&gt;$laptop&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nv"&gt;$clonedLaptop&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'White'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$cart&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;addProduct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$clonedLaptop&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;assertCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$cart&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getProducts&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$cart&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getProducts&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="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getId&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nv"&gt;$cart&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getProducts&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getId&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$cart&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getProducts&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="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getName&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nv"&gt;$cart&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getProducts&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getName&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'White'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$cart&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getProducts&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="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getColor&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Default color'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$cart&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getProducts&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getColor&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;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fenyluxx8yx7u5fdh2rch.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fenyluxx8yx7u5fdh2rch.gif" alt="Gif do bob esponja se multiplicando" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Obrigado por ler até aqui, espero que você tenha entendido melhor sobre esse padrão de projeto e lembre-se de usá-lo quando necessário!&lt;/p&gt;

</description>
      <category>braziliandevs</category>
      <category>php</category>
      <category>webdev</category>
      <category>oo</category>
    </item>
    <item>
      <title>Melhore a testabilidade do seu código PHP</title>
      <dc:creator>Fabio Hiroki</dc:creator>
      <pubDate>Sat, 25 Sep 2021 18:17:33 +0000</pubDate>
      <link>https://forem.com/portugues/melhore-a-testabilidade-do-seu-codigo-php-3fpp</link>
      <guid>https://forem.com/portugues/melhore-a-testabilidade-do-seu-codigo-php-3fpp</guid>
      <description>&lt;h2&gt;
  
  
  Introdução
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4sbezwymaa3d18pdi5yc.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4sbezwymaa3d18pdi5yc.gif" alt="gif de boas vindas" width="480" height="277"&gt;&lt;/a&gt;&lt;br&gt;
Bem vindo ao meu artigo! Espero que você seja como eu e acredite no poder dos testes unitários, ou pelo menos saiba que eles são importantes. Resumindo, eu gosto deles porque me dão confiança que meu código está funcionando e ninguém mais fará alterações nele por engano.&lt;/p&gt;

&lt;p&gt;Nesse artigo eu vou mostrar como combinar mocks e reflexão para escrever um teste que a princípio parecia impossível.&lt;/p&gt;

&lt;p&gt;O código completo está no &lt;a href="https://github.com/fabiothiroki/php-reflection-test" rel="noopener noreferrer"&gt;Github&lt;/a&gt;.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/fabiothiroki" rel="noopener noreferrer"&gt;
        fabiothiroki
      &lt;/a&gt; / &lt;a href="https://github.com/fabiothiroki/php-reflection-test" rel="noopener noreferrer"&gt;
        php-reflection-test
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A simple example of unit tests using reflection
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;
 
&lt;h2&gt;
  
  
  Desafio aceito
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo4iy8bucy3xu1lvmw5k9.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo4iy8bucy3xu1lvmw5k9.gif" alt="gif escrito challenge accepted" width="480" height="480"&gt;&lt;/a&gt;&lt;br&gt;
Eu havia acabado de começar num trabalho novo, numa empresa que usa PHP como linguagem principal. Peguei uma nova tarefa e estava muito animado para terminá-la (com testes, é claro!).&lt;/p&gt;

&lt;p&gt;Mas, de repente, uma classe selvagem aparece! Ela não expunha uma dependência que eu precisava mockar. Eu poderia refatorar esse código pra receber a dependência através do construtor, mas decidi não seguir esse caminho porque eu era novo na empresa e não sabia se isso era um padrão aceitável ou qual foi o racional da pessoa que desenvolveu a classe originalmente.&lt;/p&gt;

&lt;p&gt;Por outro lado, a solução alternativa que eu mostrar a seguir também não demandaria um esforço grande. Vindo de um background Java, eu sabia que isso poderia ser feito usando "reflexão".&lt;/p&gt;
&lt;h2&gt;
  
  
  Reflexão? O que?
&lt;/h2&gt;

&lt;p&gt;Antes de irmos direto para o código precisamos entender o conceito de reflexão. Aqui vai a minha definição simples:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Reflexão é uma ferramenta que permite inspecionar o código e passar por cima da tipagem estática.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Por exemplo, nesse artigo vou utilizar reflexão para para alterar a instância de um atributo inacessível, de uma classe que não tem um método "setter" nem uma outra forma de acessá-la.&lt;/p&gt;
&lt;h2&gt;
  
  
  Por que você quer fazer isso?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2kstaqojvbeblfd66izs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2kstaqojvbeblfd66izs.png" alt="Diagrama de classes" width="338" height="422"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Nesse exemplo, a classe &lt;code&gt;Implementation&lt;/code&gt; contém um método público que faz uma chamada para a dependência inacessível. Então o teste que queremos fazer é: quando chamamos o método público de &lt;code&gt;Implementation&lt;/code&gt;, estamos chamando a dependência com os argumentos corretos?&lt;/p&gt;
&lt;h2&gt;
  
  
  Me mostre o código
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Classe abstrata
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AbstractClass&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$unacessibleDependency&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;__construct&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;unacessibleDependency&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;UnacessibleDependency&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$argument&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&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;Como podemos observar, não há uma forma de acessar &lt;code&gt;$unacessibleDependency&lt;/code&gt; externamente, a não ser que refatoremos essa classe, o que já disse anteriormente que não é o caminho que decidi não seguir.&lt;/p&gt;
&lt;h3&gt;
  
  
  Classe Implementation
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ImplementationClass&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;AbstractClass&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;doSomething&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$argument&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&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;unacessibleDependency&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;doSomethingElse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$argument&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;&lt;code&gt;doSomething&lt;/code&gt; é o método que queremos testar.&lt;/p&gt;
&lt;h3&gt;
  
  
  Configuração do teste
&lt;/h3&gt;

&lt;p&gt;Comece criando uma instância do sistema a ser testado (system under test ou SUT):&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;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;implementation&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;ImplementationClass&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Torne a &lt;code&gt;unacessibleDependency&lt;/code&gt; da instância anterior acessível por meio da reflexão:&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;$reflectionClass&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;ReflectionClass&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;implementation&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$property&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$reflectionClass&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'unacessibleDependency'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$property&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setAccessible&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Crie uma instância mock de &lt;code&gt;UnacessibleDependency&lt;/code&gt; para que possamos verificar se está sendo chamada:&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;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;mockUnacessible&lt;/span&gt; &lt;span class="o"&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="nf"&gt;createMock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UnacessibleDependency&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Então, substitua a dependência original pelo object mock:&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;$property&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setValue&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;implementation&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;mockUnacessible&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Por fim, a afirmação
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&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;mockUnacessible&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;expects&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;once&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'doSomethingElse'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;equalTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'argument'&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;implementation&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'argument'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Traduzindo para linguagem humana: quando &lt;code&gt;doSomething&lt;/code&gt; é chamado com o parâmetro &lt;code&gt;argument&lt;/code&gt;, &lt;code&gt;doSomethingElse&lt;/code&gt; é também chamado com o mesmo parâmetro?&lt;/p&gt;

&lt;p&gt;Agora nós temos nosso teste, e ninguém se feriu durante esse processo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F17c4ktwczt951n3cvbvs.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F17c4ktwczt951n3cvbvs.gif" alt="gif de celebração" width="480" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Existe uma forma de adicionar um teste unitário mesmo em cenários improváveis, mas essa técnica deve ser usado com cuidado porque nós podemos estar mascarando um design de código ruim. Se o código não está facilmente testável, então provavelmente não estamos seguindo as boas práticas de encapsulamento ou abstração.&lt;/p&gt;

&lt;h3&gt;
  
  
  Eu quero saber mais!
&lt;/h3&gt;

&lt;p&gt;Para mais técnicas de melhoria de testabilidade de código, dê uma olhada no livro "Trabalho Eficaz com Código Legado" de Michael Feathers.&lt;/p&gt;

</description>
      <category>braziliandevs</category>
      <category>webdev</category>
      <category>tutorial</category>
      <category>php</category>
    </item>
  </channel>
</rss>
