<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>codamos.com.br</title><description>Codamos: blogs sobre desenvolvimento de software.</description><link>https://codamos.com.br/</link><language>pt-br</language><item><title>Como instalar o MySQL 5.5 no Ubuntu 22.04 LTS</title><link>https://codamos.com.br/tutorial-instalar-mysql-55-no-ubuntu-2204-lts/</link><guid isPermaLink="true">https://codamos.com.br/tutorial-instalar-mysql-55-no-ubuntu-2204-lts/</guid><description>Eu recentemente me deparei com um cliente que ainda está rodando a versão 5.5 do MySQL em seus servidores Ubuntu 14.04 LTS. E, apesar de a migração para uma versão mais atualizada ser fundamental, nós</description><pubDate>Sat, 17 Aug 2024 16:59:59 GMT</pubDate><content:encoded>&lt;p data-renderer-start-pos=&quot;1&quot;&gt;Eu recentemente me deparei com um cliente que ainda está rodando a versão 5.5 do MySQL em seus servidores Ubuntu 14.04 LTS. E, apesar de a migração para uma versão mais atualizada ser fundamental, nós decidimos que o primeiro e mais fácil dos passos seria atualizar o próprio sistema operacional para que possamos ter acesso a correções de bugs, falhas de segurança e melhorias nos drivers.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;393&quot;&gt;Decidimos então migrar para o Ubuntu 22.04 LTS, e reinstalamos o MySQL 5.5 nele manualmente, já que o repositório &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;apt&lt;/code&gt; oficial do Ubuntu 22.04 nos oferece apenas o MySQL 8.0 que é incompatível com a base de dados no estado atual. Neste artigo eu vou te mostrar como instalar e configurar o MySQL 5.5 no Ubuntu 22.04 LTS manualmente.&lt;/p&gt;
&lt;h2 data-renderer-start-pos=&quot;726&quot;&gt;Ambiente de desenvolvimento&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;755&quot;&gt;Para que você possa executar cada passo do tutorial comigo, vamos utilizar um ambiente controlado através do docker. Para iniciar seu servidor Ubuntu 22.04 LTS dentro do docker, rode o seguinte comando:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;755&quot;&gt;$ docker run --rm -it ubuntu:22.04&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;995&quot;&gt;Você precisa ter o docker ou rancher-desktop instalados para o comando acima funcionar. E se a imagem &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;ubuntu:22.04&lt;/code&gt; não estiver presente no seu sistema, este comando vai primeiro fazer o download da imagem (cerca de 78MB) para depois iniciar o servidor. Sua tela vai ficar mais ou menos assim:&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image post__image--wide&quot; src=&quot;/media/posts/79/iniciar-ubuntu-22.04.jpg&quot; alt=&quot;&quot; width=&quot;1346&quot; height=&quot;355&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;cc-1wlpsko&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;1291&quot;&gt;Iniciando uma sessão no ubuntu:22.04 utilizando &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;docker&lt;/code&gt;&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;1348&quot;&gt;Para baixar arquivos a partir da internet, vamos precisar de um pacote chamado &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;curl&lt;/code&gt;. Podemos instalar o pacote através do &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;apt&lt;/code&gt;:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;1348&quot;&gt;# apt update&lt;br&gt;# apt install -y curl&lt;/pre&gt;
&lt;div class=&quot;gallery&quot; contenteditable=&quot;false&quot; data-is-empty=&quot;false&quot; data-translation=&quot;Add images&quot; data-columns=&quot;2&quot;&gt;
&lt;figure class=&quot;gallery__item&quot;&gt;&lt;a href=&quot;/media/posts/79/gallery/apt-update.jpg&quot; data-size=&quot;1341x796&quot;&gt;&lt;img src=&quot;/media/posts/79/gallery/apt-update-thumbnail.jpg&quot; alt=&quot;Comando &amp;#96;apt update&amp;#96;&quot; width=&quot;768&quot; height=&quot;456&quot;&gt;&lt;/a&gt;
&lt;figcaption&gt;Comando `apt update`&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;gallery__item&quot;&gt;&lt;a href=&quot;/media/posts/79/gallery/instalando-curl-via-apt.jpg&quot; data-size=&quot;1341x796&quot;&gt;&lt;img src=&quot;/media/posts/79/gallery/instalando-curl-via-apt-thumbnail.jpg&quot; alt=&quot;Instalando o &amp;#96;curl&amp;#96;&quot; width=&quot;768&quot; height=&quot;456&quot;&gt;&lt;/a&gt;
&lt;figcaption&gt;Instalando o `curl`&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;h2 id=&quot;Ambiente-de-desenvolvimento&quot; data-renderer-start-pos=&quot;726&quot;&gt;&lt;/h2&gt;
&lt;h2 id=&quot;Baixar-o-servidor-MySQL-5.5-oficial-no-Ubuntu-22.04-LTS&quot; data-renderer-start-pos=&quot;1559&quot;&gt;Baixar o servidor MySQL 5.5 oficial no Ubuntu 22.04 LTS&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;1616&quot;&gt;No Ubuntu 22.04 você vai reparar que através do &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;apt&lt;/code&gt; a versão do MySQL disponível é a &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;8.0&lt;/code&gt;. Caso queira instalar uma versão mais antiga, vai precisar adicionar um repositório apt diferente ou instalar através dos binários oficiais distribuídos pela Oracle.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1872&quot;&gt;Eu particularmente não confio em repositórios PPA que eu tenha pouca familiaridade e não os utilizo em projetos profissionais. Então a minha alternativa é justamente baixar o MySQL Server 5.5 através do &lt;a data-testid=&quot;link-with-safety&quot; href=&quot;https://downloads.mysql.com/archives/community/&quot; title=&quot;https://downloads.mysql.com/archives/community/&quot; data-renderer-mark=&quot;true&quot; class=&quot;cc-1rn59kg&quot;&gt;site oficial do MySQL&lt;/a&gt;:&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image post__image--full&quot; src=&quot;/media/posts/79/download-mysql-5.5.jpg&quot; alt=&quot;Filtro de versão e sistema operacional da listagem de downloads.&quot; width=&quot;1657&quot; height=&quot;549&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;cc-1wlpsko&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;2102&quot;&gt;Filtro de versão e sistema operacional da listagem de downloads.&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;2169&quot;&gt;Como o Ubuntu é uma distribuição Linux baseada em Debian, podemos escolher “Debian Linux” no filtro de sistema operacional, e baixar o pacote adequado. No meu caso, vou baixar o arquivo 64 bit &lt;a data-testid=&quot;link-with-safety&quot; href=&quot;https://downloads.mysql.com/archives/get/p/23/file/mysql-5.5.40-debian6.0-x86_64.deb&quot; title=&quot;https://downloads.mysql.com/archives/get/p/23/file/mysql-5.5.40-debian6.0-x86_64.deb&quot; data-renderer-mark=&quot;true&quot; class=&quot;cc-1rn59kg&quot;&gt;mysql-5.5.40-debian6.0-x86_64.deb&lt;/a&gt; no diretório &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;/opt&lt;/code&gt;:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;2169&quot;&gt;# cd /opt&lt;br&gt;# curl -LO https://downloads.mysql.com/archives/get/p/23/file/mysql-5.5.40-debian6.0-x86_64.deb&lt;/pre&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image post__image--full&quot; src=&quot;/media/posts/79/download-mysql-5.5-via-curl.jpg&quot; alt=&quot;Download do servidor MySQL 5.5 via curl&quot; width=&quot;1341&quot; height=&quot;319&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;cc-1wlpsko&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;2525&quot;&gt;Download do servidor MySQL 5.5 via &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;curl&lt;/code&gt;&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;2567&quot;&gt;Podemos agora expandir o pacote utilizando o utilitário &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;dpkg&lt;/code&gt; com o comando a seguir:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;2567&quot;&gt;# dpkg --unpack mysql-5.5.40-debian6.0-x86_64.deb&lt;/pre&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image post__image--full&quot; src=&quot;/media/posts/79/dpkg-i-mysql-5.5.jpg&quot; alt=&quot;Extração dos arquivos do servidor MySQL 5.5 via &amp;#96;dpkg --unpack&amp;#96;&quot; width=&quot;1341&quot; height=&quot;381&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;cc-1wlpsko&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;2706&quot;&gt;Extração dos arquivos do servidor MySQL 5.5 via &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;dpkg --unpack&lt;/code&gt;&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;2770&quot;&gt;Agora podemos entrar no diretório &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;/opt/mysql/server-5.5&lt;/code&gt; e visualizar os arquivos da instalação do MySQL 5.5:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;2770&quot;&gt;# cd /opt/mysql/server-5.5&lt;br&gt;# ll&lt;/pre&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image post__image--full&quot; src=&quot;/media/posts/79/listar-arquivos-mysql.jpg&quot; alt=&quot;Listagem de arquivos em /opt/mysql/server-5.5&quot; width=&quot;1341&quot; height=&quot;610&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;cc-1wlpsko&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;2915&quot;&gt;Listagem de arquivos em &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;/opt/mysql/server-5.5&lt;/code&gt;&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;Instalar-dependências-do-MySQL-5.5-no-Ubuntu-22.04-LTS&quot; data-renderer-start-pos=&quot;2963&quot;&gt;Instalar dependências do MySQL 5.5 no Ubuntu 22.04 LTS&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;3019&quot;&gt;A versão 5.5 do MySQL exige versões antigas de algumas bibliotecas. No caso do MySQL 5.5 no ubuntu 22.04 LTS precisamos instalar três bibliotecas em versões específicas:&lt;/p&gt;
&lt;ul class=&quot;ak-ul&quot; data-indent-level=&quot;1&quot;&gt;
&lt;li&gt;
&lt;p data-renderer-start-pos=&quot;3192&quot;&gt;&lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;libaio1 v0.3&lt;/code&gt; - &lt;a data-testid=&quot;link-with-safety&quot; href=&quot;http://archive.ubuntu.com/ubuntu/pool/main/liba/libaio/libaio1_0.3.113-5_amd64.deb&quot; title=&quot;http://archive.ubuntu.com/ubuntu/pool/main/liba/libaio/libaio1_0.3.113-5_amd64.deb&quot; data-renderer-mark=&quot;true&quot; class=&quot;cc-1rn59kg&quot;&gt;download oficial&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;libncurses5 v6.4&lt;/code&gt; - &lt;a data-testid=&quot;link-with-safety&quot; href=&quot;http://archive.ubuntu.com/ubuntu/pool/universe/n/ncurses/libncurses5_6.4-2_amd64.deb&quot; title=&quot;http://archive.ubuntu.com/ubuntu/pool/universe/n/ncurses/libncurses5_6.4-2_amd64.deb&quot; data-renderer-mark=&quot;true&quot; class=&quot;cc-1rn59kg&quot;&gt;download oficial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;libtinfo5 v6.4&lt;/code&gt; - &lt;a data-testid=&quot;link-with-safety&quot; href=&quot;http://archive.ubuntu.com/ubuntu/pool/universe/n/ncurses/libtinfo5_6.4-2_amd64.deb&quot; title=&quot;http://archive.ubuntu.com/ubuntu/pool/universe/n/ncurses/libtinfo5_6.4-2_amd64.deb&quot; data-renderer-mark=&quot;true&quot; class=&quot;cc-1rn59kg&quot;&gt;download oficial&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-renderer-start-pos=&quot;3303&quot;&gt;Vamos baixar e instalar estes três pacotes:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;3303&quot;&gt;# cd /opt&lt;br&gt;# curl -LO http://archive.ubuntu.com/ubuntu/pool/universe/n/ncurses/libtinfo5_6.4-2_amd64.deb&lt;br&gt;# dpkg -i libtinfo5_6.4-2_amd64.deb&lt;br&gt;# curl -LO http://archive.ubuntu.com/ubuntu/pool/universe/n/ncurses/libncurses5_6.4-2_amd64.deb&lt;br&gt;# dpkg -i libncurses5_6.4-2_amd64.deb&lt;br&gt;# curl -LO http://archive.ubuntu.com/ubuntu/pool/main/liba/libaio/libaio1_0.3.113-5_amd64.deb&lt;br&gt;# dpkg -i libaio1_0.3.113-5_amd64.deb&lt;/pre&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image post__image--full&quot; src=&quot;/media/posts/79/instalar-bibliotecas-libaio-libtinfo-libncurses.jpg&quot; alt=&quot;Download de dependências via curl e instalação via dpkg -i&quot; width=&quot;1341&quot; height=&quot;1160&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;cc-1wlpsko&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;3757&quot;&gt;Download de dependências via &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;curl&lt;/code&gt; e instalação via &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;dpkg -i&lt;/code&gt;&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;Adicionar-binários-ao-escopo-global-do-Linux&quot; data-renderer-start-pos=&quot;3818&quot;&gt;Adicionar binários ao escopo global do Linux&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;3864&quot;&gt;Neste momento se você tentar executar o comando &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;mysql&lt;/code&gt; ou iniciar o servidor &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;mysqld_safe&lt;/code&gt; receberá uma mensagem de “Comando não encontrado”. Isso porque apesar de termos baixado e extraído os arquivos do servidor, os binários ainda não estão disponíveis no sistema.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;4129&quot;&gt;Para que o sistema possa encontrar os binários, vamos fazer links simbólicos dentro de &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;/usr/bin&lt;/code&gt; para expor os arquivos binários dentro de &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;/opt/mysql/server-5.5/bin&lt;/code&gt;. Resolvi utilizar um loop &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;for ...; do ; done&lt;/code&gt; para iterar sobre todos os arquivos binários do MySQL 5.5 e a partir desta lista fazer os links simbólicos com o comando &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;ln -s&lt;/code&gt;:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;4129&quot;&gt;# for f in &quot;/opt/mysql/server-5.5/bin&quot;/*; do&lt;br&gt;&amp;gt;   filename=$(basename $f);&lt;br&gt;&amp;gt;   ln -s $f &quot;/usr/bin/$filename&quot;;&lt;br&gt;&amp;gt; done&lt;br&gt;# mysql --version&lt;br&gt;mysql  Ver 14.14 Distrib 5.5.40, for debian6.0 (x86_64) using readline 5.1&lt;/pre&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image post__image--full&quot; src=&quot;/media/posts/79/link-simbolico-binarios-mysql.jpg&quot; alt=&quot;Criação de links simbólicos dentro de um loop &amp;#96;for&amp;#96;&quot; width=&quot;1341&quot; height=&quot;213&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Criação de links simbólicos dentro de um loop for&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;Criar-usuário,-grupo-e-pastas-do-MySQL-Server-5.5&quot; data-renderer-start-pos=&quot;4731&quot;&gt;Criar usuário, grupo e pastas do MySQL Server 5.5&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;4782&quot;&gt;Não é recomendável rodar o MySQL Server com o usuário &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;root&lt;/code&gt; por questões de segurança. Portanto vamos criar um usuário &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;mysql&lt;/code&gt; que pertence ao grupo &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;mysql&lt;/code&gt; e atribuir algumas pastas à este usuário:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;4782&quot;&gt;# groupadd mysql&lt;br&gt;# useradd -g mysql mysql&lt;br&gt;# chown mysql:mysql -R /opt/mysql/server-5.5&lt;/pre&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image post__image--full&quot; src=&quot;/media/posts/79/criar-grupo-usuario-permissao-mysql.jpg&quot; alt=&quot;Criação do grupo e usuário mysql. Atribuição da pasta /opt/mysql/server-5.5 à este grupo e usuário.&quot; width=&quot;1341&quot; height=&quot;219&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;cc-1wlpsko&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;5067&quot;&gt;Criação do grupo e usuário &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;mysql&lt;/code&gt;. Atribuição da pasta &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;/opt/mysql/server-5.5&lt;/code&gt; à este grupo e usuário.&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;Configurar-o-MySQL&quot; data-renderer-start-pos=&quot;5169&quot;&gt;Configurar o MySQL&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;5189&quot;&gt;Existem alguns arquivos de configuração do MySQL dentro da pasta &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;/opt/mysql/server-5.5/support-files&lt;/code&gt;, vamos copiar o arquivo &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;my-small.cnf&lt;/code&gt; para o diretório &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;/etc/mysql/&lt;/code&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;5358&quot;&gt;Vamos também transformar o MySQL em um serviço reconhecido pelo Ubuntu ao copiar o arquivo &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;mysql.server&lt;/code&gt; para o diretório &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;/etc/init.d&lt;/code&gt;:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;5358&quot;&gt;# mkdir /etc/mysql&lt;br&gt;# cp /opt/mysql/server-5.5/support-files/my-small.cnf /etc/mysql/my.cnf&lt;br&gt;# cp /opt/mysql/server-5.5/support-files/mysql.server /etc/init.d/mysql.server&lt;/pre&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image post__image--full&quot; src=&quot;/media/posts/79/copia-arquivos-padrao-mysql-5.5.jpg&quot; alt=&quot;Cópia dos arquivos padrão da instalação do MySQL 5.5&quot; width=&quot;1341&quot; height=&quot;219&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;cc-1wlpsko&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;5666&quot;&gt;Cópia dos arquivos padrão da instalação do MySQL 5.5&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;5721&quot;&gt;Como nós instalamos nossos arquivos numa pasta fora do padrão, precisamos alterar o conteúdo do arquivo de configuração &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;my.cnf&lt;/code&gt; para adicionar os campos &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;datadir&lt;/code&gt; e &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;basedir&lt;/code&gt; sob a configuração &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;mysqld&lt;/code&gt;. Abra o arquivo &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;/etc/mysql/my.cnf&lt;/code&gt; com seu editor de preferência, e adicione essas duas linhas abaixo da categoria &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;[mysqld]&lt;/code&gt;:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;5721&quot;&gt;[mysqld]&lt;br&gt;basedir = /opt/mysql/server-5.5&lt;br&gt;datadir = /opt/mysql/server-5.5/data&lt;/pre&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image post__image--full&quot; src=&quot;/media/posts/79/basedir-e-datadir-mysql-5.5-my.cnf.jpg&quot; alt=&quot;Adicionadas as opções basedir e datadir no arquivo &amp;#96;/etc/mysql/my.cnf&amp;#96;&quot; width=&quot;1341&quot; height=&quot;499&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;cc-1wlpsko&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;6123&quot;&gt;Adicionadas as opções &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;basedir&lt;/code&gt; e &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;datadir&lt;/code&gt; no arquivo &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;/etc/mysql/my.cnf&lt;/code&gt;&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;(Opcional)-Inicializar-dados-do-servidor-MySQL-5.5&quot; data-renderer-start-pos=&quot;6194&quot;&gt;(Opcional) Inicializar dados do servidor MySQL 5.5&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;6246&quot;&gt;Caso você esteja iniciando do zero, sem nenhum dado para migrar, é importante inicializar a base de dados para que as tabelas de sistema e usuários sejam instalados. &lt;strong data-renderer-mark=&quot;true&quot;&gt;Não é recomendado inicializar os dados do servidor caso você esteja migrando arquivos de um servidor para outro, você irá inutilizar seu banco de dados!&lt;/strong&gt;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;6566&quot;&gt;Você pode inicializar os dados do servidor MySQL 5.5 ao invocar o script &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;mysql_install_db&lt;/code&gt;:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;6566&quot;&gt;# /opt/mysql/server-5.5/scripts/mysql_install_db&lt;/pre&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image post__image--full&quot; src=&quot;/media/posts/79/inicializacao-servidor-mysql-5.5.jpg&quot; alt=&quot;Inicialização das tabelas do banco MySQL 5.5&quot; width=&quot;1341&quot; height=&quot;1025&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;cc-1wlpsko&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;6710&quot;&gt;Inicialização das tabelas do banco MySQL 5.5&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;Instalação-concluída!&quot; data-renderer-start-pos=&quot;6757&quot;&gt;Instalação concluída!&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;6780&quot;&gt;O servidor MySQL 5.5 já está instalado em seu Ubuntu 22.04 LTS! Você pode inicializar o servidor utilizando a linha de comando.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;6909&quot;&gt;Vamos iniciar o &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;mysqld_safe&lt;/code&gt; e realizar um breve teste:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;6909&quot;&gt;# mysqld_safe --user=mysql &amp;amp;&lt;br&gt;# mysql -uroot&lt;br&gt;&lt;br&gt;mysql&amp;gt; show databases;&lt;/pre&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image post__image--full&quot; src=&quot;/media/posts/79/teste-servidor-mysql-5.5.jpg&quot; alt=&quot;Teste do servidor MySQL 5.5 utilizando o comando SQL show databases&quot; width=&quot;1341&quot; height=&quot;1025&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;cc-1wlpsko&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;7036&quot;&gt;Teste do servidor MySQL 5.5 utilizando o comando SQL &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;show databases&lt;/code&gt;&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;</content:encoded><category>linux</category><category>mysql</category><category>ubuntu</category></item><item><title>6 regras de etiqueta para profissionais de tecnologia</title><link>https://codamos.com.br/comportamento-trabalho-profissionais-tecnologia/</link><guid isPermaLink="true">https://codamos.com.br/comportamento-trabalho-profissionais-tecnologia/</guid><description>Neste artigo eu trago algumas dicas de como se comportar no ambiente profissional que são particularmente valiosas para uma profissional de tecnologia e que se aplicam principalmente às profissões de </description><pubDate>Sat, 17 Aug 2024 11:40:41 GMT</pubDate><content:encoded>&lt;p data-renderer-start-pos=&quot;4&quot;&gt;Neste artigo eu trago algumas dicas de como se comportar no ambiente profissional que são particularmente valiosas para uma profissional de tecnologia e que se aplicam principalmente às profissões de desenvolvedora de software, analista de testes, analista de dados, cientista de dados, devops e suporte técnico. &lt;strong data-renderer-mark=&quot;true&quot;&gt;Estas dicas são particularmente úteis para quem está no começo da carreira e ainda precisa se adaptar ao mundo do trabalho na tecnologia.&lt;/strong&gt;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;456&quot;&gt;Aqui você vai encontrar dicas sobre como colaborar com o restante do time de maneira a otimizar o trabalho de todo mundo, reduzir o estresse e aumentar a satisfação no dia a dia de trabalho.&lt;/p&gt;
&lt;div class=&quot;ak-editor-panel__content&quot;&gt;
&lt;p class=&quot;msg msg--highlight &quot; data-renderer-start-pos=&quot;649&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;A palavra chave aqui é autonomia!&lt;/strong&gt; Todas essas dicas se baseiam na ideia de que você precisa buscar se tornar uma profissional com autonomia o suficiente para atingir seus objetivos. E da mesma forma, você se esforça para que suas colegas possam atingir a mesma autonomia.&lt;/p&gt;
&lt;div class=&quot;post__toc&quot;&gt;
&lt;h3&gt;Neste artigo: regras de etiqueta para profissionais de tecnologia&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#1.-Revise-o-seu-próprio-Pull-Request-antes-de-solicitar-revisão&quot;&gt;Revise o seu próprio Pull Request antes de solicitar revisão&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#2.-Descreva-seu-Pull-Request-com-carinho&quot;&gt;Descreva seu Pull Request com carinho&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#3.-Atualize-a-documentação-sempre-que-fizer-uma-alteração&quot;&gt;Atualize a documentação sempre que fizer uma alteração&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#4.-Adote-uma-comunicação-clara-e-direta&quot;&gt;Adote uma comunicação clara e direta&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#5.-Respeite-o-tempo-do-outro-ao-pedir-ajuda&quot;&gt;Respeite o tempo do outro ao pedir ajuda&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#6.-Comunique-dificuldades-e-atrasos-o-quanto-antes&quot;&gt;Comunique dificuldades e atrasos o quanto antes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id=&quot;1.-Revise-o-seu-próprio-Pull-Request-antes-de-solicitar-revisão&quot; data-renderer-start-pos=&quot;932&quot;&gt;1. Revise o seu próprio &lt;em data-renderer-mark=&quot;true&quot;&gt;Pull Request&lt;/em&gt; antes de solicitar revisão&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;997&quot;&gt;Isto se aplica a qualquer tipo de trabalho que você fizer em colaboração com outras pessoas: código, documentação, apresentações… É importante que você faça sempre a primeira revisão do seu trabalho antes de pedir a opinião das outras pessoas.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1242&quot;&gt;Revisar seu próprio trabalho vai garantir que você tire os erros mais óbvios do caminho como erros de escrita, de ortografia, erros lógicos ou até mesmo te faça refletir em como você pode ajudar a próxima pessoa a revisar seu trabalho de forma rápida.&lt;/p&gt;
&lt;h2 id=&quot;2.-Descreva-seu-Pull-Request-com-carinho&quot; data-renderer-start-pos=&quot;1495&quot;&gt;2. Descreva seu &lt;em data-renderer-mark=&quot;true&quot;&gt;Pull Request&lt;/em&gt; com carinho&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;1537&quot;&gt;Sempre que você criar um &lt;em data-renderer-mark=&quot;true&quot;&gt;Pull Request&lt;/em&gt; é importante pensar que quem lê aquele código não tem o mesmo contexto que você teve quando o escreveu. É bem capaz que se você deixar o &lt;em data-renderer-mark=&quot;true&quot;&gt;Pull Request&lt;/em&gt; de lado e voltar em 2 dias nem você mesma vá lembrar das alterações que fez.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1803&quot;&gt;Então é importantíssimo sempre deixar muito claro na descrição do seu &lt;em data-renderer-mark=&quot;true&quot;&gt;Pull Request&lt;/em&gt; o que está sendo modificado, como e o objetivo desta alteração.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1951&quot;&gt;Em ferramentas como Github e Gitlab é possível colocar vídeos e imagens na descrição de um &lt;em data-renderer-mark=&quot;true&quot;&gt;Pull Request&lt;/em&gt;. Você se destaca de forma positiva se adota o costume de descrever o que está sendo feito e colocar um vídeo descrevendo suas alterações ou mostrando o resultado final. Desta forma você reduz o número de perguntas que sua revisora precisa fazer para entender o seu contexto e começar a fazer uma revisão útil.&lt;/p&gt;
&lt;h2 id=&quot;3.-Atualize-a-documentação-sempre-que-fizer-uma-alteração&quot; data-renderer-start-pos=&quot;2366&quot;&gt;3. Atualize a documentação sempre que fizer uma alteração&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;2425&quot;&gt;É natural que uma documentação que não é gerada automaticamente acabe ficando atrasada em relação à implementação do código. Em algumas empresas as pessoas que escrevem o software não são as mesmas que fazem a documentação, isto acaba virando responsabilidade de outra pessoa.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2703&quot;&gt;Em todos os casos é importante que a documentação sempre reflita a realidade. Então, se você criou ou alterou um método, classe ou uma API e isto é importante de ser documentado, faça um esforço para atualizar a documentação: faça você mesma a atualização ou procure quem possa iniciar este procedimento e avise sobre as suas alterações.&lt;/p&gt;
&lt;h2 id=&quot;4.-Adote-uma-comunicação-clara-e-direta&quot; data-renderer-start-pos=&quot;3042&quot;&gt;4. Adote uma comunicação clara e direta&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;3083&quot;&gt;Para quem está começando na área de tecnologia isso pode ser um desafio, mas a comunicação clara e direta é chave para levar qualquer equipe ao sucesso!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3237&quot;&gt;Em muitos casos a sua colega não precisa de todos os detalhes que você carrega consigo: só a mensagem ou pedido que você tem pra fazer já é suficiente. Em alguns casos estas informações adicionais podem ser importantes: deixe que a sua colega pergunte por estas informações. Veja aqui um exemplo:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p data-renderer-start-pos=&quot;3536&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Pedro: &lt;/strong&gt;Andressa, posso te pedir uma coisa?&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3580&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Andressa: &lt;/strong&gt;Hmmm? O que foi?&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3608&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Pedro: &lt;/strong&gt;É que eu estava conversando com a nossa diretora ontem, e a Valéria estava me contando sobre aquela falha que aconteceu semana passada. Sabe?&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3758&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Andressa: &lt;/strong&gt;Qual falha?&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3781&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Pedro: &lt;/strong&gt;Quando o site caiu e a gente ficou sem visibilidade nenhuma. Sabe?&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3856&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Andressa:&lt;/strong&gt; Não tô sabendo. Eu tava de férias. Mas o que tem?&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3917&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Pedro:&lt;/strong&gt; Deixa. Isso nem é importante. A questão é que ela disse que gostaria de fazer um &lt;em data-renderer-mark=&quot;true&quot;&gt;dashboard&lt;/em&gt; pra visualizar se o site está de pé ou não.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;4060&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Andressa:&lt;/strong&gt; Tá…&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;4075&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Pedro:&lt;/strong&gt; …&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;4085&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Andressa:&lt;/strong&gt; E como eu posso te ajudar Pedro?&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;4129&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Pedro:&lt;/strong&gt; É que eu já criei o &lt;em data-renderer-mark=&quot;true&quot;&gt;dashboard&lt;/em&gt; e preciso dar acesso pra Valéria.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;4201&quot;&gt;…&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-renderer-start-pos=&quot;4205&quot;&gt;Soa familiar o diálogo? Pois é, muitas das nossas conversas são assim desde a infância até o começo da carreira profissional. Mas ele poderia ter sido bem mais curto e direto, veja:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p data-renderer-start-pos=&quot;4389&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Pedro:&lt;/strong&gt; Andressa, me ajuda a dar acesso à um &lt;em data-renderer-mark=&quot;true&quot;&gt;dashboard&lt;/em&gt; pra Valéria?&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;4458&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Andressa: &lt;/strong&gt;Claro! Te chamo em 30 minutos pra gente fazer. Me manda o link pro &lt;em data-renderer-mark=&quot;true&quot;&gt;dashboard&lt;/em&gt; que eu já deixo preparado.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-renderer-start-pos=&quot;4574&quot;&gt;Para quem está acostumada a falar desta forma, pode ser difícil fazer a mudança. Mas todos nós aprendemos com o tempo e prática. Em alguns momentos você pode parecer seca, em outros talvez até rude. Mas com o tempo esta habilidade vai ficar mais forte e você vai ter interações muito mais úteis e leves com suas colegas de trabalho.&lt;/p&gt;
&lt;h2 id=&quot;5.-Respeite-o-tempo-do-outro-ao-pedir-ajuda&quot; data-renderer-start-pos=&quot;4908&quot;&gt;5. Respeite o tempo do outro ao pedir ajuda&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;4953&quot;&gt;Não importa muito se o ambiente de trabalho é remoto, presencial ou híbrido. Interrupções são muito ruins para o ambiente de trabalho. Cada interrupção pode custar de 10 a 30 minutos de pura inatividade em uma profissional que precisa de foco e criatividade para produzir. Quatro interrupções em muitos casos podem significar um dia de trabalho perdido.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;5308&quot;&gt;Portanto é importante notar que sua colega tem outras tarefas a fazer e que o seu pedido, apesar de importante pra você, tem outra prioridade para a sua colega. É importante ser paciente e procurar oferecer o máximo de informação e autonomia que puder para sua colega te ajudar de forma rápida e certeira. E ao mesmo tempo é importante entender que o seu pedido pode ficar de 5 minutos até algumas horas sem resposta.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;5727&quot;&gt;Ao mesmo tempo, não fique parada! Enquanto espera você pode continuar tentando resolver seu problema ou resolver tarefas menores até receber um retorno.&lt;/p&gt;
&lt;h2 id=&quot;6.-Comunique-dificuldades-e-atrasos-o-quanto-antes&quot; data-renderer-start-pos=&quot;5881&quot;&gt;6. Comunique dificuldades e atrasos o quanto antes&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;5933&quot;&gt;Nada mais triste do que entrar numa reunião em que todas criaram uma expectativa enorme no resultado do seu trabalho para só então descobrir que você precisa de mais alguns dias para entregar.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;6127&quot;&gt;Na maioria dos casos o atraso não é exatamente o problema mas sim a expectativa! Portanto sempre que tiver alguma dificuldade ou perceber que o prazo está escapando, comunique o quanto antes. Isto ajuda a alinhar expectativas e ao restante do time a se adaptar à situação. Talvez eles venham dividir a tarefa contigo, talvez dêem prioridade a outras tarefas.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;6487&quot;&gt;O que não dá é pra chegar no dia da entrega e falar de surpresa pra todo mundo que não vai conseguir.&lt;/p&gt;
&lt;h2 id=&quot;Conclusão&quot; data-renderer-start-pos=&quot;6590&quot;&gt;Conclusão&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;6601&quot;&gt;Todas as dicas que eu coloquei neste artigo se referem ao seu dia a dia e como você pode colaborar melhor com suas colegas de trabalho. A palavra chave é autonomia: busque ser independente quando possível e ofereça todas as ferramentas possíveis para que suas colegas também possam ser independentes.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;6903&quot;&gt;São dicas valiosíssimas para quem está no começo da carreira ou ainda não se acostumou a pensar de forma sistêmica.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;7020&quot;&gt;Uma equipe mais autônoma consegue entregar com menos esforço, estresse e conflitos. Quando a comunicação é clara e oferece todo o contexto necessário, mas nada além do necessário, todo mundo sai ganhando.&lt;/p&gt;
&lt;/div&gt;</content:encoded><category>carreira</category><category>junior</category></item><item><title>Como rodar um client OpenVPN dentro de um container docker</title><link>https://codamos.com.br/como-conectar-vpn-dentro-de-container-docker/</link><guid isPermaLink="true">https://codamos.com.br/como-conectar-vpn-dentro-de-container-docker/</guid><description>Com certa frequência eu preciso me conectar a redes VPN para realizar serviços em clientes com servidores em outros continentes, de forma que a latência de todos os aplicativos do meu computador que u</description><pubDate>Mon, 25 Dec 2023 16:24:45 GMT</pubDate><content:encoded>&lt;p data-renderer-start-pos=&quot;1&quot;&gt;Com certa frequência eu preciso me conectar a redes VPN para realizar serviços em clientes com servidores em outros continentes, de forma que a latência de todos os aplicativos do meu computador que utilizam a internet acabam por sofrer - e muitas vezes eu preciso apenas fazer uma conexão SSH.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;297&quot;&gt;Neste tutorial eu vou te mostrar como eu resolvi este problema ao mover o cliente VPN para um contêiner &lt;em data-renderer-mark=&quot;true&quot;&gt;docker&lt;/em&gt; de forma que toda a rede da minha máquina se manteve com a conexão local comum.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;297&quot;&gt;Como já é de costume, fiz um vídeo rápido explicando como seguir o passo a passo deste artigo:&lt;/p&gt;
&lt;figure class=&quot;post__video&quot;&gt;&lt;iframe width=&quot;560&quot; height=&quot;314&quot; src=&quot;https://www.youtube.com/embed/UaKXWY8o228&quot; allowfullscreen=&quot;allowfullscreen&quot; data-mce-fragment=&quot;1&quot;&gt;&lt;/iframe&gt;&lt;/figure&gt;
&lt;h2 id=&quot;Configurar-um-contêiner-docker-para-conectar-se-à-VPN&quot; data-renderer-start-pos=&quot;489&quot;&gt;Configurar um contêiner &lt;em data-renderer-mark=&quot;true&quot;&gt;docker&lt;/em&gt; para conectar-se à VPN&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;544&quot;&gt;Para este tutorial vamos utilizar a imagem &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;alpine:3.17&lt;/code&gt;, mas este passo a passo deverá funcionar com qualquer outra distribuição - talvez com alguns ajustes aqui e ali.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;713&quot;&gt;Vamos então baixar a imagem:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;713&quot;&gt;$ docker pull alpine:3.17&lt;/pre&gt;
&lt;figure contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image&quot; src=&quot;/media/posts/77/baixar-imagem-docker-alpine.png&quot; alt=&quot;Comando docker pull que baixa a imagem alpine:3.17&quot; width=&quot;936&quot; height=&quot;579&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Comando &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;docker pull&lt;/code&gt; que baixa a imagem &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;alpine:3.17&lt;/code&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;825&quot;&gt;Após baixada a imagem podemos já rodar o nosso contêiner. Para executar o contêiner precisamos passar alguns parâmetros relacionados à rede e como ele vai criar o túnel VPN. A linha de comando completa fica assim:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;825&quot;&gt;$ docker run --rm -it --cap-add=NET_ADMIN alpine:3.17&lt;/pre&gt;
&lt;figure contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image&quot; src=&quot;/media/posts/77/rodar-conteiner-docker-com-rede-2.png&quot; alt=&quot;Dentro do contêiner, visualizando dados do usuário e interfaces de rede.&quot; width=&quot;936&quot; height=&quot;576&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Dentro do contêiner, visualizando dados do usuário e interfaces de rede.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;1172&quot;&gt;O comando acima vai rodar um contêiner em modo interativo (&lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;-it&lt;/code&gt;) e este contêiner vai ser removido assim que você terminar sua sessão (&lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;--rm&lt;/code&gt;). Além disso nós vamos dar a capacidade ao contêiner de mexer na nossa interface de rede (&lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;--cap-add=NET_ADMIN&lt;/code&gt;). Por fim, estamos invocando uma sessão &lt;em data-renderer-mark=&quot;true&quot;&gt;shell&lt;/em&gt; da imagem &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;alpine:3.17&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;Como-instalar-e-configurar-o-cliente-openvpn-no-contêiner-docker&quot; data-renderer-start-pos=&quot;1491&quot;&gt;Como instalar e configurar o cliente &lt;em data-renderer-mark=&quot;true&quot;&gt;openvpn&lt;/em&gt; no contêiner &lt;em data-renderer-mark=&quot;true&quot;&gt;docker&lt;/em&gt;&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;1557&quot;&gt;Agora que o contêiner já tem a capacidade de modificar a nossa interface de rede (&lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;--cap-add=NET_ADMIN&lt;/code&gt;) nós podemos instalar os pacotes necessários e configurar o ambinte.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1729&quot;&gt;Vamos criar um &lt;em data-renderer-mark=&quot;true&quot;&gt;device&lt;/em&gt; que será capaz de abrir um túnel VPN dentro do contêiner seguindo as &lt;a data-testid=&quot;link-with-safety&quot; href=&quot;https://www.kernel.org/doc/html/latest/networking/tuntap.html#configuration&quot; title=&quot;https://www.kernel.org/doc/html/latest/networking/tuntap.html#configuration&quot; data-renderer-mark=&quot;true&quot; class=&quot;cc-tgpl01&quot;&gt;instruções de configuração do driver TAP/TUN do manual do Kernel GNU/Linux&lt;/a&gt;:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;1729&quot;&gt;$ mkdir /dev/net&lt;br&gt;$ mknod /dev/net/tun c 10 200&lt;br&gt;$ chmod 0666 /dev/net/tun&lt;/pre&gt;
&lt;figure contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image&quot; src=&quot;/media/posts/77/criar-device-tun-tap-linux.png&quot; alt=&quot;Criando o device de TUN/TAP conforme o manual do Kernel GNU/Linux&quot; width=&quot;936&quot; height=&quot;576&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Criando o &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;device&lt;/code&gt; de TUN/TAP conforme o manual do Kernel GNU/Linux&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;2041&quot;&gt;Agora podemos instalar o cliente &lt;a data-testid=&quot;link-with-safety&quot; href=&quot;https://openvpn.net/&quot; title=&quot;https://openvpn.net/&quot; data-renderer-mark=&quot;true&quot; class=&quot;cc-tgpl01&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;openvpn&lt;/em&gt;&lt;/a&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt; &lt;/em&gt;diretamente no nosso contêiner alpine:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;2041&quot;&gt;$ apk update&lt;br&gt;$ apk add openvpn&lt;/pre&gt;
&lt;figure contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image&quot; src=&quot;/media/posts/77/instalar-cliente-openvpn-2.png&quot; alt=&quot;Instalação do pacote openvpn através do gerenciador de pacotes apk&quot; width=&quot;936&quot; height=&quot;576&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Instalação do pacote &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;openvpn&lt;/code&gt; através do gerenciador de pacotes &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;apk&lt;/code&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;Como-ligar-a-rede-VPN-dentro-do-contêiner-docker&quot; data-renderer-start-pos=&quot;2225&quot;&gt;Como ligar a rede VPN dentro do contêiner &lt;em data-renderer-mark=&quot;true&quot;&gt;docker&lt;/em&gt;&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;2275&quot;&gt;Agora que tudo está instalado e configurado, podemos conectar o nosso contêiner à rede VPN através da linha de comando seguinte:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;2275&quot;&gt;$ openvpn client.ovpn &amp;gt; /dev/null &amp;amp;&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;2442&quot;&gt;Onde &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;client.ovpn&lt;/code&gt; é um &lt;a data-testid=&quot;link-with-safety&quot; href=&quot;https://openvpn.net/community-resources/how-to/#editing-the-client-configuration-files&quot; title=&quot;https://openvpn.net/community-resources/how-to/#editing-the-client-configuration-files&quot; data-renderer-mark=&quot;true&quot; class=&quot;cc-tgpl01&quot;&gt;arquivo de configuração no formato do OpenVPN&lt;/a&gt; com os dados de conexão e credenciais da rede externa. Repare que o fim do comando redireciona qualquer texto para o limbo de forma que não apareça na sua tela (&lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;&amp;gt; /dev/null&lt;/code&gt;) e joga o comando para executar em plano de fundo (&lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;&amp;amp;&lt;/code&gt;) de maneira que você possa rodar outros comandos imediatamente.&lt;/p&gt;
&lt;figure contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image&quot; src=&quot;/media/posts/77/conectar-vpn-via-cli-com-openvpn.png&quot; alt=&quot;Ilustração do comando que abre o túnel VPN. Repare que o tempo de resposta do ping aumentou após alguns momentos - exatamente quando o túnel foi estabelecido.&quot; width=&quot;936&quot; height=&quot;576&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Ilustração do comando que abre o túnel VPN. Repare que o tempo de resposta do &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;ping&lt;/code&gt; aumentou após alguns momentos - exatamente quando o túnel foi estabelecido.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;2964&quot;&gt;Desta forma você consegue rodar o cliente VPN dentro de um contêiner docker sem precisar conectar a sua máquina &lt;em data-renderer-mark=&quot;true&quot;&gt;host&lt;/em&gt; ao servidor externo, de forma a poder utilizar outros serviços online sem o problema da latência.&lt;/p&gt;</content:encoded><category>docker</category><category>tecnica</category><category>produtividade</category></item><item><title>Como ler variáveis de ambiente na linguagem Rust</title><link>https://codamos.com.br/como-ler-variaveis-de-ambiente-na-linguagem-rust/</link><guid isPermaLink="true">https://codamos.com.br/como-ler-variaveis-de-ambiente-na-linguagem-rust/</guid><description>Em diversas situações a gente pode precisar utilizar variáveis de ambiente, alguns exemplos incluem: Alterar o comportamento do software através de Feature flags Dar acesso a segredos e chaves de API </description><pubDate>Tue, 19 Dec 2023 09:28:45 GMT</pubDate><content:encoded>&lt;p data-renderer-start-pos=&quot;66&quot;&gt;Em diversas situações a gente pode precisar utilizar variáveis de ambiente, alguns exemplos incluem:&lt;/p&gt;
&lt;ul class=&quot;ak-ul&quot; data-indent-level=&quot;1&quot;&gt;
&lt;li&gt;
&lt;p data-renderer-start-pos=&quot;170&quot;&gt;Alterar o comportamento do software através de &lt;a data-testid=&quot;link-with-safety&quot; href=&quot;https://codamos.com.br/feature-flags/&quot; title=&quot;https://codamos.com.br/feature-flags/&quot; data-renderer-mark=&quot;true&quot; class=&quot;cc-tgpl01&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;Feature flags&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;Dar acesso a segredos e chaves de API&lt;/li&gt;
&lt;li&gt;Personalizar a configuração do software - por exemplo, alterar a porta de um servidor&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Para facilitar o aprendizado, eu montei um vídeo bem simples pra explicar tudo o que está aqui no artigo:&lt;/p&gt;
&lt;figure class=&quot;post__video&quot;&gt;&lt;iframe width=&quot;560&quot; height=&quot;314&quot; src=&quot;https://www.youtube.com/embed/NDYKKenx-VU&quot; allowfullscreen=&quot;allowfullscreen&quot; data-mce-fragment=&quot;1&quot;&gt;&lt;/iframe&gt;&lt;/figure&gt;
&lt;h2 id=&quot;Como-ler-variáveis-de-ambiente-com-Rust-utilizando-a-biblioteca-padrão&quot; data-renderer-start-pos=&quot;364&quot;&gt;Como ler variáveis de ambiente com Rust utilizando a biblioteca padrão&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;436&quot;&gt;Rust possui uma biblioteca padrão bem completinha, que é a &lt;a data-testid=&quot;link-with-safety&quot; href=&quot;https://doc.rust-lang.org/std/index.html&quot; title=&quot;https://doc.rust-lang.org/std/index.html&quot; data-renderer-mark=&quot;true&quot; class=&quot;cc-tgpl01&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;std&lt;/em&gt;&lt;/a&gt;. Para acessar variáveis de ambiente utilizando esta biblioteca, você pode utilizar a função &lt;a data-testid=&quot;link-with-safety&quot; href=&quot;https://doc.rust-lang.org/std/env/fn.var.html&quot; title=&quot;https://doc.rust-lang.org/std/env/fn.var.html&quot; data-renderer-mark=&quot;true&quot; class=&quot;cc-tgpl01&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;std::env::var()&lt;/em&gt;&lt;/a&gt; e o seu tipo de retorno é um objeto do tipo &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;Result&amp;lt;String, VarError&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;436&quot;&gt;Então para obter uma variável de ambiente chamada &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;SERVER_PORT&lt;/code&gt; podemos fazer algo como o seguinte:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;436&quot;&gt;fn main() {&lt;br&gt;  let port = std::env::var(&quot;SERVER_PORT&quot;).unwrap_or(&quot;8080&quot;.to_string());&lt;br&gt;  &lt;br&gt;  println!(&quot;A porta e {}&quot;, port);&lt;br&gt;}&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;902&quot;&gt;Repare que como o retorno é do tipo &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;Result&amp;lt;String, VarError&amp;gt;&lt;/code&gt; você pode utilizar a função &lt;a data-testid=&quot;link-with-safety&quot; href=&quot;https://doc.rust-lang.org/std/result/enum.Result.html#method.unwrap_or&quot; title=&quot;https://doc.rust-lang.org/std/result/enum.Result.html#method.unwrap_or&quot; data-renderer-mark=&quot;true&quot; class=&quot;cc-tgpl01&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;unwrap_or()&lt;/em&gt;&lt;/a&gt; para definir um valor padrão caso a variável não esteja presente. Portanto ao rodar o programa, temos as seguintes saídas:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;902&quot;&gt;$ cargo run&lt;br&gt;A porta e 8080&lt;br&gt;&lt;br&gt;$ SERVER_PORT=9090 cargo run&lt;br&gt;A porta e 9090&lt;/pre&gt;
&lt;h2 id=&quot;Como-ler-variáveis-de-ambiente-em-tempo-de-compilação-com-Rust&quot; data-renderer-start-pos=&quot;1200&quot;&gt;Como ler variáveis de ambiente em tempo de compilação com Rust&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;1264&quot;&gt;As vezes é importante mudar o comportamento do software em tempo de compilação e mantê-lo fixo durante o tempo de execução, por exemplo criar um comportamento diferente para ambientes Windows e Linux, ou utilizando o X11 ou Wayland.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1498&quot;&gt;Para fazer algo assim, também é possível utilizar variáveis de ambiente porém precisamos utilizar a macro &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;env!()&lt;/code&gt; que retorna um &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;&amp;amp;&apos;static str&lt;/code&gt;. É importante notar que quando a macro &lt;a data-testid=&quot;link-with-safety&quot; href=&quot;https://doc.rust-lang.org/core/macro.env.html&quot; title=&quot;https://doc.rust-lang.org/core/macro.env.html&quot; data-renderer-mark=&quot;true&quot; class=&quot;cc-tgpl01&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;env!&lt;/em&gt;&lt;/a&gt; é utilizada, a variável de ambiente precisa estar presente no momento da compilação - caso contrário um erro de compilação ocorre. Veja:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;1498&quot;&gt;fn main() {&lt;br&gt;  let default_port = env!(&quot;DEFAULT_SERVER_PORT&quot;);&lt;br&gt;  &lt;br&gt;  println!(&quot;A porta padrao e {}&quot;, default_port);&lt;br&gt;}&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;1938&quot;&gt;Ao compilar sem a variável de ambiente:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;1938&quot;&gt;$ cargo build&lt;br&gt;&lt;br&gt;error: environment variable `DEFAULT_SERVER_PORT` not defined at compile time&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;2073&quot;&gt;E ao compilar com a variável de ambiente definida e rodar o programa (que se chama rust-env no meu exemplo):&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;2073&quot;&gt;$ DEFAULT_SERVER_PORT=8080 cargo build&lt;br&gt;$ ./target/debug/rust-env&lt;br&gt;&lt;br&gt;A porta padrao e 8080&lt;br&gt;&lt;br&gt;$ DEFAULT_SERVER_PORT=9090 ./target/debug/rust-env&lt;br&gt;&lt;br&gt;A porta padrao e 8080&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;2347&quot;&gt;Repare que ao rodar o binário, mesmo que a variável &lt;code class=&quot;code cc-1o5d2cw&quot; data-renderer-mark=&quot;true&quot;&gt;DEFAULT_SERVER_PORT&lt;/code&gt; seja redefinida, o software não a utiliza. Isto porque a macro &lt;a data-testid=&quot;link-with-safety&quot; href=&quot;https://doc.rust-lang.org/core/macro.env.html&quot; title=&quot;https://doc.rust-lang.org/core/macro.env.html&quot; data-renderer-mark=&quot;true&quot; class=&quot;cc-tgpl01&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;env!&lt;/em&gt;&lt;/a&gt; só opera em tempo de compilação.&lt;/p&gt;</content:encoded><category>c</category><category>rust</category></item><item><title>Como escrever macros em C</title><link>https://codamos.com.br/como-escrever-macros-em-c/</link><guid isPermaLink="true">https://codamos.com.br/como-escrever-macros-em-c/</guid><description>A linguagem C em muitos casos nos exige escrever muitas linhas de código para fazer algo relativamente simples, e não são raros os casos em que precisamos repetir estas rotinas de novo e de novo. Bibl</description><pubDate>Sun, 08 Oct 2023 09:26:00 GMT</pubDate><content:encoded>&lt;p data-renderer-start-pos=&quot;4&quot;&gt;A linguagem C em muitos casos nos exige escrever muitas linhas de código para fazer algo relativamente simples, e não são raros os casos em que precisamos repetir estas rotinas de novo e de novo. Bibliotecas como a &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;libssh&lt;/code&gt; e a &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;libusb&lt;/code&gt; nos dão a responsabilidade de inicializar subsistemas, realizar verificações de rotina após cada operação… e tudo isso acaba engordando o nosso código com pouco significado semântico.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;422&quot;&gt;Neste tutorial eu vou te mostrar como simplificar estas rotinas repetitivas com macros em C, e como utilizar sua estrutura super poderosa: as macros de argumentos variáveis.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;422&quot;&gt;Caso você prefira um apoio em vídeo, tá aqui explicadinho o artigo todo e você consegue acompanhar com código conforme vou escrevendo os exemplos:&lt;/p&gt;
&lt;figure class=&quot;post__video&quot;&gt;&lt;iframe width=&quot;560&quot; height=&quot;314&quot; src=&quot;https://www.youtube.com/embed/RXzp5SZoOuI&quot; allowfullscreen=&quot;allowfullscreen&quot; data-mce-fragment=&quot;1&quot;&gt;&lt;/iframe&gt;&lt;/figure&gt;
&lt;h2 id=&quot;O-que-são-macros-na-linguagem-C?&quot; data-renderer-start-pos=&quot;597&quot;&gt;O que são macros na linguagem C?&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;631&quot;&gt;Macros na linguagem C são pedaços de código que você pode “inserir” em qualquer lugar. Você pode reconhecer uma macro através da palavra-chave &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;#define&lt;/code&gt;: se você vir esta palavra-chave antes de algum texto, este texto é uma macro.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;861&quot;&gt;Ao referenciar uma macro em seu código, o conteúdo desta macro é &lt;em data-renderer-mark=&quot;true&quot;&gt;copiado&lt;/em&gt; antes de compilar seu código.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;965&quot;&gt;Abaixo um exemplo de programa em C que define uma macro &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;CODAMOS&lt;/code&gt;, atribui um valor &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;&quot;codamos.com.br&quot;&lt;/code&gt; e a utiliza no contexto da função &lt;a data-testid=&quot;link-with-safety&quot; href=&quot;https://www.gnu.org/software/libc/manual/html_node/Formatted-Output-Functions.html#index-printf&quot; title=&quot;https://www.gnu.org/software/libc/manual/html_node/Formatted-Output-Functions.html#index-printf&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot;&gt;printf()&lt;/a&gt;.&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;965&quot;&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br&gt;&lt;br&gt;#define CODAMOS &quot;codamos.com.br&quot;&lt;br&gt;&lt;br&gt;int main(void)&lt;br&gt;{&lt;br&gt;  printf(&quot;Ola, %s\n&quot;, CODAMOS);&lt;br&gt;}&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;1215&quot;&gt;Eu comentei que as macros são &lt;em data-renderer-mark=&quot;true&quot;&gt;copiadas&lt;/em&gt; quando referenciadas. Acontece que antes de compilar seu código, ele vai se transformar no seguinte:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;1215&quot;&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br&gt;&lt;br&gt;int main(void)&lt;br&gt;{&lt;br&gt;  printf(&quot;Ola, %s\n&quot;, &quot;codamos.com.br&quot;);&lt;br&gt;}&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;1437&quot;&gt;Repare que ao compilar o código, a constante &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;CODAMOS&lt;/code&gt; foi substituída por seu valor definido: &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;&quot;codamos.com.br&quot;&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;Macros-como-funções-em-C&quot; data-renderer-start-pos=&quot;1549&quot;&gt;Macros como funções em C&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;1575&quot;&gt;Como vimos acima macros podem ser utilizadas para substituir um símbolo criado pela palavra-chave &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;#define&lt;/code&gt; por algum outro texto ou código. É possível fazer com que macros invoquem funções, como no exemplo abaixo:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;1575&quot;&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br&gt;&lt;br&gt;#define ECHO(msg) printf(msg);&lt;br&gt;&lt;br&gt;int main(void)&lt;br&gt;{&lt;br&gt;  ECHO(&quot;Ola codamos!\n&quot;);&lt;br&gt;}&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;1887&quot;&gt;Podemos inclusive fazer com que nossas macros automatizem certas rotinas, como por exemplo indicar o nível de log na mensagem:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;1887&quot;&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br&gt;&lt;br&gt;#define LOG_ERR(msg) fprintf(stderr, msg)&lt;br&gt;#define LOG_INFO(msg) fprintf(stdout, msg)&lt;br&gt;&lt;br&gt;int main(void)&lt;br&gt;{&lt;br&gt;  LOG_INFO(&quot;Inicializando o programa...\n&quot;);&lt;br&gt;  LOG_ERR(&quot;Falha ao inicializar o programa\n&quot;);&lt;br&gt;  return 1;&lt;br&gt;}&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;2246&quot;&gt;Repare que &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;LOG_INFO()&lt;/code&gt; e &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;LOG_ERR()&lt;/code&gt; não são funções. São apenas macros que se comportam como função. E por baixo dos panos tomam algumas decisões fundamentais e repetitivas como qual &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;stream&lt;/code&gt; utilizar para a saída da mensagem: &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;stdout&lt;/code&gt; ou &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;stderr&lt;/code&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2488&quot;&gt;Com macros podemos inclusive tornar este mecanismo ainda mais poderoso para indicar, por exemplo, qual a linha e arquivo onde um erro aconteceu. Veja:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;2488&quot;&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br&gt;&lt;br&gt;#define eprintf(msg) fprintf(stderr, &quot;[%s:%d] &quot;, __FILE__, __LINE__); fprintf(stderr, msg);&lt;br&gt;&lt;br&gt;int main(void)&lt;br&gt;{&lt;br&gt;  eprintf(&quot;Falha ao inicializar o programa\n&quot;);&lt;br&gt;}&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;2821&quot;&gt;Ao executar o código acima teremos uma saída mais ou menos assim:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p data-renderer-start-pos=&quot;2889&quot;&gt;[main.c:7] Falha ao inicializar o programa&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-renderer-start-pos=&quot;2934&quot;&gt;E se quisermos utilizar um &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;printf()&lt;/code&gt; com vários argumentos para interpolar strings? Neste caso precisamos de &lt;strong data-renderer-mark=&quot;true&quot;&gt;macros com argumentos variáveis&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;Macros-com-argumentos-variáveis&quot; data-renderer-start-pos=&quot;3076&quot;&gt;Macros com argumentos variáveis&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;3109&quot;&gt;A função &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;printf()&lt;/code&gt; (e outras parecidas como o &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;fprintf()&lt;/code&gt;) podem receber N argumentos de acordo com o argumento “formato” que é passado. O exemplo abaixo recebe uma string “codamos.com.br” e um inteiro com valor &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;10&lt;/code&gt;:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;3109&quot;&gt;printf(&quot;Site: %s, Nota: %d&quot;, &quot;codamos.com.br&quot;, 10);&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;3376&quot;&gt;Como podemos transferir estes valores para a nossa macro?&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3435&quot;&gt;Supondo que a nossa macro se chame &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;LOG_INFO&lt;/code&gt; e precise indicar o arquivo, linha e texto onde a mensagem foi enviada, podemos escrever algo assim:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;3435&quot;&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br&gt;&lt;br&gt;#define LOG_INFO(...) fprintf(stderr, &quot;[INFO] %s:%d: &quot;, __FILE__, __LINE__); fprintf(stderr, __VA_ARGS__);&lt;br&gt;&lt;br&gt;int main(void)&lt;br&gt;{&lt;br&gt;  LOG_INFO(&quot;Inicializando o programa &apos;%s&apos;.\n&quot;, &quot;codamos.com.br&quot;);&lt;br&gt;}&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;3803&quot;&gt;A macro acima utiliza a palavra-chave &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;__VA_ARGS__&lt;/code&gt; que justamente expande para todas as variáveis recebidas como parâmetro, representadas por &lt;code&gt;...&lt;/code&gt;, quando compilamos o programa. O termo para esta tecnica é &lt;a data-testid=&quot;link-with-safety&quot; href=&quot;https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html&quot; title=&quot;https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;Variadic Macros&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;4001&quot;&gt;A saída do comando acima deverá ser algo como:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p data-renderer-start-pos=&quot;4050&quot;&gt;[INFO] main.c:7: Inicializando o programa ‘codamos.com.br’&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-renderer-start-pos=&quot;4111&quot;&gt;Isto porque os dois parâmetros da macro &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;LOG_INFO&lt;/code&gt; foram a string &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;&quot;Inicializando o programa &apos;%s&apos;.\n&apos;&quot;&lt;/code&gt;e a string &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;&quot;codamos.com.br&quot;&lt;/code&gt;. Estes dois parâmetros foram armazenados no símbolo &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;__VA_ARGS__&lt;/code&gt; e repassados para a função &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;fprintf()&lt;/code&gt; no contexto daquela macro.&lt;/p&gt;
&lt;h2 id=&quot;Macros-com-multiplas-linhas-de-código&quot; data-renderer-start-pos=&quot;4367&quot;&gt;Macros com multiplas linhas de código&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;4406&quot;&gt;Como vimos nos exemplos anteriores, macros ficam bagunçadas rapidinho. Porque quanto mais funcionalidade a gente adicionar num único &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;#define&lt;/code&gt;, maior a linha daquela macro.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;4578&quot;&gt;Mas é possível quebrar as linhas de uma macro para que fique mais fácil de entender. Para isto é necessário adicionar uma barra invertida ao final de cada linha, veja como:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;4578&quot;&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br&gt;&lt;br&gt;#define LOG_INFO(...) \&lt;br&gt;  fprintf(stderr, &quot;[INFO] %s:%d: &quot;, __FILE__, __LINE__); \&lt;br&gt;  fprintf(stderr, __VA_ARGS__);&lt;br&gt;&lt;br&gt;int main(void)&lt;br&gt;{&lt;br&gt;  LOG_INFO(&quot;Inicializando o programa &apos;%s&apos;.\n&quot;, &quot;codamos.com.br&quot;);&lt;br&gt;}&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;4982&quot;&gt;A mensagem agora deverá ser quase a mesma de antes, o que muda é apenas a linha onde foi invocada a mensagem porque agora a macro possui múltiplas linhas:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p data-renderer-start-pos=&quot;5139&quot;&gt;[INFO] main.c:9: Inicializando o programa ‘codamos.com.br’&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded><category>c</category><category>produtividade</category><category>tecnica</category></item><item><title>O que é Software Livre?</title><link>https://codamos.com.br/o-que-e-software-livre/</link><guid isPermaLink="true">https://codamos.com.br/o-que-e-software-livre/</guid><description>Em determinado momento da carreira de programação a questão do Software Livre acaba aparecendo. Para quem trabalha com tecnologias como Linux talvez um pouco mais cedo do que para quem utiliza outras </description><pubDate>Tue, 03 Oct 2023 10:54:36 GMT</pubDate><content:encoded>&lt;p data-renderer-start-pos=&quot;1&quot;&gt;Em determinado momento da carreira de programação a questão do Software Livre acaba aparecendo. Para quem trabalha com tecnologias como Linux talvez um pouco mais cedo do que para quem utiliza outras tecnologias, mas este dia chega &lt;span data-emoji-id=&quot;1f642&quot; data-emoji-short-name=&quot;:slight_smile:&quot; data-emoji-text=&quot;🙂&quot;&gt;&lt;span class=&quot;emoji-common-main-styles emoji-common-node   emoji-common-emoji-image   css-9fkst0&quot; title=&quot;:slight_smile:&quot; role=&quot;img&quot; data-testid=&quot;image-emoji-:slight_smile:&quot; data-emoji-type=&quot;image&quot; aria-label=&quot;:slight_smile:&quot;&gt;&lt;img class=&quot;emoji&quot; src=&quot;https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/standard/caa27a19-fc09-4452-b2b4-a301552fd69c/32x32/1f642.png&quot; alt=&quot;:slight_smile:&quot; width=&quot;20&quot; height=&quot;20&quot; loading=&quot;lazy&quot; data-emoji-short-name=&quot;:slight_smile:&quot; data-emoji-id=&quot;1f642&quot; data-emoji-text=&quot;🙂&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;237&quot;&gt;Este artigo vai ajudar a entender melhor o que é software livre, qual o significado de “Livre” em seu nome, sua relação com código aberto (open source) e o que você pode e não pode fazer com Software Livre.&lt;/p&gt;
&lt;h2 id=&quot;O-que-é-Software-Livre?&quot; data-renderer-start-pos=&quot;400&quot;&gt;O que é Software Livre?&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;425&quot;&gt;A língua portuguesa é muito feliz na tradução do termo de “Free Software” para “Software Livre”, porque o sentido do termo “Free” em &lt;em data-renderer-mark=&quot;true&quot;&gt;free software&lt;/em&gt; não tem nada a ver com preço mas sim com liberdade.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p data-renderer-start-pos=&quot;626&quot;&gt;“Software livre” significa um software que respeite as liberdades e comunidade de seus usuários. Basicamente significa que &lt;strong data-renderer-mark=&quot;true&quot;&gt;seus usuários têm a liberdade de rodar, copiar, distribuir, estudar, modificar e melhorar o software&lt;/strong&gt;. Portanto “software livre” é sobre liberdade, não preço. […]&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;912&quot;&gt;Você pode ter pago dinheiro para obter cópias de um software livre, ou pode ter tido acesso a essas cópias sem pagar nada. Mas independentemente da forma como você conseguiu suas cópias, você sempre terá a liberdade de copiar e modificar o software, e até mesmo de vender outras cópias.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-renderer-start-pos=&quot;1201&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Trecho retirado do texto “&lt;/strong&gt;&lt;a data-testid=&quot;link-with-safety&quot; href=&quot;https://www.gnu.org/philosophy/free-sw.html&quot; title=&quot;https://www.gnu.org/philosophy/free-sw.html&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;What is Free Software?&lt;/strong&gt;&lt;/a&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;” disponível no site &lt;/strong&gt;&lt;a data-testid=&quot;link-with-safety&quot; href=&quot;http://gnu.org&quot; title=&quot;http://gnu.org&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;gnu.org&lt;/strong&gt;&lt;/a&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;, da Free Software Foundation.&lt;/strong&gt;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1309&quot;&gt;Portanto software livre é &lt;em data-renderer-mark=&quot;true&quot;&gt;também&lt;/em&gt; um software de código aberto, mas não apenas isso. É um software que pode ter seus fontes lidos e modificados por qualquer pessoa, e que permita a redistribuição por qualquer pessoa.&lt;/p&gt;
&lt;h2 id=&quot;As-quatro-liberdades-essenciais-do-software-livre&quot; data-renderer-start-pos=&quot;1526&quot;&gt;As quatro liberdades essenciais do software livre&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;1577&quot;&gt;A &lt;a data-testid=&quot;link-with-safety&quot; href=&quot;https://www.fsf.org/&quot; title=&quot;https://www.fsf.org/&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot;&gt;Free Software Foundation&lt;/a&gt; indica que para que um software seja considerado livre, ele deve respeitar quatro liberdades essenciais, são elas:&lt;/p&gt;
&lt;ul class=&quot;ak-ul&quot; data-indent-level=&quot;1&quot;&gt;
&lt;li&gt;
&lt;p data-renderer-start-pos=&quot;1722&quot;&gt;Liberdade 0 - liberdade de rodar o programa como você quiser, por qualquer motivo.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;Liberdade 1 - liberdade de estudar como o programa funciona, e modificá-lo para que faça a computação que você desejar. Ter acesso ao código-fonte é uma pré-condição para esta liberdade.&lt;/li&gt;
&lt;li&gt;Liberdade 2 - liberdade de redistribuir cópias para que você possa ajudar outrem.&lt;/li&gt;
&lt;li&gt;Liberdade 3 - liberdade de distribuir cópias das versões modificadas com outrem. Ao fazer isso você permite que toda a comunidade se beneficie com as suas alterações. Ter acesso ao código fonte é pré-condição para esta liberdade.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-renderer-start-pos=&quot;2316&quot;&gt;Com estas quatro liberdades essenciais fica claro que software livre (&lt;em data-renderer-mark=&quot;true&quot;&gt;free software&lt;/em&gt;) não é sinônimo de software de código aberto (&lt;em data-renderer-mark=&quot;true&quot;&gt;open source software&lt;/em&gt;). Visto que um software puramente de código aberto mas que não possui uma licença &lt;em data-renderer-mark=&quot;true&quot;&gt;livre&lt;/em&gt; pode te proibir de executar alguma das liberdades acima: de redistribuir cópias do original, ou de distribuir modificações por exemplo.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2692&quot;&gt;Mas de toda forma não é possível existir um software livre e que não possua código aberto, porque isto violaria diretamente as liberdades 1 e 3.&lt;/p&gt;
&lt;h2 id=&quot;Licenciamento-de-software-livre&quot; data-renderer-start-pos=&quot;2838&quot;&gt;Licenciamento de software livre&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;2871&quot;&gt;O segredo para entender se o software em questão é livre ou não está em sua licença de uso.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2964&quot;&gt;Softwares que são lançados com licenças como &lt;a data-testid=&quot;link-with-safety&quot; href=&quot;https://www.gnu.org/licenses/gpl-3.0.html&quot; title=&quot;https://www.gnu.org/licenses/gpl-3.0.html&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot;&gt;GNU GPL&lt;/a&gt;, &lt;a data-testid=&quot;link-with-safety&quot; href=&quot;https://www.gnu.org/licenses/agpl-3.0.html&quot; title=&quot;https://www.gnu.org/licenses/agpl-3.0.html&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot;&gt;GNU AGPL&lt;/a&gt;, &lt;a data-testid=&quot;link-with-safety&quot; href=&quot;https://www.gnu.org/licenses/lgpl-3.0.html&quot; title=&quot;https://www.gnu.org/licenses/lgpl-3.0.html&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot;&gt;GNU LGPL&lt;/a&gt;, licenças do tipo Copyleft, domínio público, etc., podem ser considerados livres. Mesmo que tenha sido desenvolvido por uma pessoa ou empresa.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3181&quot;&gt;Também é possível encontrar licenças de código aberto e que não são livres, como a &lt;a data-testid=&quot;link-with-safety&quot; href=&quot;https://directory.fsf.org/wiki/License:JSON&quot; title=&quot;https://directory.fsf.org/wiki/License:JSON&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot;&gt;JSON&lt;/a&gt;, &lt;a data-testid=&quot;link-with-safety&quot; href=&quot;https://directory.fsf.org/wiki/License:Ms-SS&quot; title=&quot;https://directory.fsf.org/wiki/License:Ms-SS&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot;&gt;Ms-SS&lt;/a&gt; da MicroSoft e a &lt;a data-testid=&quot;link-with-safety&quot; href=&quot;https://directory.fsf.org/wiki/License:OPL-1.0&quot; title=&quot;https://directory.fsf.org/wiki/License:OPL-1.0&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot;&gt;Open Public License&lt;/a&gt;. O motivo de não serem livres inclui restrições na redistribuição como proibição de venda ou restrição de uso como “somente para estudantes”.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3456&quot;&gt;Softwares com licenças do tipo Freeware ou Shareware não podem ser considerados livres: na maioria dos casos você não tem acesso aos fontes do software (liberdades 1 e 3) e há restrições de distribuição como proibido vender ou revender (liberdade 2).&lt;/p&gt;
&lt;div class=&quot;ak-editor-panel__content&quot;&gt;
&lt;p class=&quot;msg msg--success&quot; data-renderer-start-pos=&quot;3709&quot;&gt;Qualquer licença que limite o uso, modificação, distribuição e redistribuição do software não pode ser considerada livre.&lt;/p&gt;
&lt;/div&gt;
&lt;h2 id=&quot;A-recomendação-de-licenciamento-da-FSF-para-software-livre&quot; data-renderer-start-pos=&quot;3833&quot;&gt;A recomendação de licenciamento da FSF para software livre&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;3893&quot;&gt;Se você quer desenvolver um software e quer torná-lo livre, a recomendação geral da &lt;em data-renderer-mark=&quot;true&quot;&gt;Free Software Foundation&lt;/em&gt; é de utilizar as licenças compatíveis com a &lt;em data-renderer-mark=&quot;true&quot;&gt;GNU GPL - General Public License&lt;/em&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;4082&quot;&gt;A licença mais utilizada pelo projeto GNU é a &lt;a data-testid=&quot;link-with-safety&quot; href=&quot;https://www.gnu.org/licenses/gpl-3.0.html&quot; title=&quot;https://www.gnu.org/licenses/gpl-3.0.html&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot;&gt;General Public License ou GPL&lt;/a&gt;, considerada uma “licença viral” porque obriga que quaisquer alterações do código fonte sejam também distribuídas com a mesma licença do original. De forma que toda modificação de um software GPL 3.0 precisa ser publicada sob licença GPL 3.0.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;4402&quot;&gt;Por exemplo, se você disponibilizou uma biblioteca chamada &lt;em data-renderer-mark=&quot;true&quot;&gt;libmaravilhosa&lt;/em&gt; via GPL 3.0, qualquer software que utilize esta biblioteca via link estático ou dinâmico, vira um derivado e, portanto, precisa ser distribuído através da licença GPL 3.0.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;4649&quot;&gt;Outra licença que pode ser utilizada, principalmente por bibliotecas, é a &lt;a data-testid=&quot;link-with-safety&quot; href=&quot;https://www.gnu.org/licenses/lgpl-3.0.html&quot; title=&quot;https://www.gnu.org/licenses/lgpl-3.0.html&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot;&gt;licença GNU Lesser GPL ou &lt;strong data-renderer-mark=&quot;true&quot;&gt;LGPL&lt;/strong&gt;&lt;/a&gt; que é um pouco mais permissiva que a GPL 3.0. A LGPL obriga que todo software que incorpore o software licenciado sob LGPL indique a origem e a licença deste software licenciado, e também permita que usuários modifiquem a parte licenciada.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;4995&quot;&gt;Se a biblioteca &lt;em data-renderer-mark=&quot;true&quot;&gt;libmaravilha&lt;/em&gt; estiver sob LGPL 3.0 e o software &lt;em data-renderer-mark=&quot;true&quot;&gt;incrivel.exe&lt;/em&gt; utiliza esta biblioteca, ele precisa indicar que a biblioteca &lt;em data-renderer-mark=&quot;true&quot;&gt;libmaravilha&lt;/em&gt; foi utilizada, que sua licença é a &lt;em data-renderer-mark=&quot;true&quot;&gt;LGPL 3.0&lt;/em&gt; e deve permitir que seus usuários modifiquem a &lt;em data-renderer-mark=&quot;true&quot;&gt;libmaravilhosa&lt;/em&gt;. Portanto se você utilizou link dinâmico (arquivos .so, .dll ou mesmo código fonte) então tudo certo. Mas se você utilizou link estático, que incorpora a biblioteca ao seu binário final, você precisa distribuir seu código com LGPL.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;5485&quot;&gt;Para serviços online (SaaS) também foi criada a &lt;a data-testid=&quot;link-with-safety&quot; href=&quot;https://www.gnu.org/licenses/agpl-3.0.html&quot; title=&quot;https://www.gnu.org/licenses/agpl-3.0.html&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot;&gt;licença GNU Affero GPL ou &lt;strong data-renderer-mark=&quot;true&quot;&gt;AGPL&lt;/strong&gt;&lt;/a&gt;. Caso um serviço do tipo &lt;em data-renderer-mark=&quot;true&quot;&gt;SaaS&lt;/em&gt; utilize software licenciado sobre AGPL, o provedor é obrigado a distribuir sua versão modificada do software.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;5705&quot;&gt;Acesse &lt;a data-testid=&quot;link-with-safety&quot; href=&quot;https://www.gnu.org/licenses/license-list.html#GPLCompatibleLicenses&quot; title=&quot;https://www.gnu.org/licenses/license-list.html#GPLCompatibleLicenses&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot;&gt;lista completa de licenças compatíveis com a GNU GPL&lt;/a&gt; para descobrir mais e mais detalhes sobre cada uma.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;5705&quot;&gt; &lt;/p&gt;</content:encoded><category>principios</category></item><item><title>Como abrir o VIM sem plugins</title><link>https://codamos.com.br/como-abrir-vim-sem-plugins/</link><guid isPermaLink="true">https://codamos.com.br/como-abrir-vim-sem-plugins/</guid><description>Para escrever tutoriais sobre VIM eu preciso sempre garantir que os comandos que eu utilizo funcionariam em qualquer ambiente VIM, independente de configurações e plugins. E para isso é necessário exe</description><pubDate>Fri, 25 Aug 2023 14:30:45 GMT</pubDate><content:encoded>&lt;p data-renderer-start-pos=&quot;4&quot;&gt;Para escrever tutoriais sobre VIM eu preciso sempre garantir que os comandos que eu utilizo funcionariam em qualquer ambiente VIM, independente de configurações e plugins. E para isso é necessário executar o programa ignorando todas as customizações.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;256&quot;&gt;Neste artigo eu vou te mostrar como iniciar o VIM ignorando quaisquer plugins, configurações ou customizações que estejam em seu computador.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;398&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Para abrir o VIM sem plugins ou configurações basta utilizar a &lt;/strong&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;flag&lt;/strong&gt;&lt;/em&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt; &lt;/strong&gt;&lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;--clean&lt;/code&gt; &lt;strong data-renderer-mark=&quot;true&quot;&gt;ao abrir o programa&lt;/strong&gt;, como na linha a seguir:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;398&quot;&gt;$ vim --clean&lt;/pre&gt;
&lt;figure contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image&quot; src=&quot;/media/posts/73/vim-clean.jpg&quot; alt=&quot;Como abrir o VIM sem plugins: vim --clean&quot; width=&quot;960&quot; height=&quot;194&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;css-lmzmsq&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;537&quot;&gt;Como abrir o VIM sem plugins: &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;vim --clean&lt;/code&gt;&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;581&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Para abrir um arquivo com o VIM sem utilizar plugins ou configurações podemos utilizar também a flag &lt;/strong&gt;&lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;--clean&lt;/code&gt;, como na linha de comando abaixo:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;581&quot;&gt;$ vim --clean nomedoarquivo.txt&lt;/pre&gt;
&lt;figure contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image&quot; src=&quot;/media/posts/73/vim-clean-arquivo.jpg&quot; alt=&quot;Como abrir um arquivo no VIM sem plugins: vim --clean nomedoarquivo.txt&quot; width=&quot;960&quot; height=&quot;247&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;css-lmzmsq&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;760&quot;&gt;Como abrir um arquivo no VIM sem plugins: &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;vim --clean nomedoarquivo.txt&lt;/code&gt;&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;O-que-diz-o-manual?&quot; data-renderer-start-pos=&quot;834&quot;&gt;O que diz o manual?&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;855&quot;&gt;O manual oficial do editor VIM indica que a opção &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;--clean&lt;/code&gt; causa o seguinte efeito:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p data-renderer-start-pos=&quot;940&quot;&gt;--clean: Do not use any personal configuration (vimrc, plugins, etc.). Useful to see if problem reproduces with a clean Vim setup.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-renderer-start-pos=&quot;1074&quot;&gt;Em tradução (minha) significa o seguinte:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p data-renderer-start-pos=&quot;1118&quot;&gt;--clean: Não utilizar nenhuma configuração pessoal (vimrc, plugins, etc.). Útil para verificar se um problema pode ser reproduzido com uma configuração limpa do Vim.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-renderer-start-pos=&quot;1285&quot;&gt;Portanto sempre que escrevo artigos sobre VIM é útil a &lt;em data-renderer-mark=&quot;true&quot;&gt;flag&lt;/em&gt; &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;--clean&lt;/code&gt; para que nenhum comportamento seja específico do meu computador e possa funcionar para qualquer pessoa que siga os mesmos passos.&lt;/p&gt;</content:encoded><category>produtividade</category><category>vim</category></item><item><title>8 dicas para quem quer aprender a programar em 2023</title><link>https://codamos.com.br/8-dicas-para-aprender-a-programar-em-2023/</link><guid isPermaLink="true">https://codamos.com.br/8-dicas-para-aprender-a-programar-em-2023/</guid><description>Aprender a programar pode ser uma jornada desafiadora, mas recompensadora. É uma habilidade essencial em um mundo cada vez mais digital e tecnologicamente avançado. Se você está interessado em dar os </description><pubDate>Tue, 01 Aug 2023 20:28:06 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Aprender a programar pode ser uma jornada desafiadora, mas  recompensadora. É uma habilidade essencial em um mundo cada vez mais digital e tecnologicamente avançado.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Se você está interessado em dar os primeiros passos no mundo da programação, este pequeno artigo lhe dará algumas dicas sobre como começar e como superar problemas que você possa encontrar ao longo do caminho. &lt;/span&gt;&lt;/p&gt;
&lt;h2 class=&quot;p1&quot;&gt;1 – Selecione a linguagem de programação&lt;/h2&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Um dos primeiros desafios para iniciantes é decidir qual linguagem de programação aprender. Existem várias opções como &lt;a href=&quot;/tema/php/&quot;&gt;PHP&lt;/a&gt;, Python, Java, &lt;a href=&quot;/tema/javascript/&quot;&gt;JavaScript&lt;/a&gt;, &lt;a href=&quot;/tema/c/&quot;&gt;C&lt;/a&gt;, etc, e para conseguir escolher qual caminho seguir considere seus objetivos e interesses.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Por exemplo, Python é uma linguagem popular para iniciantes devido à sua simplicidade e ampla aplicabilidade. &lt;/span&gt;&lt;/p&gt;
&lt;h2 class=&quot;p1&quot;&gt;2 – Encontre recursos de aprendizado&lt;/h2&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Existem muitos recursos disponíveis para aprender programação, como livros, tutoriais em vídeo, cursos online e plataformas interativas, e acredite, a quantidade de informações pode ser esmagadora. &lt;/span&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Pensando nisso, você pode escolher recursos de aprendizagem adequados ao seu estilo e que permitam a passagem gradual do nível básico ao avançado.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Para tornar a jornada do aprendizado mais divertida e eficiente, a dica é encontrar recursos que combinem com o seu estilo. &lt;/span&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Aqui não existe uma fórmula mágica única! Você pode escolher os materiais que melhor se adaptam às suas preferências e ritmo de aprendizagem.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;No site da Codamos tem &lt;a href=&quot;/aprender-a-programar-online-de-graca-em-2023/&quot;&gt;um guia que começa pelo entendimento da mecânica da linguagem (sintaxe)&lt;/a&gt;. É como aprender a linguagem nativa dos computadores!&lt;/span&gt;&lt;/p&gt;
&lt;h2 class=&quot;p1&quot;&gt;3 – Entenda os conceitos básicos&lt;/h2&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Conceitos como variáveis, loops, condições e funções são essenciais em qualquer linguagem de programação. Esse conceito pode parecer difícil de entender a princípio, mas  a chave para superar essa dificuldade é a prática.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Comece com pequenos exercícios e projetos simples para colocar esses conceitos em prática. &lt;/span&gt;&lt;/p&gt;
&lt;h2 class=&quot;p1&quot;&gt;4 – Como lidar com a decepção&lt;/h2&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;A programação pode ser difícil e as falhas ao longo do caminho são comuns – e tá tudo bem 😉. Ficar preso em um problema por horas pode ser frustrante, mas é importante lembrar que a solução de problemas é uma parte essencial da programação.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Não tenha medo de procurar ajuda em &lt;a href=&quot;/comunidades-de-desenvolvimento-de-software-brasileiras/&quot;&gt;comunidades de programadores online ou fóruns especializados&lt;/a&gt;. &lt;/span&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Profissionais de software de todos os níveis têm muito a ganhar ao participar de comunidades: iniciantes ganham exposição a ideias e discussões de alto nível, enquanto pessoas mais experientes trocam entre si e ganham experiência como mentoras.&lt;/span&gt;&lt;/p&gt;
&lt;h2 class=&quot;p1&quot;&gt;5 – Exercite-se regularmente&lt;/h2&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Consistência é a chave para aprender a programar. Reserve um tempo  para praticar e codificar regularmente, mesmo que  por um curto período de tempo todos os dias.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;A prática contínua reforça os conceitos aprendidos e ajuda a desenvolver habilidades de resolução de problemas. Uma dica legal é o site da &lt;a href=&quot;https://www.freecodecamp.org/&quot; rel=&quot;nofollow&quot;&gt;FreeCodeCamp&lt;/a&gt; onde são apresentados desafios curtinhos  com explicação a cada passo.&lt;/span&gt;&lt;/p&gt;
&lt;h2 class=&quot;p1&quot;&gt;6 – Crie seu projeto pessoal&lt;/h2&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Além de se exercitar e treinar, é importante trabalhar em projetos pessoais. Criar algo com o qual você se preocupa torna o aprendizado mais motivador e divertido, e para começar não precisa ser nada muito mirabolante.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Comece com projetos simples e aumente a complexidade à medida que ganhar confiança. Quer ver um projeto bacana para quem está iniciando? Confere este video aqui:&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/SjtdH3dWLa8&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;allowfullscreen&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;h2 class=&quot;p1&quot;&gt;7 – Colabore com outros programadores&lt;/h2&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Participar de uma comunidade de desenvolvimento ou colaborar com outras pessoas em um projeto pode ser uma experiência inestimável. Além de aprender com os outros, você  pode obter feedback e insights que o ajudarão a melhorar suas habilidades.  E se eu puder aqui puxar a brasa para a minha sardinha, recomendo fortemente as comunidades da &lt;a href=&quot;https://t.me/codamos_forum&quot;&gt;Codamos&lt;/a&gt; e o &lt;a href=&quot;https://phpsp.org.br&quot; rel=&quot;nofollow&quot;&gt;PHPSP&lt;/a&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Para descobrir diferentes comunidades você pode dar uma olhada neste artigo que tem uma lista bem bacana de &lt;a href=&quot;/comunidades-de-desenvolvimento-de-software-brasileiras/&quot;&gt;comunidades de programação brasileiras&lt;/a&gt;.&lt;/p&gt;
&lt;h2 class=&quot;p1&quot;&gt;8 – Adaptação às novas tecnologias&lt;/h2&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;O universo da programação está em constante evolução e novas tecnologias e tendências aparecem todos os dias. Esteja preparado para aprender coisas novas e acompanhar as mudanças para superar esses desafios. &lt;/span&gt;&lt;/p&gt;
&lt;h2 class=&quot;p1&quot;&gt;Minha conclusão?&lt;/h2&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Começar a programar pode ter alguns desafios, mas é uma habilidade valiosa e gratificante. Escolher a linguagem que mais atende suas expectativas, encontrar bons materiais de estudo, praticar regularmente, frustrar-se (e é sim importante, faz parte do crescimento) e trabalhar em projetos pessoais são algumas das estratégias para vencer os obstáculos nessa jornada.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Lembre-se: a chave para o sucesso está na persistência e no equilíbrio entre teoria e prática. Prepare-se para desbravar novos horizontes e descobrir todo o potencial que a programação oferece.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Boa sorte e divirta-se nessa jornada!&lt;/span&gt;&lt;/p&gt;</content:encoded><category>carreira</category><category>junior</category></item><item><title>Linguagem C – Como escrever callbacks?</title><link>https://codamos.com.br/linguagem-c-como-escrever-callbacks/</link><guid isPermaLink="true">https://codamos.com.br/linguagem-c-como-escrever-callbacks/</guid><description>De algumas décadas pra cá se popularizou a utilização de callbacks , funções que são referenciadas por outras funções e executadas de forma não deterministica – principalmente por causa do paradigma a</description><pubDate>Mon, 03 Jul 2023 11:16:36 GMT</pubDate><content:encoded>&lt;p data-renderer-start-pos=&quot;4&quot;&gt;De algumas décadas pra cá se popularizou a utilização de &lt;em data-renderer-mark=&quot;true&quot;&gt;callbacks&lt;/em&gt;, funções que são referenciadas por outras funções e executadas de forma não deterministica – principalmente por causa do paradigma assíncrono de programação.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;230&quot;&gt;A linguagem C já oferece suporte a callbacks há muito tempo, mas sua utilização não é parecida com linguagens mais populares como o JavaScript ou PHP. &lt;em data-renderer-mark=&quot;true&quot;&gt;Callbacks&lt;/em&gt; em C precisam ter tipos definidos em tempo de compilação e são tratados como ponteiros. Vem comigo que eu te explico!&lt;/p&gt;
&lt;h2 id=&quot;Exemplo-de-callback-e-utilização-de-callbacks-em-C&quot; data-renderer-start-pos=&quot;510&quot;&gt;Exemplo de callback e utilização de callbacks em C&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;562&quot;&gt;Se você não quiser entender como tudo funciona e quiser pular para a solução, aqui está!&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;562&quot;&gt;// Define a assinatura do callback&lt;br&gt;typedef void (*hello_t)(const char *name);&lt;br&gt;&lt;br&gt;// Implementação que será utilizada como callback&lt;br&gt;void say_hello(const char *name)&lt;br&gt;{&lt;br&gt;    printf(&quot;Olá, %s!\n&quot;, name);&lt;br&gt;}&lt;br&gt;&lt;br&gt;int main(void)&lt;br&gt;{&lt;br&gt;    // Variável que armazena o callback&lt;br&gt;    hello_t callback = say_hello;&lt;br&gt;    &lt;br&gt;    // Como chamar o callback&lt;br&gt;    callback(&quot;codamos.com.br&quot;); // equivalente a say_hello(&quot;codamos.com.br&quot;)&lt;br&gt;&lt;br&gt;    return 0;&lt;br&gt;}&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;1072&quot;&gt;Para entender bem o que está acontecendo no exemplo acima, continue lendo que eu te explico 😉&lt;/p&gt;
&lt;h2 id=&quot;Como-definir-um-callback-em-C?&quot; data-renderer-start-pos=&quot;1168&quot;&gt;Como definir um callback em C?&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;1200&quot;&gt;Antes de entender como escrever um &lt;em data-renderer-mark=&quot;true&quot;&gt;callback&lt;/em&gt; em C, você precisa entender como funcionam ponteiros em C. Sugiro a leitura do &lt;a href=&quot;https://www.inf.pucrs.br/~pinho/PRGSWB/Ponteiros/ponteiros.html&quot; title=&quot;https://www.inf.pucrs.br/~pinho/PRGSWB/Ponteiros/ponteiros.html&quot; rel=&quot;nofollow&quot;&gt;material de aula do professor Márcio Sarroglia Pinho (PUCRS) sobre ponteiros&lt;/a&gt;, após ler este material você provavelmente vai entender bem como ponteiros funcionam!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1487&quot;&gt;Ponteiros em C apenas referenciam um endereço na memória. Então se todo o nosso código é carregado em memória provavelmente poderíamos referenciar uma função, certo? Corretíssimo! E é assim que podemos trabalhar com callbacks. Vejamos o exemplo abaixo:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;1487&quot;&gt;void say_hello(void)&lt;br&gt;{&lt;br&gt;  // ...&lt;br&gt;}&lt;br&gt;&lt;br&gt;int main(void)&lt;br&gt;{&lt;br&gt;  void *callback = say_hello;&lt;br&gt;  // callback agora aponta para o endereço de (void say_hello(void))&lt;br&gt;&lt;br&gt;  return 0;&lt;br&gt;}&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;1908&quot;&gt;No exemplo acima a variável &lt;em data-renderer-mark=&quot;true&quot;&gt;callback&lt;/em&gt; é definida como &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;*callback&lt;/code&gt;, que é como definimos um ponteiro. O tipo deste ponteiro é &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;void&lt;/code&gt;, o que significa dizer que a linguagem C não precisa saber nada sobre &lt;em data-renderer-mark=&quot;true&quot;&gt;o que&lt;/em&gt; está contido naquele endereço de memória.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2154&quot;&gt;Porém não é possível executar a função &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;say_hello()&lt;/code&gt; através da variável &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;callback&lt;/code&gt; sem indicar ao compilador com quais tipos estamos lidando. A forma mais clara de indicar os tipos é através da estrutura &lt;a href=&quot;https://www.inf.pucrs.br/~flash/lapro2ec/cppreference/w/cpp/language/typedef.html&quot; title=&quot;https://www.inf.pucrs.br/~flash/lapro2ec/cppreference/w/cpp/language/typedef.html&quot; rel=&quot;nofollow&quot;&gt;typedef&lt;/a&gt;, como a seguir:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;2154&quot;&gt;// Define um tipo &quot;callback_t&quot; que é uma função&lt;br&gt;typedef void (*callback_t)(void);&lt;br&gt;&lt;br&gt;void say_hello(void)&lt;br&gt;{&lt;br&gt;  // ...&lt;br&gt;}&lt;br&gt;&lt;br&gt;int main(void)&lt;br&gt;{&lt;br&gt;  callback_t callback = say_hello;&lt;br&gt;  &lt;br&gt;  callback();&lt;br&gt;  return 0;&lt;br&gt;}&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;2582&quot;&gt;No exemplo acima nós definimos um tipo chamado &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;callback_t&lt;/code&gt; que é um ponteiro de função. Este ponteiro indica que a função retorna &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;void&lt;/code&gt; e que não possui parâmetro algum.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2751&quot;&gt;Supondo que a função &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;say_hello()&lt;/code&gt; recebesse um parâmetro do tipo string, poderíamos mudar o código para o seguinte:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;2751&quot;&gt;// Define um tipo &quot;callback_t&quot; que é uma função&lt;br&gt;typedef void (*callback_t)(const char *name);&lt;br&gt;&lt;br&gt;void say_hello(const char *name)&lt;br&gt;{&lt;br&gt;  // ...&lt;br&gt;}&lt;br&gt;&lt;br&gt;int main(void)&lt;br&gt;{&lt;br&gt;  callback_t callback = say_hello;&lt;br&gt;  &lt;br&gt;  callback(&quot;codamos.com.br&quot;);&lt;br&gt;  return 0;&lt;br&gt;}&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;3109&quot;&gt;Repare como a definição do tipo &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;callback_t&lt;/code&gt; precisou se adaptar para receber &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;const char *name&lt;/code&gt; como parâmetro. Do contrário a chamada &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;callback(&quot;codamos.com.br&quot;)&lt;/code&gt; geraria um erro.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3286&quot;&gt;Portanto para definir um callback você pode utilizar a sintaxe abaixo:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;3286&quot;&gt;typedef &amp;lt;tipo_de_retorno&amp;gt; (*nome_do_callback)(&amp;lt;tipo&amp;gt; param1, &amp;lt;tipo&amp;gt; param2, ...);&lt;/pre&gt;
&lt;h2 id=&quot;Como-passar-e-receber-um-callback-por-parâmetro-em-C?&quot; data-renderer-start-pos=&quot;3441&quot;&gt;Como passar e receber um callback por parâmetro em C?&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;3496&quot;&gt;Receber um &lt;em data-renderer-mark=&quot;true&quot;&gt;callback&lt;/em&gt; por parâmetro pode ser feito de duas formas diferentes: através da definição de tipos (&lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;typedef&lt;/code&gt;) ou através de uma definição na assinatura da função.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3666&quot;&gt;Para receber um &lt;em data-renderer-mark=&quot;true&quot;&gt;callback&lt;/em&gt; via parâmetro utilizando a sua definição &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;typedef&lt;/code&gt; basta referenciar o tipo, como no exemplo abaixo:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;3666&quot;&gt;typedef void (*callback_t)(const char *name);&lt;br&gt;&lt;br&gt;void run_callback(callback_t callback)&lt;br&gt;{&lt;br&gt;  callback(&quot;codamos.com.br&quot;);&lt;br&gt;}&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;3912&quot;&gt;Você também pode descrever a assinatura do callback na assinatura da função, sem utilizar &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;typedef&lt;/code&gt; como no exemplo abaixo:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;3912&quot;&gt;void run_callback(void (*callback)(const char *name))&lt;br&gt;{&lt;br&gt;  callback(&quot;codamos.com.br&quot;);&lt;br&gt;}&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;4124&quot;&gt;A segunda opção, apesar de não definir um novo tipo, é muito mais difícil de ler. Portanto eu não recomendo a sua utilização.&lt;/p&gt;
&lt;h2 id=&quot;Quando-utilizar-um-callback-em-C?&quot; data-renderer-start-pos=&quot;4251&quot;&gt;Quando utilizar um callback em C?&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;4286&quot;&gt;Callbacks podem ser utilizados em diferentes situações, abaixo vou listar apenas algumas delas.&lt;/p&gt;
&lt;h3 id=&quot;Programação-assíncrona&quot; data-renderer-start-pos=&quot;4383&quot;&gt;Programação assíncrona&lt;/h3&gt;
&lt;p data-renderer-start-pos=&quot;4407&quot;&gt;O estilo assíncrono de programação, que ficou popular com a utilização de JavaScript em ambientes de navegador e também no NodeJS, depende da utilização de &lt;em data-renderer-mark=&quot;true&quot;&gt;callbacks&lt;/em&gt; para delegar a execução de funções para um futuro indeterminado.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;4639&quot;&gt;Por exemplo, &lt;strong data-renderer-mark=&quot;true&quot;&gt;a implementação do &lt;/strong&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Event Loop&lt;/strong&gt;&lt;/em&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt; utilizado pelo NodeJS depende da biblioteca &lt;/strong&gt;&lt;a href=&quot;https://libuv.org/&quot; title=&quot;https://libuv.org/&quot; rel=&quot;nofollow&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;libuv&lt;/strong&gt;&lt;/a&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt; escrita em C/C++&lt;/strong&gt;. Esta implementação permite realizar operações de entrada e saída como ler o disco rígido ou realizar escritas ou leituras por rede de forma não bloqueante e organizar o fluxo de execução através de &lt;em data-renderer-mark=&quot;true&quot;&gt;callbacks&lt;/em&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;4960&quot;&gt;Um outro exemplo de programação assíncrona que utiliza &lt;em data-renderer-mark=&quot;true&quot;&gt;callbacks&lt;/em&gt; em C é o &lt;em data-renderer-mark=&quot;true&quot;&gt;multithreading&lt;/em&gt;, a capacidade de executar mais de um (sub) processo ao mesmo tempo. Em C uma implementação muito conhecida é a da biblioteca &lt;a href=&quot;https://www.cs.cmu.edu/afs/cs/academic/class/15492-f07/www/pthreads.html&quot; title=&quot;https://www.cs.cmu.edu/afs/cs/academic/class/15492-f07/www/pthreads.html&quot; rel=&quot;nofollow&quot;&gt;pthreads&lt;/a&gt; que recebe um &lt;em data-renderer-mark=&quot;true&quot;&gt;callback&lt;/em&gt; como parâmetro da função &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;pthread_create()&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;Programação-de-rede-e-IoT&quot; data-renderer-start-pos=&quot;5250&quot;&gt;Programação de rede e IoT&lt;/h3&gt;
&lt;p&gt;Normalmente utilizamos &lt;em data-renderer-mark=&quot;true&quot;&gt;callbacks&lt;/em&gt; sempre que precisamos delegar uma tarefa a outro processo: uma thread, o sistema operacional ou mesmo um evento externo. É muito comum, por exemplo, utilizar &lt;em data-renderer-mark=&quot;true&quot;&gt;callbacks&lt;/em&gt; para tratar eventos de rede ou de sensores. Veja o exemplo (não realista) abaixo:&lt;/p&gt;
&lt;pre&gt;void handle_message(connection_t conn, const char *msg, size_t len);&lt;br&gt;&lt;br&gt;void on_connect_callback(connection_t conn)&lt;br&gt;{&lt;br&gt;  on_message(conn, handle_message);&lt;br&gt;}&lt;br&gt;&lt;br&gt;socket_t socket = bind_socket(&quot;0.0.0.0&quot;, 8080);&lt;br&gt;on_connect(socket, on_connect_callback);&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;5807&quot;&gt;No exemplo acima nós abrimos um socket que permite que diferentes computadores se conectem a este programa através da porta 8080. A cada nova conexão o programa irá chamar a função &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;on_connect_callback()&lt;/code&gt;. E nesta função registramos também outro callback, o &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;handle_message()&lt;/code&gt;, que deverá ser chamado a cada vez que aquela conexão enviar algum pacote de rede para o nosso programa.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;6186&quot;&gt;Como são ações externas nós não podemos controlá-las e, portanto, o &lt;em data-renderer-mark=&quot;true&quot;&gt;callback&lt;/em&gt; é justamente uma ferramenta para organizar o fluxo do nosso código em situações assíncronas em que não controlamos o fluxo da aplicação.&lt;/p&gt;
&lt;h3 id=&quot;Para-trabalhar-com-eventos&quot; data-renderer-start-pos=&quot;6401&quot;&gt;Para trabalhar com eventos&lt;/h3&gt;
&lt;p data-renderer-start-pos=&quot;6429&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;Callbacks&lt;/em&gt; não precisam ser utilizados apenas em situações em que trabalhamos com redes, disco ou sensores de forma assíncrona e/ou não-bloqueante.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;6577&quot;&gt;Em muitos casos a utilização de eventos nos ajuda a organizar o nosso código melhor. Por exemplo, no código abaixo nós lemos eventos de um arquivo de texto e executamos seus respectivos &lt;em data-renderer-mark=&quot;true&quot;&gt;callbacks&lt;/em&gt;:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;6577&quot;&gt;typedef void (*callback_t)(void);&lt;br&gt;&lt;br&gt;void replay_events(callback_t user_created, callback_t user_updated)&lt;br&gt;// Ler eventos a partir de um arquivo de texto&lt;br&gt;int events[];&lt;br&gt;int total_events;&lt;br&gt;&lt;br&gt;for (int i = 0; i &amp;lt; total_events; ++i) {&lt;br&gt;  switch (events[i]) {&lt;br&gt;    case EV_USER_CREATED:&lt;br&gt;      user_created();&lt;br&gt;      break;&lt;br&gt;    case EV_USER_UPDATED:&lt;br&gt;      user_updated();&lt;br&gt;      break;&lt;br&gt;    // ...&lt;br&gt;  }&lt;br&gt;}&lt;/pre&gt;
&lt;p&gt;Da mesma forma como passamos cada &lt;em data-renderer-mark=&quot;true&quot;&gt;callback&lt;/em&gt; via parâmetro, poderíamos tê-los passado via &lt;a href=&quot;https://wiki.sj.ifsc.edu.br/index.php/PRG29003:_Introdu%C3%A7%C3%A3o_a_Tabelas_Hash&quot; title=&quot;https://wiki.sj.ifsc.edu.br/index.php/PRG29003:_Introdu%C3%A7%C3%A3o_a_Tabelas_Hash&quot; rel=&quot;nofollow&quot;&gt;HashMap&lt;/a&gt;, que é uma estrutura muito mais dinâmica e nos permitiria registrar diversos callbacks para diferentes eventos.&lt;/p&gt;
&lt;h2 id=&quot;Conclusão&quot; data-renderer-start-pos=&quot;7372&quot;&gt;Conclusão&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;7383&quot;&gt;Neste artigo vimos como e quando implementar um &lt;em data-renderer-mark=&quot;true&quot;&gt;callback&lt;/em&gt; utilizando a linguagem C, quais suas utilidades e diferentes casos de uso. Também vimos por cima alguns conceitos importantes como os de programação assíncrona e ponteiros.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;7383&quot;&gt;Não deixe de compartilhar com seus colegas e seguidores caso tenha gostado deste artigo ou ache que pode ser útil para outras pessoas.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;7750&quot;&gt;Até a próxima! 👋&lt;/p&gt;</content:encoded><category>c</category></item><item><title>Como configurar o usuário e email do git em sua máquina</title><link>https://codamos.com.br/como-configurar-usuario-email-git/</link><guid isPermaLink="true">https://codamos.com.br/como-configurar-usuario-email-git/</guid><description>É muito comum, quando a gente começa a trabalhar com GIT, de não entendermos alguns conceitos simples. Coisas que a gente precisa configurar uma única vez na vida e nunca mais vê. E aí quando formatam</description><pubDate>Thu, 08 Jun 2023 07:07:49 GMT</pubDate><content:encoded>&lt;p data-renderer-start-pos=&quot;4&quot;&gt;É muito comum, quando a gente começa a trabalhar com GIT, de não entendermos alguns conceitos simples. Coisas que a gente precisa configurar uma única vez na vida e nunca mais vê. E aí quando formatamos o computador ou trocamos de equipamento essas dúvidas sempre voltam.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;277&quot;&gt;Uma dúvida comum que eu tinha quando estava iniciando e que recebo várias vezes por mês de pessoas que eu acompanho os estudos, é &lt;strong data-renderer-mark=&quot;true&quot;&gt;“Por que quando eu subo arquivos no github a minha foto não aparece na lista de commits?”&lt;/strong&gt; – e isto acontece porque na hora de fazer o &lt;em data-renderer-mark=&quot;true&quot;&gt;commit&lt;/em&gt; o seu usuário e email não estavam configurados e portanto a assinatura não saiu como o esperado.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;277&quot;&gt;Neste artigo vamos ver exatamente como configurar seu usuário e e-mail do GIT em sua máquina local para corrigir as assinaturas de seus &lt;em&gt;commits.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;Por-que-minha-foto-não-aparece-nos-commits-do-Github-ou-Gitlab?&quot; data-renderer-start-pos=&quot;597&quot;&gt;Por que minha foto não aparece nos commits do Github ou Gitlab?&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;662&quot;&gt;Porque o GIT em sua máquina não está configurado com o mesmo e-mail do seu perfil no Github ou Gitlab.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;766&quot;&gt;Sempre que nós fazemos um &lt;em data-renderer-mark=&quot;true&quot;&gt;commit&lt;/em&gt;, como explicamos no artigo &lt;a href=&quot;/subindo-arquivos-no-github/&quot;&gt;como subir arquivos pro seu projeto no Github&lt;/a&gt;, a ferramenta GIT não apenas armazena as alterações como assina com o seu usuário atual. Veja na imagem abaixo uma assinatura de commit:&lt;/p&gt;
&lt;figure contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image&quot; src=&quot;/media/posts/70/git-log-assinatura-commit.png&quot; alt=&quot;git log mostrando o dado “Author: Nawarian &amp;lt;nickolas@phpsp.org.br&amp;gt;”&quot; width=&quot;581&quot; height=&quot;153&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;css-lmzmsq&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;969&quot;&gt;&lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;git log&lt;/code&gt; mostrando o dado “Author: Nawarian &amp;lt;nickolas@phpsp.org.br&amp;gt;”&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;div class=&quot;ak-editor-panel__content&quot;&gt;
&lt;p class=&quot;msg msg--success&quot; data-renderer-start-pos=&quot;1040&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Esta assinatura é o que permite o Github ou Gitlab de compreenderem qual foto mostrar.&lt;/strong&gt; Se o seu e-mail estiver na plataforma deles, a sua foto aparecerá.&lt;/p&gt;
&lt;/div&gt;
&lt;p data-renderer-start-pos=&quot;1196&quot;&gt;Portanto para a sua foto aparecer na lista de &lt;em data-renderer-mark=&quot;true&quot;&gt;commits&lt;/em&gt; dessas plataformas, é importante configurar o seu nome de usuário e e-mail corretamente.&lt;/p&gt;
&lt;h2 id=&quot;Como-configurar-usuário-e-e-mail-do-GIT&quot; data-renderer-start-pos=&quot;1340&quot;&gt;Como configurar usuário e e-mail do GIT&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;1381&quot;&gt;O usuário e e-mail associado ao git podem ser configurados para todos seus projetos de uma única vez utilizando o comando &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;git config&lt;/code&gt; e passando a &lt;em data-renderer-mark=&quot;true&quot;&gt;flag&lt;/em&gt; &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;--global&lt;/code&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1381&quot;&gt;Para definir o seu e-mail de assinatura GIT, rode o comando abaixo:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;1381&quot;&gt;$ git config --global user.email &quot;seuemail@codamos.com.br&quot;&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;1672&quot;&gt;Desta forma todos os &lt;em data-renderer-mark=&quot;true&quot;&gt;commits&lt;/em&gt; que vocie escrever daqui em diante serão assinados com o e-mail “seuemail@codamos.com.br”. De forma semelhante, podemos alterar o nome de usuário GIT da seguinte maneira:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;1672&quot;&gt;$ git config --global user.name &quot;seuusuario&quot;&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;1919&quot;&gt;Você pode verificar que as suas configurações tomaram efeito rodando o mesmo comando com a flag &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;--list&lt;/code&gt;:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;1919&quot;&gt;$ git config --list&lt;br&gt;...&lt;br&gt;user.email=seuemail@codamos.com.br&lt;br&gt;user.name=seuusario&lt;/pre&gt;
&lt;figure contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image&quot; src=&quot;/media/posts/70/git-config-list-exemplo.png&quot; alt=&quot;Ilustração dos comandos git config e a listagem das configurações&quot; width=&quot;875&quot; height=&quot;262&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;css-lmzmsq&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;2106&quot;&gt;Ilustração dos comandos &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;git config&lt;/code&gt; e a listagem das configurações&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;Como-configurar-um-usuário-e-e-mail-diferente-para-um-repositório-específico&quot; data-renderer-start-pos=&quot;2174&quot;&gt;Como configurar um usuário e e-mail diferente para um repositório específico&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;2252&quot;&gt;Pode acontecer de num mesmo computador você precisar utilizar duas contas de GIT diferentes. Por exemplo, caso você utilize o mesmo computador para trabalho e para projetos pessoais. Ou caso preste consultoria a diferentes empresas.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2486&quot;&gt;Além de definir a configuração global do GIT com o comando &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;git config --global&lt;/code&gt;, que se aplica a todos os repositórios GIT em seu computador, é possível alterar configurações apenas para o projeto atual através da flag &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;--local&lt;/code&gt;:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;2486&quot;&gt;$ git config --local user.email &quot;seuoutroemail@codamos.com.br&quot;&lt;br&gt;$ git config --local user.name &quot;seuoutrousuario&quot;&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;2827&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Os comandos acima apenas funcionarão se o seu diretório atual for um repositório GIT.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;Conclusão&quot; data-renderer-start-pos=&quot;2914&quot;&gt;Conclusão&lt;/h2&gt;
&lt;p&gt;A gente viu como alterar seu usuário e e-mail de assinatura de &lt;em data-renderer-mark=&quot;true&quot;&gt;commits &lt;/em&gt;do GIT através do comando &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;git config&lt;/code&gt;. Com isso você vai poder resolver seu problema de identificação de &lt;em data-renderer-mark=&quot;true&quot;&gt;commits&lt;/em&gt; mais facilmente.&lt;/p&gt;
&lt;p&gt;Se você já fez um &lt;em data-renderer-mark=&quot;true&quot;&gt;commit&lt;/em&gt; que não estava assinado corretamente e quer corrigí-lo, dê uma olhada neste outro artigo sobre &lt;a href=&quot;/git-renomear-mensagens-commit-repositorio/&quot;&gt;como renomear mensagens de commit em um repositório&lt;/a&gt; para ter uma outra chance de assinar aqueles &lt;em data-renderer-mark=&quot;true&quot;&gt;commits&lt;/em&gt;.&lt;/p&gt;</content:encoded><category>git</category><category>ferramentas</category></item><item><title>Como redefinir a senha de root no MySQL e no MariaDB</title><link>https://codamos.com.br/como-redefinir-a-senha-de-root-mysql-mariadb/</link><guid isPermaLink="true">https://codamos.com.br/como-redefinir-a-senha-de-root-mysql-mariadb/</guid><description>As vezes é necessário redefinir a senha do usuário root da base de dados MySQL. Seja para retomar controle de um banco ou mesmo para trabalhar com backups. Neste artigo rápido eu vou te mostrar como p</description><pubDate>Sun, 21 May 2023 08:35:34 GMT</pubDate><content:encoded>&lt;p data-renderer-start-pos=&quot;1&quot;&gt;As vezes é necessário redefinir a senha do usuário &lt;em data-renderer-mark=&quot;true&quot;&gt;root&lt;/em&gt; da base de dados MySQL. Seja para retomar controle de um banco ou mesmo para trabalhar com backups. Neste artigo rápido eu vou te mostrar como proceder para redefinir a senha de root.&lt;/p&gt;
&lt;h2 id=&quot;1.-Reiniciar-o-servidor-no-modo-de-segurança&quot; data-renderer-start-pos=&quot;243&quot;&gt;1. Reiniciar o servidor no modo de segurança&lt;/h2&gt;
&lt;p&gt;Primeiramente nós precisamos interromper o servidor MySQL para podemos entrar em &lt;em data-renderer-mark=&quot;true&quot;&gt;modo de segurança&lt;/em&gt;. &lt;strong data-renderer-mark=&quot;true&quot;&gt;O modo de segurança do &lt;/strong&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;MySQL&lt;/strong&gt;&lt;/em&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt; vai nos permitir acessar o banco de dados sem nenhuma senha e com todas as permissões que precisamos para realizar quaisquer alterações&lt;/strong&gt;.&lt;/p&gt;
&lt;div class=&quot;ak-editor-panel__content&quot;&gt;
&lt;p class=&quot;msg msg--highlight &quot; data-renderer-start-pos=&quot;551&quot;&gt;🚨 Não rode o servidor em modo de segurança em produção. Qualquer usuário que realizar login no seu servidor terá acesso irrestrito a base de dados!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;699&quot;&gt;Vamos primeiro interromper o serviço &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;mysql&lt;/code&gt;:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;699&quot;&gt;$ sudo service mysql stop&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;771&quot;&gt;O comando acima assume que seu servidor utiliza &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;service&lt;/code&gt;, outras variações podem incluir &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;systemctl&lt;/code&gt; ou &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;init&lt;/code&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;879&quot;&gt;Após interromper o serviço &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;mysql&lt;/code&gt; podemos inicializar o mesmo serviço, mas desta vez utilizando o daemon &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;mysqld_safe&lt;/code&gt;, da seguinte maneira:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;879&quot;&gt;$ sudo mysqld_safe --skip-grant-tables &amp;amp;&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;1060&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;A mágica acontece na flag &lt;/strong&gt;&lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;--skip-grant-tables&lt;/code&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt; que nos permite fazer login e alterar qualquer coisa no servidor sem verificar permissões&lt;/strong&gt;. O &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;&amp;amp;&lt;/code&gt; ao fim do comando coloca este &lt;em data-renderer-mark=&quot;true&quot;&gt;daemon&lt;/em&gt; para rodar em plano de fundo, desta forma nós conseguimos continuar utilizando o mesmo terminal para seguir os próximos passos.&lt;/p&gt;
&lt;h2 id=&quot;2.-Alterar-senha-de-root&quot; data-renderer-start-pos=&quot;1367&quot;&gt;2. Alterar senha de &lt;em data-renderer-mark=&quot;true&quot;&gt;root&lt;/em&gt;&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;1393&quot;&gt;Agora que o &lt;em data-renderer-mark=&quot;true&quot;&gt;MySQL&lt;/em&gt; está rodando em modo de segurança e sem verificar permissões, podemos facilmente realizar o login via linha de comando da seguinte maneira:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;1393&quot;&gt;$ mysql -uroot&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;1568&quot;&gt;O sistema sequer vai lhe pedir uma senha. A partir daqui estamos no console do &lt;em data-renderer-mark=&quot;true&quot;&gt;MySQL &lt;/em&gt;e podemos rodar quaisquer comandos SQL ou comandos específicos do &lt;em data-renderer-mark=&quot;true&quot;&gt;MySQL&lt;/em&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1727&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Para alterar a senha do usuário root vamos rodar o comando &lt;/strong&gt;&lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;ALTER USER&lt;/code&gt; como descrito abaixo:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;1727&quot;&gt;mysql&amp;gt; FLUSH PRIVILEGES;&lt;br&gt;mysql&amp;gt; ALTER USER &apos;root&apos;@&apos;localhost&apos; IDENTIFIED BY &apos;NOVA SENHA ROOT&apos;;&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;1916&quot;&gt;O &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;FLUSH PRIVILEGES&lt;/code&gt; recarrega as tabelas de permissões — passo necessário no MySQL 5.7+/8.0, que de outra forma recusaria o &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;ALTER USER&lt;/code&gt; enquanto o servidor roda com &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;--skip-grant-tables&lt;/code&gt;. Em seguida, o comando &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;ALTER USER&lt;/code&gt; modifica a senha do usuário &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;root&lt;/code&gt; para &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;NOVA SENHA ROOT&lt;/code&gt; (altere o comando para utilizar a senha desejada). Este comando também especifica que o usuário &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;root&lt;/code&gt; só pode acessar o banco de dados quando na mesma máquina que o servidor (&lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;localhost&lt;/code&gt;). Portanto não é possível acessar este banco como &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;root&lt;/code&gt; a partir de uma outra máquina.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2273&quot;&gt;O segundo comando, &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;FLUSH PRIVILEGES&lt;/code&gt;, ordena que o &lt;em data-renderer-mark=&quot;true&quot;&gt;MySQL&lt;/em&gt; reavalie sua cadeia de usuários e permissões imediatamente.&lt;/p&gt;
&lt;h2 id=&quot;3.-Reiniciar-o-servidor-MySQL-em-modo-normal&quot; data-renderer-start-pos=&quot;2390&quot;&gt;3. Reiniciar o servidor &lt;em data-renderer-mark=&quot;true&quot;&gt;MySQL&lt;/em&gt; em modo normal&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;2436&quot;&gt;Agora que terminamos de corrigir a senha do usuário &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;root&lt;/code&gt; podemos interromper o modo de segurança e reiniciar o servidor em modo normal de operação.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2585&quot;&gt;Para interromper o modo de segurança podemos rodar o seguinte comando:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;2585&quot;&gt;$ mysqladmin -uroot -p shutdown&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;2690&quot;&gt;Note que agora o servidor vai pedir a senha para o usuário &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;root&lt;/code&gt;, que deverá ser a mesma que você definiu no passo 2.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2808&quot;&gt;Podemos agora reiniciar o servidor &lt;em data-renderer-mark=&quot;true&quot;&gt;MySQL&lt;/em&gt; em modo normal:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;2808&quot;&gt;$ sudo service mysql start&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;2894&quot;&gt;Se tudo correu bem, o servidor estará operando normalmente e a nova senha se aplicará ao usuário &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;root&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;</content:encoded><category>mysql</category></item><item><title>Erro &quot;Use of undefined constant&quot; do PHP: o que é e como resolver?</title><link>https://codamos.com.br/erro-use-of-undefined-constant-php-como-resolver/</link><guid isPermaLink="true">https://codamos.com.br/erro-use-of-undefined-constant-php-como-resolver/</guid><description>Se você programa ou está aprendendo PHP há algum tempo já deve ter visto um erro na sua tela ou arquivo de log que diz algo mais ou menos assim: PHP Notice: Use of undefined constant nome - assumed &apos;n</description><pubDate>Tue, 02 May 2023 07:03:22 GMT</pubDate><content:encoded>&lt;p data-renderer-start-pos=&quot;4&quot;&gt;Se você programa ou está aprendendo PHP há algum tempo já deve ter visto um erro na sua tela ou arquivo de log que diz algo mais ou menos assim:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;4&quot;&gt;PHP Notice: Use of undefined constant nome - assumed &apos;nome&apos; in /var/www/index.php on line 10&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;244&quot;&gt;Hoje nós vamos falar sobre este erro, como identificar e corrigir de forma segura. Vem comigo!&lt;/p&gt;
&lt;h2 id=&quot;Por-que-“Use-of-undefined-constant”-acontece?&quot; data-renderer-start-pos=&quot;340&quot;&gt;Por que “Use of undefined constant” acontece?&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;387&quot;&gt;Quando nós fazemos referência a uma &lt;a data-testid=&quot;link-with-safety&quot; href=&quot;https://www.php.net/manual/pt_BR/language.constants.php&quot; title=&quot;https://www.php.net/manual/pt_BR/language.constants.php&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;constante&lt;/a&gt; que não foi declarada, o PHP decide que em vez de te devolver uma tela em branco ou com erros é melhor entender que você quis dizer que aquilo era uma &lt;em data-renderer-mark=&quot;true&quot;&gt;string&lt;/em&gt;. É uma estratégia de melhor esforço (&lt;em data-renderer-mark=&quot;true&quot;&gt;best effort&lt;/em&gt;) em vez de falhar cedo (&lt;em data-renderer-mark=&quot;true&quot;&gt;fail first&lt;/em&gt;).&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;678&quot;&gt;O erro &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;Use of undefined constant&lt;/code&gt; acontece porque o PHP tenta perdoar uma falha que nós cometemos enquanto escrevemos um código ao não colocar &lt;em data-renderer-mark=&quot;true&quot;&gt;strings&lt;/em&gt; entre aspas.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;842&quot;&gt;Por exemplo, o código abaixo funciona:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;842&quot;&gt;$arr = [&quot;nome&quot; =&amp;gt; &quot;Nawarian&quot;];&lt;br&gt;echo $arr[nome];&lt;br&gt;// PHP Notice:  Use of undefined constant nome - assumed &apos;nome&apos; in ...&lt;br&gt;// Nawarian&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;1014&quot;&gt;O código acima vai justamente gerar um erro &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;Use of undefined constant nome - assumed &apos;nome&apos; in ...&lt;/code&gt;. Isto porque ao acessar a chave &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;nome&lt;/code&gt; do array &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$arr&lt;/code&gt; não utilizamos uma &lt;em data-renderer-mark=&quot;true&quot;&gt;string&lt;/em&gt; &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;&apos;nome&apos;&lt;/code&gt; mas sim uma constante &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;nome&lt;/code&gt; que nunca foi declarada.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1250&quot;&gt;O PHP então perdoa este erro que cometemos e entende que estamos tentando fazer &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;echo $arr[&apos;nome&apos;]&lt;/code&gt;. Mas como isto pode ter sido um erro da nossa parte, o PHP gera um erro do tipo &lt;a data-testid=&quot;link-with-safety&quot; href=&quot;https://www.php.net/manual/pt_BR/errorfunc.constants.php&quot; title=&quot;https://www.php.net/manual/pt_BR/errorfunc.constants.php&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;notice&lt;/em&gt;&lt;/a&gt; que nos permite averiguar aquele pedaço de código para corrigirmos ou mesmo identificarmos bugs.&lt;/p&gt;
&lt;h2 id=&quot;Como-corrigir-o-erro-“Use-of-undefined-constant”?&quot; data-renderer-start-pos=&quot;1533&quot;&gt;Como corrigir o erro “Use of undefined constant”?&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;1584&quot;&gt;O erro &lt;em data-renderer-mark=&quot;true&quot;&gt;Use of undefined constant&lt;/em&gt; acontece, na maioria dos casos, porque tentamos utilizar uma &lt;em data-renderer-mark=&quot;true&quot;&gt;string&lt;/em&gt; mas esquecemos de colocar as aspas. Nestes casos o ideal é corrigir o problema colocando aspas na palavra.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1793&quot;&gt;Por exemplo ao acessar a chave “pessoa” do array “arr” o seguinte código &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$arr[pessoa]&lt;/code&gt; gera erro mas funciona, enquanto o código &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$arr[&apos;pessoa&apos;]&lt;/code&gt; funciona da mesma forma e sem erros.&lt;/p&gt;
&lt;p class=&quot;msg msg--highlight &quot; data-renderer-start-pos=&quot;1793&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Atenção!&lt;/strong&gt; Em alguns casos pode ser que a intenção da pessoa que escreveu aquela linha fosse realmente de referenciar uma constante que foi definida em outro arquivo e nunca foi importada. Neste caso o correto não é transformar em string, mas sim fazer o &lt;a data-testid=&quot;link-with-safety&quot; href=&quot;https://www.php.net/manual/pt_BR/function.include.php&quot; title=&quot;https://www.php.net/manual/pt_BR/function.include.php&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;include&lt;/em&gt;&lt;/a&gt; do arquivo que define a constante.&lt;/p&gt;
&lt;h2 id=&quot;Como-ler-a-mensagem-de-erro-“Use-of-undefined-constant”&quot; data-renderer-start-pos=&quot;2273&quot;&gt;Como ler a mensagem de erro “Use of undefined constant”&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;2330&quot;&gt;Esta mensagem normalmente fica no seu arquivo &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;error.log&lt;/code&gt;mas também pode ser enviada diretamente na tela em ambiente de desenvolvimento.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2466&quot;&gt;O template da mensagem é o seguinte:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;2466&quot;&gt;PHP Notice:  Use of undefined constant &amp;lt;NOME&amp;gt; - assumed &apos;&amp;lt;NOME&amp;gt;&apos; in &amp;lt;ARQUIVO&amp;gt; on line &amp;lt;LINHA&amp;gt;&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;2599&quot;&gt;Vamos quebrar esta mensagem em partes:&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2639&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;PHP Notice:&lt;/strong&gt; o tipo do erro que aconteceu de acordo com os &lt;a data-testid=&quot;link-with-safety&quot; href=&quot;https://www.php.net/manual/pt_BR/errorfunc.constants.php&quot; title=&quot;https://www.php.net/manual/pt_BR/errorfunc.constants.php&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;níveis de erros da linguagem PHP&lt;/a&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2732&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Use of undefined constant &amp;lt;NOME&amp;gt;:&lt;/strong&gt; indica que no código a constante &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;&amp;lt;NOME&amp;gt;&lt;/code&gt; foi referenciada mas nunca foi definida. Deixa eu clarificar o que isso significa com o código a seguir:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;2732&quot;&gt;const PESSOA = &apos;nawarian&apos;;&lt;br&gt;$arr = [&lt;br&gt;  &apos;nawarian&apos; =&amp;gt; &apos;programador&apos;,&lt;br&gt;  &apos;nickolas&apos; =&amp;gt; &apos;trabalhador&apos;&lt;br&gt;];&lt;br&gt;&lt;br&gt;echo $arr[PESSOA]; // programador&lt;br&gt;echo $arr[nickolas]; // Notice&lt;br&gt;echo $arr[&apos;nickolas&apos;]; // trabalhador&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;3117&quot;&gt;No exemplo acima &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$arr[PESSOA]&lt;/code&gt; não gera erro, porque a constante &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;PESSOA&lt;/code&gt; foi definida na primeira linha do código. Já a linha &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$arr[nickolas]&lt;/code&gt; gera um erro &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;Use of undefined constant nickolas&lt;/code&gt; porque estamos fazendo referência a uma constante &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;nickolas&lt;/code&gt; que nunca foi declarada. Note que o correto neste caso é utilizar &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$arr[&apos;nickolas&apos;]&lt;/code&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3448&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;assumed ‘&amp;lt;NOME&amp;gt;&apos; in &amp;lt;ARQUIVO&amp;gt; on line &amp;lt;LINHA&amp;gt;:&lt;/strong&gt; aqui temos a decisão que o PHP tomou por você: utilizar uma string em vez de constante. Como em &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$arr[nickolas]&lt;/code&gt; que vira &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$arr[&apos;nickolas&apos;]&lt;/code&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3634&quot;&gt;O PHP também te indica qual o nome do arquivo em que este problema aconteceu, e em qual linha. Desta forma você pode inspecionar o arquivo e verificar se este é realmente o comportamento que você gostaria que a sua aplicação tivesse.&lt;/p&gt;
&lt;h2 id=&quot;Como-identificar-onde-o-“Use-of-undefined-constant”-ocorre?&quot; data-renderer-start-pos=&quot;3869&quot;&gt;Como identificar onde o “Use of undefined constant” ocorre?&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;3930&quot;&gt;Ao navegar pelo seu sistema você provavelmente vai gerar alguns erros. Estes erros são escritos num arquivo de log, normalmente chamado &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;error.log&lt;/code&gt;. O caminho onde este arquivo é escrito fica definido na &lt;a data-testid=&quot;link-with-safety&quot; href=&quot;https://www.php.net/manual/pt_BR/errorfunc.configuration.php#ini.error-log&quot; title=&quot;https://www.php.net/manual/pt_BR/errorfunc.configuration.php#ini.error-log&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;variável error_log do php.ini&lt;/a&gt;, você pode verificar o caminho tanto no &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;php.ini&lt;/code&gt; quando utilizando a &lt;a data-testid=&quot;link-with-safety&quot; href=&quot;https://www.php.net/manual/pt_BR/function.phpinfo&quot; title=&quot;https://www.php.net/manual/pt_BR/function.phpinfo&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;função phpinfo()&lt;/a&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;4249&quot;&gt;Ao verificar o arquivo &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;error.log&lt;/code&gt; você pode buscar pelo texto “Use of undefined constant” e vai encontrar diferentes linhas com este erro. Leia o fim da linha e repare que ela tem o formato &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;in /caminho/para/arquivo.php on line 100&lt;/code&gt;. Ora, é justamente aqui que você entende qual arquivo PHP está gerando este erro, e qual a linha em que ele acontece.&lt;/p&gt;
&lt;h2 id=&quot;Consequências-do-erro-“Use-of-undefined-constant”&quot; data-renderer-start-pos=&quot;4598&quot;&gt;Consequências do erro “Use of undefined constant”&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;4649&quot;&gt;É importante que a gente seja sempre 100% intencional sobre o código que escrevemos. Eu escrevi sobre isso no artigo sobre &lt;a href=&quot;/programacao-por-coincidencia/&quot;&gt;programação por coincidência e como escrever códigos que outras pessoas entendem&lt;/a&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;4855&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Uma das consequências do &lt;/strong&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Use of undefined constant&lt;/strong&gt;&lt;/em&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt; é que o nosso código fica mais imprevisível, porque nós permitimos que o PHP altere o comportamento do nosso código.&lt;/strong&gt; Isto pode gerar falhas de software que se manifestam das formas mais estranhas possíveis. Além do mais, ao atualizar a versão do PHP pode acontecer de a nova versão remover este comportamento completamente.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;5231&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Outra consequência disso é que o nosso arquivo de logs de erro fica poluído com mensagens do tipo &lt;/strong&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Use of undefined constant&lt;/strong&gt;&lt;/em&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;.&lt;/strong&gt; Estas mensagens não precisam existir &lt;em data-renderer-mark=&quot;true&quot;&gt;porque o seu código está funcionando&lt;/em&gt;, só que não da forma como você o escreveu. Ao poluir o log com mensagens deste tipo, você perde a capacidade de prestar atenção em erros que realmente podem significar uma falha importante no seu sistema.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;5636&quot;&gt;A última consequência que quero citar aqui é a da &lt;strong data-renderer-mark=&quot;true&quot;&gt;utilização de disco indevida&lt;/strong&gt;. Eu já trabalhei com aplicações que para cada página acessada geravam-se cerca de 30 mil linhas de log do tipo &lt;em data-renderer-mark=&quot;true&quot;&gt;Use of undefined constant&lt;/em&gt;. &lt;strong data-renderer-mark=&quot;true&quot;&gt;Isto gera uma superutilização de disco desnecessária e pode inclusive gerar problemas de manutenção em seus servidores e o aumento de custo de armazenamento.&lt;/strong&gt;&lt;/p&gt;</content:encoded><category>php</category><category>junior</category></item><item><title>GIT: Como renomear mensagens de commit em um repositório</title><link>https://codamos.com.br/git-renomear-mensagens-commit-repositorio/</link><guid isPermaLink="true">https://codamos.com.br/git-renomear-mensagens-commit-repositorio/</guid><description>As vezes a gente passa tanto tempo escrevendo um código que na hora de fazer o commit vem aquela sensação de alívio e a gente chega até escreve a mensagem de commit errado, né? 🤣 Neste mini tutorial </description><pubDate>Fri, 17 Mar 2023 20:55:05 GMT</pubDate><content:encoded>&lt;p data-renderer-start-pos=&quot;4&quot;&gt;As vezes a gente passa tanto tempo escrevendo um código que na hora de fazer o &lt;em data-renderer-mark=&quot;true&quot;&gt;commit&lt;/em&gt; vem aquela sensação de alívio e a gente chega até escreve a mensagem de &lt;em data-renderer-mark=&quot;true&quot;&gt;commit&lt;/em&gt; errado, né? 🤣&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;185&quot;&gt;Neste mini tutorial eu vou te mostrar como você pode renomear o &lt;em data-renderer-mark=&quot;true&quot;&gt;commit&lt;/em&gt; anterior usando a opção &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;amend&lt;/code&gt; do Git. Se você ainda não sabe nada sobre git, dá uma olhada neste &lt;a href=&quot;/subindo-arquivos-no-github/&quot; title=&quot;https://codamos.com.br/subindo-arquivos-no-github/&quot;&gt;guia básico&lt;/a&gt; primeiro que vai ser de imensa ajuda!&lt;/p&gt;
&lt;p class=&quot;msg msg--highlight &quot; data-renderer-start-pos=&quot;185&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Atenção!&lt;/strong&gt; Só é possível renomear um &lt;em data-renderer-mark=&quot;true&quot;&gt;commit&lt;/em&gt; usando a opção &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;--force&lt;/code&gt; do comando &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;git push&lt;/code&gt;. Isto é perigoso e pode te levar a perder &lt;em data-renderer-mark=&quot;true&quot;&gt;commits&lt;/em&gt; que estiverem no servidor mas não estiverem em sua máquina local. Use por sua conta e risco!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;635&quot;&gt;Como o tópico pode ficar complicado rapidinho, eu gravei este vídeo pra te ajudar a entender o processo:&lt;/p&gt;
&lt;figure class=&quot;post__video&quot;&gt;&lt;iframe width=&quot;560&quot; height=&quot;314&quot; src=&quot;https://www.youtube.com/embed/zJUaMXAFVHk&quot; allowfullscreen=&quot;allowfullscreen&quot; data-mce-fragment=&quot;1&quot;&gt;&lt;/iframe&gt;&lt;/figure&gt;
&lt;h2 id=&quot;Como-renomear-o-último-commit-do-repositório&quot; data-renderer-start-pos=&quot;742&quot;&gt;Como renomear o último commit do repositório&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;788&quot;&gt;Para renomear o último commit nós podemos utilizar o comando &lt;a href=&quot;https://git-scm.com/docs/git-commit#Documentation/git-commit.txt---amend&quot; title=&quot;https://git-scm.com/docs/git-commit#Documentation/git-commit.txt---amend&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;git commit --amend&lt;/em&gt;&lt;/a&gt;, que só opera sobre o último &lt;em data-renderer-mark=&quot;true&quot;&gt;commit&lt;/em&gt; feito.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;912&quot;&gt;Vejamos este &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;git log&lt;/code&gt; como exemplo, o repositório tem exatamente 3 &lt;em data-renderer-mark=&quot;true&quot;&gt;commits&lt;/em&gt;:&lt;/p&gt;
&lt;div class=&quot;rich-media-item mediaSingleView-content-wrap image-center css-1mzi1es&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div class=&quot;css-eoctpd&quot;&gt;
&lt;div data-context-id=&quot;101318657&quot; data-type=&quot;file&quot; data-node-type=&quot;media&quot; data-width=&quot;1058&quot; data-height=&quot;389&quot; data-id=&quot;9e9a1ad6-d48b-4363-9578-064e3e01e9e9&quot; data-collection=&quot;contentId-101318657&quot; data-file-name=&quot;Screenshot 2023-03-17 at 08.57.59.png&quot; data-file-size=&quot;74195&quot; data-file-mime-type=&quot;image/png&quot; data-alt=&quot;&quot;&gt;
&lt;div id=&quot;newFileExperienceWrapper&quot; class=&quot;new-file-experience-wrapper css-ywv8v8&quot; data-testid=&quot;media-card-view&quot;&gt;
&lt;div class=&quot;media-file-card-view css-1yn77bd&quot; data-testid=&quot;media-file-card-view&quot; data-test-status=&quot;complete&quot; data-test-media-name=&quot;Screenshot 2023-03-17 at 08.57.59.png&quot; data-test-progress=&quot;1&quot;&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image&quot; src=&quot;/media/posts/63/git-log-3-commits.jpg&quot; alt=&quot;Resultado do comando &apos;git log&apos; mostrando 3 commits. Todos escritos em inglês.&quot; width=&quot;960&quot; height=&quot;352&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Resultado do comando &apos;git log&apos; mostrando 3 commits. Todos escritos em inglês.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;O último commit diz &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;feat: add sample map&lt;/code&gt;. Vamos supor que eu gostaria de traduzir esta mensagem de &lt;em data-renderer-mark=&quot;true&quot;&gt;commit&lt;/em&gt; para português. Eu posso renomear aquele commit com o seguinte comando:&lt;/p&gt;
&lt;pre&gt;$ git commit --amend -m &apos;feat: adiciona mapa de exemplo&apos;&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;1228&quot;&gt;Pronto, simples assim! O último commit foi renomeado:&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image&quot; src=&quot;/media/posts/63/git-log-ultimo-commit-traduzido.jpg&quot; alt=&quot;Resultado do comando &apos;git log&apos; mostrando 3 commits. O último commit agora está em português.&quot; width=&quot;959&quot; height=&quot;501&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Resultado do comando &apos;git log&apos; mostrando 3 commits. O último commit agora está em português.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;1286&quot;&gt;Note que nosso &lt;em data-renderer-mark=&quot;true&quot;&gt;branch&lt;/em&gt; agora diz &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;HEAD -&amp;gt; main&lt;/code&gt; e não está mais de acordo com o &lt;em data-renderer-mark=&quot;true&quot;&gt;upstream&lt;/em&gt; (github, gitlab, bitbucket…). Isto acontece porque ao renomear um commit o histórico GIT é modificado e portanto você só consegue atualizar seu repositório usando o &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;git push&lt;/code&gt; com a opção &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;--force&lt;/code&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1568&quot;&gt;Para enviar o commit ao servidor, precisamos agora fazer um &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;git push --force&lt;/code&gt;:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;1568&quot;&gt;$ git push origin main --force&lt;/pre&gt;
&lt;h2 id=&quot;Como-renomear-muitas-mensagens-de-commit&quot; data-renderer-start-pos=&quot;1679&quot;&gt;Como renomear muitas mensagens de commit&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;1721&quot;&gt;A opção &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;--amend&lt;/code&gt; só nos permite renomear &lt;em data-renderer-mark=&quot;true&quot;&gt;a última mensagem de commit&lt;/em&gt; do histórico. &lt;strong data-renderer-mark=&quot;true&quot;&gt;Se você precisa renomear mensagens mais antigas, ou diversas mensagens de uma vez só, vai precisar utilizar um outro comando chamado &lt;/strong&gt;&lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;rebase&lt;/code&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;ak-editor-panel__content&quot;&gt;
&lt;p class=&quot;msg msg--success&quot; data-renderer-start-pos=&quot;1946&quot;&gt;O &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;git rebase&lt;/code&gt; te permite revisitar qualquer porção do seu histórico e modificar como quiser: renomear &lt;em data-renderer-mark=&quot;true&quot;&gt;commits&lt;/em&gt;, remover &lt;em data-renderer-mark=&quot;true&quot;&gt;commits&lt;/em&gt;, mesclar dois mais mais &lt;em data-renderer-mark=&quot;true&quot;&gt;commits&lt;/em&gt; num só…&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2114&quot;&gt;Para renomear muitas mensagens de commit de uma vez só, vamos rodar o seguinte comando:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;2114&quot;&gt;$ git rebase -i HEAD~2&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;2227&quot;&gt;Note que a opção &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;-i&lt;/code&gt; significa &lt;em data-renderer-mark=&quot;true&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;interactive&lt;/strong&gt;&lt;/em&gt;, ou seja: o comando vai aguardar a nossa intervenção pra fazer quaisquer alterações.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2355&quot;&gt;O argumento &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;HEAD~2&lt;/code&gt; indica ao git que nós queremos rever &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;2&lt;/code&gt; &lt;em data-renderer-mark=&quot;true&quot;&gt;commits&lt;/em&gt;, a partir do último commit (&lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;HEAD&lt;/code&gt;). O git então vai abrir seu editor de texto padrão, que no meu caso é o VIM – Se você fica perdidim quando o VIM aparece na sua frente, dá uma olhada neste artigo que eu escrevi sobre &lt;a href=&quot;/vim-basico/&quot; title=&quot;https://codamos.com.br/vim-basico/&quot;&gt;como começar com VIM do zero&lt;/a&gt;. A tela vai ficar assim:&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image&quot; src=&quot;/media/posts/63/git-rebase-lista-commits.jpg&quot; alt=&quot;Tela de edição de commits, resultado do comando &apos;git rebase -i HEAD~2&apos;.&quot; width=&quot;960&quot; height=&quot;680&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Tela de edição de commits, resultado do comando &apos;git rebase -i HEAD~2&apos;.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;2696&quot;&gt;Bueno, as linhas que começam com &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;pick&lt;/code&gt; são &lt;em data-renderer-mark=&quot;true&quot;&gt;commits&lt;/em&gt; que seu repositório conhece. Para todas as mensagens de &lt;em data-renderer-mark=&quot;true&quot;&gt;commit&lt;/em&gt; que você quiser renomear, basta você trocar a palavra &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;pick&lt;/code&gt; por &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;reword&lt;/code&gt;.&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image&quot; src=&quot;/media/posts/63/git-rebase-reword.jpg&quot; alt=&quot;Commit anterior marcado como &apos;reword&apos; durante &apos;git rebase -i HEAD~2&apos;.&quot; width=&quot;960&quot; height=&quot;683&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Commit anterior marcado como &apos;reword&apos; durante &apos;git rebase -i HEAD~2&apos;.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;2884&quot;&gt;Quando você salvar o arquivo, para cada &lt;em data-renderer-mark=&quot;true&quot;&gt;commit&lt;/em&gt; que você decidiu renomear, um editor de texto vai se abrir. Veja:&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image&quot; src=&quot;/media/posts/63/git-rebase-reword-alterar-mensagem-commit.jpg&quot; alt=&quot;Tela de edição da mensagem de commit.&quot; width=&quot;960&quot; height=&quot;400&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Tela de edição da mensagem de commit.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;3001&quot;&gt;E pronto, desta forma você consegue renomear quantos &lt;em data-renderer-mark=&quot;true&quot;&gt;commits&lt;/em&gt; quiser. Não se esqueça de que para enviar estas alterações ao servidor git, seja ele github, gitlab, Bitbucket ou qualquer outro, você precisa fazer um &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;git push --force&lt;/code&gt;, porque isto efetivamente altera o histórico do seu repositório.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</content:encoded><category>ferramentas</category><category>git</category><category>tecnica</category></item><item><title>PHPeste 2023 em Fortaleza, Ceará</title><link>https://codamos.com.br/phpeste-2023-em-fortaleza-ceara/</link><guid isPermaLink="true">https://codamos.com.br/phpeste-2023-em-fortaleza-ceara/</guid><description>Todo ano ela vem e deixa o nosso coração quentinho! É claro que eu estou falando da PHPeste! A maior conferência de PHP de todo o nordeste brasileiro 🥳 No ano de 2023 a PHPeste vai acontecer nos dias</description><pubDate>Wed, 15 Mar 2023 06:56:58 GMT</pubDate><content:encoded>&lt;p data-renderer-start-pos=&quot;1&quot;&gt;Todo ano ela vem e deixa o nosso coração quentinho! É claro que eu estou falando da PHPeste! A maior conferência de PHP de todo o nordeste brasileiro 🥳&lt;/p&gt;
&lt;div class=&quot;ak-editor-panel__content&quot;&gt;
&lt;p class=&quot;msg msg--success&quot; data-renderer-start-pos=&quot;156&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;No ano de 2023 a PHPeste vai acontecer nos dias 06, 07 e 08 de Outubro lá em Fortaleza, Ceará!&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;post__toc&quot;&gt;
&lt;h3&gt;Neste post você vai ver&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#O-que-é-a-PHPeste?&quot;&gt;O que é a PHPeste&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Onde-vai-acontecer-a-PHPeste-2023?&quot;&gt;Onde vai acontecer a PHPeste 2023&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Como-entrar-em-contato-com-a-organização&quot;&gt;Como entrar em contato com a organização&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Datas-importantes!&quot;&gt;Datas importantes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Números-importantes!&quot;&gt;Números importantes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Quero-participar,-como-faço?&quot;&gt;Quero participar, como faço?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Quero-patrocinar,-como-faço?&quot;&gt;Quero patrocinar, como faço? Cadê o Mídia Kit!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#A-conferência-é-da-comunidade,-para-a-comunidade!&quot;&gt;A conferência é da comunidade, para a comunidade!&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id=&quot;O-que-é-a-PHPeste?&quot; data-renderer-start-pos=&quot;254&quot;&gt;O que é a PHPeste&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;274&quot;&gt;PHPeste é uma conferência de PHP organizada pelas comunidades “cabra da peste” do nordeste brasileiro. O evento já passou por João Pessoa (PB), Salvador (BA), Fortaleza(CE), São Luís (MA), Recife (PE), Natal (RN) e agora volta a Fortaleza (CE).&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;520&quot;&gt;Esta foto é do fim do evento que aconteceu em 2022 lá em Natal, no Rio Grande do Norte. A esta altura do campeonato, algumas pessoas já haviam ido pra casa mas dá pra ter uma noção da vibe dessa galera muito massa!&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/62/phpeste-2022-rio-grande-do-norte.jpg&quot; alt=&quot;PHPeste 2022 em Natal, Rio Grande do Norte. Espaço oferecido pelo SebraeLab 💙&quot; width=&quot;4032&quot; height=&quot;2256&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;css-lmzmsq&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;738&quot;&gt;PHPeste 2022 em Natal, Rio Grande do Norte. Espaço oferecido pelo SebraeLab 💙&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;819&quot;&gt;Em 2023 teremos 3 dias de muito aprendizado, mão na massa e, principalmente, de gente “arretada da peste” que irá ampliar ainda mais seu networking. O evento contará com a participação de palestrantes de altíssimo nível e minicursos práticos.&lt;/p&gt;
&lt;h2 id=&quot;Onde-vai-acontecer-a-PHPeste-2023?&quot; data-renderer-start-pos=&quot;1063&quot;&gt;Onde vai acontecer a PHPeste 2023&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;1099&quot;&gt;Este ano a PHPeste vai ser sediada pela nossa querida &lt;a href=&quot;https://www.unifor.br/&quot; title=&quot;https://www.unifor.br/&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Unifor&lt;/a&gt;, que desde já merece muitos aplausos!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1199&quot;&gt;A universidade vai nos receber com espaço e infraestrutura para os três dias de evento, e o endereço é este aqui:&lt;/p&gt;
&lt;div class=&quot;ak-editor-panel__content&quot;&gt;
&lt;p class=&quot;msg msg--highlight &quot; data-renderer-start-pos=&quot;1315&quot;&gt;📍 Av. Washington Soares, 1321 - Edson Queiroz - CEP 60811-905 - Fortaleza-CE Brasil. &lt;a href=&quot;https://goo.gl/maps/cnDwQaqfUPmhnHQj9&quot; rel=&quot;nofollow&quot;&gt;Clique aqui para abrir o &lt;em&gt;Google Maps&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1315&quot;&gt;&lt;iframe width=&quot;400&quot; height=&quot;300&quot; style=&quot;border: 0;&quot; src=&quot;https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d370.33811692313634!2d-38.47812836669208!3d-3.7687850070329305!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x7c745fe9c03245d%3A0xd435fd5a6bfbbe44!2sUNIFOR%20-%20Universidade%20de%20Fortaleza!5e0!3m2!1spt-BR!2sde!4v1678864730242!5m2!1spt-BR!2sde&quot; allowfullscreen=&quot;allowfullscreen&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer-when-downgrade&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;h2 id=&quot;Como-entrar-em-contato-com-a-organização&quot; data-renderer-start-pos=&quot;1399&quot;&gt;Como entrar em contato com a organização&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;1441&quot;&gt;Se você quer apenas conversar, vem falar com a gente no nosso &lt;a href=&quot;https://t.me/phpeste&quot; title=&quot;https://t.me/phpeste&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Canal do Telegram&lt;/a&gt;!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1523&quot;&gt;Se você ou a sua empresa quer patrocinar a conferência, vem falar com a gente através do &lt;a href=&quot;mailto:contato@phpeste.org&quot; title=&quot;mailto:contato@phpeste.org&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;contato@phpeste.org&lt;/a&gt;. Mas eu recomendo que você continue lendo até o final pra cobrir algumas das suas dúvidas.&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/62/phpeste-redes-sociais.png&quot; alt=&quot;Redes e contatos da organização do evento!&quot; width=&quot;1603&quot; height=&quot;902&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;css-lmzmsq&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;1726&quot;&gt;Redes e contatos da organização do evento!&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;Datas-importantes!&quot; data-renderer-start-pos=&quot;1771&quot;&gt;Datas importantes&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;1791&quot;&gt;Se você quer palestrar, assistir palestras ou mesmo patrocinar o evento, é bom prestar atenção nessas datas. Vem comigo que eu vou te dar os detalhes que tu precisa!&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 30.983%;&quot;&gt;&lt;strong&gt;Data&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;width: 69.1596%;&quot;&gt;&lt;strong&gt;O que vai acontecer&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 30.983%;&quot;&gt;Outubro de 2022&lt;/td&gt;
&lt;td style=&quot;width: 69.1596%;&quot;&gt;Local da conferência confirmado: Fortaleza, Ceará&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 30.983%;&quot;&gt;Fevereiro de 2023&lt;/td&gt;
&lt;td style=&quot;width: 69.1596%;&quot;&gt;A organização concordou com o Mídia Kit proposto e sai em busca de patrocínio.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 30.983%;&quot;&gt;Março até Setembro de 2023&lt;/td&gt;
&lt;td style=&quot;width: 69.1596%;&quot;&gt;A organização fica aberta para conversar com potenciais patrocinadores.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 30.983%;&quot;&gt;Abril de 2023&lt;/td&gt;
&lt;td style=&quot;width: 69.1596%;&quot;&gt;Abertura do &lt;em data-renderer-mark=&quot;true&quot;&gt;Call for papers&lt;/em&gt;, quem quer palestrar pode enviar suas propostas!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 30.983%;&quot;&gt;Maio de 2023&lt;/td&gt;
&lt;td style=&quot;width: 69.1596%;&quot;&gt;Encerrado o &lt;em data-renderer-mark=&quot;true&quot;&gt;Call for paper&lt;/em&gt;s, qualquer submissão enviada depois desta data será ignorada.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 30.983%;&quot;&gt;Junho de 2023&lt;/td&gt;
&lt;td style=&quot;width: 69.1596%;&quot;&gt;Divulgação da lista de oficinas e palestras.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 30.983%;&quot;&gt;Agosto de 2023&lt;/td&gt;
&lt;td style=&quot;width: 69.1596%;&quot;&gt;Primeiro lote de ingressos aberto para compra&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 30.983%;&quot;&gt;Setembro* de 2023&lt;/td&gt;
&lt;td style=&quot;width: 69.1596%;&quot;&gt;Segundo lote de ingressos aberto para compra. Pode acontecer antes se o primeiro lote esgotar antes do previsto.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 30.983%;&quot;&gt;Outubro de 2023&lt;/td&gt;
&lt;td style=&quot;width: 69.1596%;&quot;&gt;É hora de falar de PHP, conhecer gente, fazer negócios e se aproximar da comunidade 🐘💙🥳&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;Números-importantes!&quot; data-renderer-start-pos=&quot;2878&quot;&gt;Números importantes&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;2900&quot;&gt;Deixa eu te contar alguns fatos e números sobre a PHPeste que são importantíssimos pra você já sentir como a conferência vai acontecer. Chegue aqui!&lt;/p&gt;
&lt;ul&gt;
&lt;li data-renderer-start-pos=&quot;2900&quot;&gt;Três dias de evento&lt;/li&gt;
&lt;li data-renderer-start-pos=&quot;2900&quot;&gt;Mais de 20 palestrantes, pelo menos 10 se identificam com ou são do gênero feminino, pelo menos 5 pessoas são das comunidades locais&lt;/li&gt;
&lt;li data-renderer-start-pos=&quot;2900&quot;&gt;400 participantes no total&lt;/li&gt;
&lt;li data-renderer-start-pos=&quot;2900&quot;&gt;7 horas inteiras dedicadas a &lt;em&gt;networking&lt;/em&gt;&lt;/li&gt;
&lt;li data-renderer-start-pos=&quot;2900&quot;&gt;3 trilhas diferentes, uma 100% em inglês&lt;/li&gt;
&lt;li data-renderer-start-pos=&quot;2900&quot;&gt;Palestras e oficinas sobre PHP, carreira, arquitetura e experiência&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;Quero-participar,-como-faço?&quot; data-renderer-start-pos=&quot;3394&quot;&gt;Quero participar, como faço?&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;3424&quot;&gt;Fica de olho no calendário acima e nas comunicações da comunidade tanto no site &lt;a href=&quot;http://phpeste.org/&quot; title=&quot;http://phpeste.org/&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;sponsored&quot;&gt;oficial da PHPeste&lt;/a&gt; quanto nas &lt;a href=&quot;https://twitter.com/phpestene&quot; title=&quot;https://twitter.com/phpestene&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;redes sociais!&lt;/a&gt;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3550&quot;&gt;Se você tem alguma oficina ou palestra que queira oferecer, a partir de Abril de 2023 você vai poder enviar a(s) sua(s) proposta(s) pra gente!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3550&quot;&gt;Não se esquece de que é obrigatório respeitar o nosso &lt;a href=&quot;https://www.phpeste.org/code-of-conduct/&quot; title=&quot;https://www.phpeste.org/code-of-conduct/&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot;&gt;Código de Conduta&lt;/a&gt;, viu?&lt;/p&gt;
&lt;h2 id=&quot;Quero-patrocinar,-como-faço?&quot; data-renderer-start-pos=&quot;3773&quot;&gt;Quero patrocinar, como faço? Cadê o Mídia Kit!&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;3803&quot;&gt;Este ano a PHPeste oferece 4 cotas diferentes de patrocínio, pra caber no caixa de qualquer empresa que queira nos apoiar. Abaixo você confere as diferentes cotas e benefícios para quem patrocina e faz o evento acontecer!&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/62/phpeste-planos-de-patrocinio-2023.png&quot; alt=&quot;Cotas Bronze (R$ 3.000), Prata (R$ 7.000), Ouro (R$ 10.000) e Diamante (R$ 12.000) e seus benefícios.&quot; width=&quot;1605&quot; height=&quot;902&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;css-lmzmsq&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;4029&quot;&gt;Cotas Bronze (R$ 3.000), Prata (R$ 7.000), Ouro (R$ 10.000) e Diamante (R$ 12.000) e seus benefícios.&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;4133&quot;&gt;Se interessou né? Se você ou a sua empresa querem e podem ajudar a bancar o evento, entra em contato com a gente no &lt;a href=&quot;mailto:contato@phpeste.org&quot; title=&quot;mailto:contato@phpeste.org&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;contato@phpeste.org&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;ak-editor-panel__content&quot;&gt;
&lt;p class=&quot;msg msg--info&quot; data-renderer-start-pos=&quot;4272&quot;&gt;&lt;strong&gt;O mídia kit está disponível pra &lt;a href=&quot;https://drive.google.com/file/d/1a3XVbW2835XtYZY_rVplemu7nO4Vl228/view?usp=sharing&quot; title=&quot;https://drive.google.com/file/d/1a3XVbW2835XtYZY_rVplemu7nO4Vl228/view?usp=sharing&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;download aqui&lt;/a&gt;! 👈👈&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;h2 id=&quot;A-conferência-é-da-comunidade,-para-a-comunidade!&quot; data-renderer-start-pos=&quot;4321&quot;&gt;A conferência é da comunidade, para a comunidade!&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;4372&quot;&gt;Então compartilha bastante este artigo nas suas redes sociais, ajuda a gente a divulgar o evento e se você puder nos conectar com empresas que tenham interesse em patrocinar a conferência deste ano, pode entrar em contato com a gente que nós vamos fazer a mágica acontecer.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;4641&quot;&gt;O compartilhamento e engajamento em redes sociais é uma ajuda incrível pra fazer esta conferência ser um sucesso como nos anos anteriores 💙!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;4788&quot;&gt;Nos vemos na Terra da Luz! ☀️&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</content:encoded><category>evento</category><category>php</category><category>phpeste</category></item><item><title>Como criar um jogo usando Phaser e TypeScript</title><link>https://codamos.com.br/como-criar-um-jogo-usando-phaser-e-typescript/</link><guid isPermaLink="true">https://codamos.com.br/como-criar-um-jogo-usando-phaser-e-typescript/</guid><description>Se você se interessa por desenvolvimento de jogos e já aprendeu alguma coisa sobre programação, provavelmente sabe que é possível escrever jogos usando a API HTML5 dos navegadores. E se procurou saber</description><pubDate>Tue, 14 Mar 2023 09:02:59 GMT</pubDate><content:encoded>&lt;p data-renderer-start-pos=&quot;4&quot;&gt;Se você se interessa por desenvolvimento de jogos e já aprendeu alguma coisa sobre programação, provavelmente sabe que é possível escrever jogos usando a &lt;a href=&quot;https://html.spec.whatwg.org/multipage/introduction.html#is-this-html5?&quot; title=&quot;https://html.spec.whatwg.org/multipage/introduction.html#is-this-html5?&quot; rel=&quot;nofollow&quot;&gt;API HTML5&lt;/a&gt; dos navegadores. E se procurou saber um pouquinho mais, percebeu que existe diferentes ferramentas pra ajudar a trabalhar com desenvolvimento de jogos como o &lt;a href=&quot;https://phaser.io/&quot; title=&quot;https://phaser.io/&quot; rel=&quot;nofollow&quot;&gt;Phaser&lt;/a&gt;.&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/61/phaser-logo.png&quot; alt=&quot;Logotipo do framework Phaser&quot; width=&quot;824&quot; height=&quot;186&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;css-lmzmsq&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;337&quot;&gt;Logotipo do framework Phaser&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;div class=&quot;ak-editor-panel__content&quot;&gt;
&lt;p class=&quot;msg msg--success&quot; data-renderer-start-pos=&quot;369&quot;&gt;Phaser é um &lt;em data-renderer-mark=&quot;true&quot;&gt;framework&lt;/em&gt; que te permite criar jogos complexos utilizando HTML5 e suas tecnologias como Canvas, WebGL, WebAudio e também facilita a forma de capturar ações do usuário usando teclado, mouse, &lt;em data-renderer-mark=&quot;true&quot;&gt;touch&lt;/em&gt; ou mesmo controles de videogame. Acesse o &lt;a href=&quot;https://phaser.io/&quot; title=&quot;https://phaser.io/&quot; rel=&quot;nofollow&quot;&gt;site oficial phaser.io&lt;/a&gt; para saber mais!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;662&quot;&gt;Neste tutorial eu vou te ensinar a criar um jogo com Phaser e &lt;a href=&quot;https://www.typescriptlang.org/&quot; title=&quot;https://www.typescriptlang.org/&quot; rel=&quot;nofollow&quot;&gt;TypeScript&lt;/a&gt; de forma rápida e prática!&lt;/p&gt;
&lt;div class=&quot;post__toc&quot;&gt;
&lt;h3&gt;Neste artigo&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1grfn7g259&quot;&gt;Vídeo do artigo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Vale-a-pena-criar-um-jogo-utilizando-Phaser?&quot;&gt;Vale a pena criar um jogo utilizando Phaser?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Qual-a-melhor-forma-de-criar-um-projeto-com-Phaser?&quot;&gt;Qual a melhor forma de criar um projeto com Phaser?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Passo-a-passo:-como-criar-um-jogo-com-Phaser-e-TypeScript&quot;&gt;Passo a passo: como criar um jogo com Phaser e TypeScript&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#Passo-1-–-Clone-o-repositório-template&quot;&gt;Passo 1 – Clone o repositório template&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Passo-2-–-Instale-as-dependências-com-NPM&quot;&gt;Passo 2 – Instale as dependências com NPM&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Passo-3-–-Inicie-o-modo-de-desenvolvimento&quot;&gt;Passo 3 – Inicie o modo de desenvolvimento&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Passo-4-–-Customize-a-configuração-do-seu-canvas&quot;&gt;Passo 4 – Customize a configuração do seu canvas&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Passo-5-–-Comece-a-desenvolver-seu-jogo&quot;&gt;Passo 5 – Comece a desenvolver seu jogo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Você-está-pronte-para-começar!&quot;&gt;Você está pronte para começar!&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id=&quot;mcetoc_1grfn7g259&quot; data-renderer-start-pos=&quot;764&quot;&gt;Vídeo do artigo&lt;/h2&gt;
&lt;p&gt;Pra facilitar a leitura e te levar direto ao ponto, nós criamos um vídeo de leitura e execução deste tutorial. Se você prefere ver do que ler, aqui está!&lt;/p&gt;
&lt;figure class=&quot;post__video&quot;&gt;&lt;iframe width=&quot;560&quot; height=&quot;314&quot; src=&quot;https://www.youtube.com/embed/uoO_HXl62Z8&quot; allowfullscreen=&quot;allowfullscreen&quot; data-mce-fragment=&quot;1&quot;&gt;&lt;/iframe&gt;&lt;/figure&gt;
&lt;h2 id=&quot;Vale-a-pena-criar-um-jogo-utilizando-Phaser?&quot; data-renderer-start-pos=&quot;764&quot;&gt;Vale a pena criar um jogo utilizando Phaser?&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;810&quot;&gt;Muita gente se pergunta qual a melhor ferramenta para aprender, já que todo mundo sonha alto: lançar um jogo na &lt;a href=&quot;https://store.steampowered.com/&quot; title=&quot;https://store.steampowered.com/&quot; rel=&quot;nofollow&quot;&gt;Steam&lt;/a&gt;, no &lt;a href=&quot;https://itch.io/&quot; title=&quot;https://itch.io/&quot; rel=&quot;nofollow&quot;&gt;Itch.io&lt;/a&gt;, Facebook ou mesmo no &lt;a href=&quot;https://play.google.com/store/games&quot; title=&quot;https://play.google.com/store/games&quot; rel=&quot;nofollow&quot;&gt;Google Play&lt;/a&gt; ou &lt;a href=&quot;https://www.apple.com/app-store/&quot; title=&quot;https://www.apple.com/app-store/&quot; rel=&quot;nofollow&quot;&gt;App Store&lt;/a&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;810&quot;&gt;Não é possível fazer tudo isso usando somente o &lt;a href=&quot;https://phaser.io/&quot; title=&quot;https://phaser.io/&quot; rel=&quot;nofollow&quot;&gt;Phaser&lt;/a&gt;, mas existem outras ferramentas como o &lt;a href=&quot;https://www.electronjs.org/&quot; title=&quot;https://www.electronjs.org/&quot; rel=&quot;nofollow&quot;&gt;Electron&lt;/a&gt; para empacotar seu jogo para plataformas Desktop e também o &lt;a href=&quot;https://ionicframework.com/&quot; title=&quot;https://ionicframework.com/&quot; rel=&quot;nofollow&quot;&gt;Ionic&lt;/a&gt; que lhe permite fazer o mesmo para Smartphones e Tablets.&lt;/p&gt;
&lt;div class=&quot;ak-editor-panel css-2yylw6&quot; data-panel-type=&quot;success&quot;&gt;
&lt;div class=&quot;ak-editor-panel__content&quot;&gt;
&lt;p class=&quot;msg msg--success&quot; data-renderer-start-pos=&quot;1218&quot;&gt;Então considerando que Phaser utiliza JavaScript e/ou TypeScript para desenvolvimento, e você pode portar seu jogo para qualquer plataforma, &lt;strong data-renderer-mark=&quot;true&quot;&gt;vale a pena sim escrever um jogo utilizando Phaser.&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-renderer-start-pos=&quot;1413&quot;&gt;E não somente jogos simples, viu? A foto abaixo é do jogo &lt;a href=&quot;https://phaser.io/news/2021/06/citadels&quot; title=&quot;https://phaser.io/news/2021/06/citadels&quot; rel=&quot;nofollow&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;Citadels&lt;/em&gt;&lt;/a&gt; lançado para Facebook, construído com Phaser e que conquistou um público de 4,2 milhões de jogadores:&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/61/citadels-game-screenshot.png&quot; alt=&quot;Captura de tela do jogo Citadels, escrito em Phaser&quot; width=&quot;1434&quot; height=&quot;717&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;css-lmzmsq&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;1585&quot;&gt;Captura de tela do jogo &lt;em data-renderer-mark=&quot;true&quot;&gt;Citadels&lt;/em&gt;, escrito em Phaser&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;Qual-a-melhor-forma-de-criar-um-projeto-com-Phaser?&quot; data-renderer-start-pos=&quot;1639&quot;&gt;Qual a melhor forma de criar um projeto com Phaser?&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;1692&quot;&gt;Eu experimentei bastante com o framework Phaser e de acordo com a minha experiência eu aprendi a seguinte lição: &lt;strong data-renderer-mark=&quot;true&quot;&gt;se o seu objetivo é criar um jogo, você deve focar mais no jogo em si e menos na tecnologia por trás dele&lt;/strong&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1692&quot;&gt;Como desenvolvedor de software tradicional isso é um exercício muito difícil pra mim. Eu gosto de criar designs elegantes, que carregam significado e facilitam a leitura. E o desenvolvimento de jogos pra mim sempre fica parecendo uma colcha de retalhos, mau acabada e com diferentes bugs esperando pra pular na minha cara.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1913&quot;&gt;Então pra facilitar a minha vida, e agora a sua também, eu criei um projetinho no Github que você pode clonar e começar a codificar. Ele já traz consigo o &lt;a href=&quot;https://phaser.io/&quot; title=&quot;https://phaser.io/&quot; rel=&quot;nofollow&quot;&gt;Phaser&lt;/a&gt;, &lt;a href=&quot;https://webpack.js.org/&quot; title=&quot;https://webpack.js.org/&quot; rel=&quot;nofollow&quot;&gt;Webpack&lt;/a&gt; e &lt;a href=&quot;https://www.typescriptlang.org/&quot; title=&quot;https://www.typescriptlang.org/&quot; rel=&quot;nofollow&quot;&gt;TypeScript&lt;/a&gt; configurados.&lt;/p&gt;
&lt;div class=&quot;ak-editor-panel__content&quot;&gt;
&lt;p class=&quot;msg msg--success&quot; data-renderer-start-pos=&quot;2437&quot;&gt;O repositório &lt;a href=&quot;https://github.com/nawarian/phaser-ts-skeleton/&quot; title=&quot;https://github.com/nawarian/phaser-ts-skeleton/&quot; rel=&quot;nofollow&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;nawarian/phaser-ts-skeleton&lt;/strong&gt;&lt;/a&gt; traz uma aplicação exemplo com &lt;a href=&quot;https://phaser.io/&quot; title=&quot;https://phaser.io/&quot; rel=&quot;nofollow&quot;&gt;Phaser&lt;/a&gt;, &lt;a href=&quot;https://webpack.js.org/&quot; title=&quot;https://webpack.js.org/&quot; rel=&quot;nofollow&quot;&gt;Webpack&lt;/a&gt; e &lt;a href=&quot;https://www.typescriptlang.org/&quot; title=&quot;https://www.typescriptlang.org/&quot; rel=&quot;nofollow&quot;&gt;TypeScript&lt;/a&gt; configurados e é perfeito para quem quer começar sem prestar muita atenção na tecnologia! &lt;strong data-renderer-mark=&quot;true&quot;&gt;A melhor forma de criar um projeto Phaser é utilizando templates que já existem, como o &lt;/strong&gt;&lt;a href=&quot;https://github.com/nawarian/phaser-ts-skeleton/&quot; title=&quot;https://github.com/nawarian/phaser-ts-skeleton/&quot; rel=&quot;nofollow&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;nawarian/phaser-ts-skeleton&lt;/strong&gt;&lt;/a&gt;!&lt;/p&gt;
&lt;h2 id=&quot;Passo-a-passo:-como-criar-um-jogo-com-Phaser-e-TypeScript&quot; data-renderer-start-pos=&quot;2748&quot;&gt;Passo a passo: como criar um jogo com Phaser e TypeScript&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;2807&quot;&gt;O nosso plano de ação é bem simples na realidade. Vamos primeiro clonar o repositório, depois instalar suas dependências e depois rodar o programa para testar.&lt;/p&gt;
&lt;h3 id=&quot;Passo-1-–-Clone-o-repositório-template&quot; data-renderer-start-pos=&quot;2968&quot;&gt;Passo 1 – Clone o repositório template&lt;/h3&gt;
&lt;p data-renderer-start-pos=&quot;3008&quot;&gt;Acesse a página do &lt;a href=&quot;https://github.com/nawarian/phaser-ts-skeleton/&quot; title=&quot;https://github.com/nawarian/phaser-ts-skeleton/&quot; rel=&quot;nofollow&quot;&gt;nawarian/phaser-ts-skeleton&lt;/a&gt; no Github para obter o link e clonar em sua máquina. Se preferir, para encurtar o caminho você pode até mesmo fazer um fork do projeto.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3008&quot;&gt;Eu vou optar por clonar, fazendo o seguinte:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;3192&quot;&gt;$ git clone git@github.com:nawarian/phaser-ts-skeleton.git meu-primeiro-jogo&lt;br&gt;$ cd meu-primeiro-jogo&lt;br&gt;$ rm -rf .git&lt;br&gt;$ git init&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;3364&quot;&gt;O primeiro comando &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;git clone git@github.com:nawarian/phaser-ts-skeleton.git meu-primeiro-jogo&lt;/code&gt; vai clonar (baixar) o repositório para o seu computador na pasta &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;meu-primeiro-jogo&lt;/code&gt;. Em seguida nós entramos nesta pasta com o comando &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;cd meu-primeiro-jogo&lt;/code&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3615&quot;&gt;Você vai reparar que este já é um repositório git, e que aponta para o meu repositório. Desta forma você não vai conseguir subir seus arquivos! Então eu apaguei as referências ao git com &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;rm -rf .git&lt;/code&gt; e inicializei um novo repositório git com o comando &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;git init&lt;/code&gt;.&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/61/clone-projeto-nawarian-phaser-typescript.png&quot; alt=&quot;Clonando o projeto nawarian/phaser-ts-skeleton!&quot; width=&quot;1189&quot; height=&quot;312&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Clonando o projeto nawarian/phaser-ts-skeleton!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;3880&quot;&gt;Se você ainda não sabe mexer com git, dá uma olhada no nosso tutorial de &lt;a href=&quot;/subindo-arquivos-no-github/&quot;&gt;como começar a trabalhar com git e github&lt;/a&gt;!&lt;/p&gt;
&lt;h3 id=&quot;Passo-2-–-Instale-as-dependências-com-NPM&quot; data-renderer-start-pos=&quot;3997&quot;&gt;Passo 2 – Instale as dependências com NPM&lt;/h3&gt;
&lt;p data-renderer-start-pos=&quot;4040&quot;&gt;Estamos prontes pra instalar as dependências do projeto. São as dependências que estão escritas no arquivo &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;package.json&lt;/code&gt; sabe? Sem elas a gente não consegue sequer rodar o nosso jogo.&lt;/p&gt;
&lt;div class=&quot;ak-editor-panel css-2yylw6&quot; data-panel-type=&quot;warning&quot;&gt;
&lt;div class=&quot;ak-editor-panel__content&quot;&gt;
&lt;p class=&quot;msg msg--highlight &quot; data-renderer-start-pos=&quot;4225&quot;&gt;Eu estou utilizando o Node 16 neste momento!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-renderer-start-pos=&quot;4272&quot;&gt;Vamos executar o seguinte comando no terminal:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;4272&quot;&gt;$ npm install&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;4335&quot;&gt;Este comando vai baixar alguns pacotes, e a tela final deve ficar mais ou menos assim:&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/61/phaser-typescript-npm-install.png&quot; alt=&quot;Instalando dependências com npm install.&quot; width=&quot;715&quot; height=&quot;222&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Instalando dependências com &lt;code&gt;npm install&lt;/code&gt;.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;Passo-3-–-Inicie-o-modo-de-desenvolvimento&quot; data-renderer-start-pos=&quot;4426&quot;&gt;Passo 3 – Inicie o modo de desenvolvimento&lt;/h3&gt;
&lt;p data-renderer-start-pos=&quot;4470&quot;&gt;Este é o principal comando que você precisa lembrar daqui pra frente. Ele vai te permitir alterar o código do seu programa e ver os resultados imediatamente no navegador!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;4642&quot;&gt;Rode o seguinte comando no terminal:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;4642&quot;&gt;$ npm run dev&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;4695&quot;&gt;Ao rodar o comando acima, você vai notar algumas mensagens aparecendo no seu terminal. Uma delas diz o seguinte:&lt;/p&gt;
&lt;div class=&quot;ak-editor-panel__content&quot;&gt;
&lt;p class=&quot;msg msg--success&quot; data-renderer-start-pos=&quot;4810&quot;&gt;&amp;lt;i&amp;gt; [webpack-dev-server] Loopback: &lt;a href=&quot;http://localhost:8080/&quot; title=&quot;http://localhost:8080/&quot; rel=&quot;nofollow&quot;&gt;http://localhost:8080/&lt;/a&gt;, &lt;a href=&quot;http://127.0.0.1:8080/&quot; title=&quot;http://127.0.0.1:8080/&quot; rel=&quot;nofollow&quot;&gt;http://127.0.0.1:8080/&lt;/a&gt;.&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image&quot; src=&quot;/media/posts/61/phaser-typescript-modo-desenvolvimento.png&quot; alt=&quot;Tela do Webpack após compilar nosso projeto Phaser com TypeScript e tornar disponível em http://localhost:8080.&quot; width=&quot;1585&quot; height=&quot;956&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Tela do Webpack após compilar nosso projeto Phaser com TypeScript e tornar disponível em &lt;a href=&quot;http://localhost:8080&quot; rel=&quot;nofollow&quot;&gt;http://localhost:8080&lt;/a&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;4898&quot;&gt;Este é justamente o endereço onde você pode encontrar seu projeto rodando! Acesse &lt;a href=&quot;http://localhost:8080/&quot; title=&quot;http://localhost:8080/&quot; rel=&quot;nofollow&quot;&gt;http://localhost:8080/&lt;/a&gt; e você vai ver a seguinte animação:&lt;/p&gt;
&lt;figure class=&quot;post__video&quot;&gt;&lt;iframe width=&quot;560&quot; height=&quot;314&quot; src=&quot;https://www.youtube.com/embed/czV2FYFuFJM&quot; allowfullscreen=&quot;allowfullscreen&quot; data-mce-fragment=&quot;1&quot;&gt;&lt;/iframe&gt;&lt;/figure&gt;
&lt;h3 id=&quot;Passo-4-–-Customize-a-configuração-do-seu-canvas&quot; data-renderer-start-pos=&quot;5041&quot;&gt;Passo 4 – Customize a configuração do seu &lt;em data-renderer-mark=&quot;true&quot;&gt;canvas&lt;/em&gt;&lt;/h3&gt;
&lt;p data-renderer-start-pos=&quot;5091&quot;&gt;Você reparou que a tela do jogo utiliza a proporção de um smartphone, certo? Provavelmente os primeiros jogos que você vai querer desenvolver utilizem uma tela um pouquinho maior. Então deixa eu te mostrar exatamente onde você pode mexer para mudar isso!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;5347&quot;&gt;No arquivo &lt;a href=&quot;https://github.com/nawarian/phaser-ts-skeleton/blob/main/src/game.ts#L13-L14&quot; title=&quot;https://github.com/nawarian/phaser-ts-skeleton/blob/main/src/game.ts#L13-L14&quot; rel=&quot;nofollow&quot;&gt;src/game.ts&lt;/a&gt; você encontra as configurações globais do jogo. É aqui que você pode alterar as proriedades &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;width&lt;/code&gt; (largura) e &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;height&lt;/code&gt; (altura) da tela. No exemplo abaixo eu alterei a tela pra utilizar 800x600 pixels:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;5347&quot;&gt;...&lt;br&gt;&lt;br&gt;const cfg: Phaser.Types.Core.GameConfig = {&lt;br&gt;  width: 800, // Largura&lt;br&gt;  height: 600, // Altura&lt;br&gt;  type: Phaser.AUTO,&lt;br&gt;  ...&lt;br&gt;};&lt;/pre&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/61/phaser-ts-altura-largura-configuracao.png&quot; alt=&quot;Tela do projeto Phaser com Typescript em 800x600 pixels.&quot; width=&quot;1920&quot; height=&quot;1200&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Tela do projeto Phaser com Typescript em 800x600 pixels.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;Passo-5-–-Comece-a-desenvolver-seu-jogo&quot; data-renderer-start-pos=&quot;5704&quot;&gt;Passo 5 – Comece a desenvolver seu jogo&lt;/h3&gt;
&lt;p data-renderer-start-pos=&quot;5745&quot;&gt;Você vai reparar que a estrutura de pastas é bem simples de entender. Vejamos a tabela a seguir:&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.5555%;&quot;&gt;&lt;strong&gt;Pasta/arquivo&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;width: 79.4445%;&quot;&gt;&lt;strong&gt;O que faz&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.5555%;&quot;&gt;assets/&lt;/td&gt;
&lt;td style=&quot;width: 79.4445%;&quot;&gt;Armazena imagens utilizadas no jogo. Aqui entram&lt;br&gt;&lt;code&gt;spritesheets&lt;/code&gt;, imagens de plano de fundo, partículas...&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.5555%;&quot;&gt;src/&lt;/td&gt;
&lt;td style=&quot;width: 79.4445%;&quot;&gt;Código fonte do seu jogo. Todos os arquivos &lt;code&gt;.ts&lt;/code&gt; estão aqui!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.5555%;&quot;&gt;src/scenes/&lt;/td&gt;
&lt;td style=&quot;width: 79.4445%;&quot;&gt;Onde todas as &lt;a href=&quot;https://newdocs.phaser.io/docs/3.55.2/Phaser.Scene&quot; title=&quot;https://newdocs.phaser.io/docs/3.55.2/Phaser.Scene&quot; rel=&quot;nofollow&quot;&gt;Cenas&lt;/a&gt; do seu jogo ficam armazenadas.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.5555%;&quot;&gt;src/game.ts&lt;/td&gt;
&lt;td style=&quot;width: 79.4445%;&quot;&gt;Configurações globais do seu jogo.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.5555%;&quot;&gt;maps/&lt;/td&gt;
&lt;td style=&quot;width: 79.4445%;&quot;&gt;Arquivos &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;.json&lt;/code&gt; criados por editores de mapas como o &lt;a href=&quot;https://www.mapeditor.org/&quot; title=&quot;https://www.mapeditor.org/&quot; rel=&quot;nofollow&quot;&gt;Tiled&lt;/a&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-renderer-start-pos=&quot;6260&quot;&gt;O arquivo &lt;a href=&quot;https://github.com/nawarian/phaser-ts-skeleton/blob/main/src/scenes/GameScene.ts&quot; title=&quot;https://github.com/nawarian/phaser-ts-skeleton/blob/main/src/scenes/GameScene.ts&quot; rel=&quot;nofollow&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;scenes/GameScene.ts&lt;/strong&gt;&lt;/a&gt; por exemplo é a cena que controla a animação que você vê na tela.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;6357&quot;&gt;Vamos adicionar o seguinte código na linha &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;16&lt;/code&gt; para tonar a imagem do Phaser vermelha:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;6357&quot;&gt;phaser.setTint(0xff0000);&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;6471&quot;&gt;Repare que &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;0xff0000&lt;/code&gt; é o código hexadecimal para a cor &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;rgb(255, 0, 0)&lt;/code&gt;. O resultado fica assim:&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/61/phaser-ts-logo-vermelho.png&quot; alt=&quot;Logotipo do Phaser agora em vermelho!&quot; width=&quot;1920&quot; height=&quot;1200&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Logotipo do Phaser agora em vermelho!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;Você-está-pronte-para-começar!&quot; data-renderer-start-pos=&quot;6569&quot;&gt;Você está pronte para começar!&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;6601&quot;&gt;No começo não vai ser simples, principalmente se você não sabe nada sobre programação de jogos. Felizmente o site oficial do framework &lt;a href=&quot;https://phaser.io/&quot; title=&quot;https://phaser.io/&quot; rel=&quot;nofollow&quot;&gt;Phaser&lt;/a&gt; traz vários &lt;a href=&quot;https://phaser.io/examples&quot; title=&quot;https://phaser.io/examples&quot; rel=&quot;nofollow&quot;&gt;exemplos&lt;/a&gt; de uma &lt;a href=&quot;https://phaser.io/learn&quot; title=&quot;https://phaser.io/learn&quot; rel=&quot;nofollow&quot;&gt;extensa documentação&lt;/a&gt;. Infelizmente, tudo em inglês.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;6824&quot;&gt;Você também pode procurar vídeos no YouTube sobre o tema. E se tiver alguma dúvida específica, pode falar comigo que eu vou ficar mais do que feliz em te ajudar a resolver o problema e aprender contigo!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;7028&quot;&gt;Nós também temos um grupo no Telegram agora, você pode &lt;a href=&quot;https://t.me/codamos_forum&quot; title=&quot;https://t.me/codamos_forum&quot; rel=&quot;nofollow&quot;&gt;clicar aqui&lt;/a&gt; pra entrar e conversar com a gente!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</content:encoded><category>javascript</category><category>jogos</category><category>phaser</category><category>typescript</category></item><item><title>12 Podcasts sobre programação e tecnologia em português para escutar em 2023</title><link>https://codamos.com.br/escutar-podcasts-de-tecnologia-e-programacao-em-portugues/</link><guid isPermaLink="true">https://codamos.com.br/escutar-podcasts-de-tecnologia-e-programacao-em-portugues/</guid><description>Para quem está estudando ou se aperfeiçoando em desenvolvimento de software, escutar podcasts é uma ferramenta incrível pra se atualizar e descobrir tópicos novos. Na edição de Outubro de 2022 eu visi</description><pubDate>Sun, 22 Jan 2023 08:08:14 GMT</pubDate><content:encoded>&lt;p data-renderer-start-pos=&quot;6&quot;&gt;Para quem está estudando ou se aperfeiçoando em desenvolvimento de software, escutar podcasts é uma ferramenta incrível pra se atualizar e descobrir tópicos novos.&lt;/p&gt;
&lt;div class=&quot;ak-editor-panel__content&quot;&gt;
&lt;p class=&quot;msg msg--info&quot; data-renderer-start-pos=&quot;156&quot;&gt;Na edição de Outubro de 2022 eu visitei o &lt;a href=&quot;https://twitter.com/phpsp/&quot; title=&quot;https://twitter.com/phpsp/&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;PHPSP + Pub&lt;/a&gt;, um bar cheio de devs e pessoas interessadas em tecnologia, e &lt;strong data-renderer-mark=&quot;true&quot;&gt;perguntei pra todo mundo no evento: qual podcast de tecnologia você está ouvindo?&lt;/strong&gt;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;356&quot;&gt;Esta é a lista dos 12 podcasts mais citados!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;402&quot;&gt;Ao fim também adicionei um &lt;strong&gt;bônus de 4 podcasts em inglês&lt;/strong&gt; que a turma citou, vem comigo!&lt;/p&gt;
&lt;div class=&quot;post__toc&quot;&gt;
&lt;h3&gt;Table of Contents&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#Por-que-ouvir-podcasts-de-tecnologia-em-2023?&quot;&gt;Por que ouvir podcasts de tecnologia em 2023?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Podcasts-de-tecnologia-em-português-para-ouvir-em-2023&quot;&gt;Podcasts de tecnologia em português para ouvir em 2023&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#Feministech-podcast&quot;&gt;Feministech podcast&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#QuebraDev&quot;&gt;QuebraDev&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Mlkda-da-deepweb&quot;&gt;Mlkda da deepweb&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Devnaestrada&quot;&gt;Devnaestrada&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Castálio-podcast&quot;&gt;Castálio podcast&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Hipsters.tech&quot;&gt;Hipsters.tech&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Lambda3-podcast&quot;&gt;Lambda3 podcast&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#P-de-Podcast&quot;&gt;P de Podcast&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Café-debug&quot;&gt;Café debug&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Devs-Cansados&quot;&gt;Devs Cansados&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#PodProgramar&quot;&gt;PodProgramar&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Tecnocast&quot;&gt;Tecnocast&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Bonus:-podcasts-de-tecnologia-em-inglês&quot;&gt;Bonus: podcasts de tecnologia em inglês&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#The-array-cast&quot;&gt;The array cast&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#PHP-Roundtable&quot;&gt;PHP Roundtable&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#PHPUgly&quot;&gt;PHPUgly&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1gv0mlcbj4&quot;&gt;SudoShow&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id=&quot;Por-que-ouvir-podcasts-de-tecnologia-em-2023?&quot; data-renderer-start-pos=&quot;492&quot;&gt;Por que ouvir podcasts de programação e tecnologia em 2023?&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;539&quot;&gt;O mercado de desenvolvimento de software vem mudando muito desde… sempre! E em 2023 o contexto é muito interessante no mundo todo, mas principalmente no Brasil:&lt;/p&gt;
&lt;ul&gt;
&lt;li data-renderer-start-pos=&quot;539&quot;&gt;um &lt;a href=&quot;https://pt.wikipedia.org/wiki/Ex%C3%A9rcito_industrial_de_reserva&quot; title=&quot;https://pt.wikipedia.org/wiki/Ex%C3%A9rcito_industrial_de_reserva&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;exército de reserva&lt;/a&gt; cada vez maior e menos qualificado – com muitas pessoas iniciantes se lançando no mercado ou fazendo a transição de carreira ao mesmo tempo;&lt;/li&gt;
&lt;li data-renderer-start-pos=&quot;539&quot;&gt;uma &lt;a href=&quot;https://clickpetroleoegas.com.br/grandes-empresas-anunciam-demissao-em-massa-no-comeco-de-2023-e-mercado-fica-preocupado-ao-que-pode-acontecer-com-a-economia-brasileira/&quot; title=&quot;https://clickpetroleoegas.com.br/grandes-empresas-anunciam-demissao-em-massa-no-comeco-de-2023-e-mercado-fica-preocupado-ao-que-pode-acontecer-com-a-economia-brasileira/&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;onda de demissões em massa&lt;/a&gt; de startups e empresas que têm, na maioria dos casos, um saldo positivo;&lt;/li&gt;
&lt;li data-renderer-start-pos=&quot;539&quot;&gt;emigração de profissionais de tecnologia mais qualificados para o exterior em busca de salários em moeda forte&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-renderer-start-pos=&quot;1068&quot;&gt;Por conta destes motivos acima citados e outros, existe uma tendência ainda maior da precarização do trabalho, rebaixamento de salários e qualidade dos serviços de tecnologia prestados no Brasil. Ao mesmo tempo, oportunidades de crescimento para quem já tem algum conhecimento prévio vão surgir cada vez mais.&lt;/p&gt;
&lt;div class=&quot;ak-editor-panel css-431guk&quot; data-panel-type=&quot;custom&quot; data-panel-color=&quot;#E3FCEF&quot; data-panel-icon=&quot;:info:&quot; data-panel-icon-id=&quot;atlassian-info&quot;&gt;
&lt;div class=&quot;ak-editor-panel__content&quot;&gt;
&lt;p class=&quot;msg msg--highlight  msg--success&quot; data-renderer-start-pos=&quot;1380&quot;&gt;Ouvir podcasts de programação e tecnologia vai te ajudar a entender o que está acontecendo no mercado brasileiro de desenvolvimento de software em 2023, mas também a identificar oportunidades e quais caminhos seguir para surfar neste cenário da melhor forma possível.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-renderer-start-pos=&quot;1611&quot;&gt;Além disso, o podcast é uma forma de mídia que você pode carregar consigo e ouvir a qualquer momento: no ônibus, no metrô, andando de bicicleta, no carro ou onde for. &lt;strong data-renderer-mark=&quot;true&quot;&gt;O podcast uma ótima forma de aprender e se atualizar para quem gasta horas em comutação entre casa e escola ou trabalho.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;Podcasts-de-tecnologia-em-português-para-ouvir-em-2023&quot; data-renderer-start-pos=&quot;1900&quot;&gt;Podcasts de programação em português para ouvir em 2023&lt;/h2&gt;
&lt;h3 id=&quot;Feministech-podcast&quot; data-renderer-start-pos=&quot;1956&quot;&gt;Feministech podcast&lt;/h3&gt;
&lt;figure class=&quot;post__image post__image--left&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image&quot; src=&quot;/media/posts/60/podcast-feministech.jpg&quot; alt=&quot;Logo do podcast Feministech&quot; width=&quot;225&quot; height=&quot;225&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Feministech&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;1980&quot;&gt;A Feministech é uma &lt;a href=&quot;https://codamos.com.br/comunidades-de-desenvolvimento-de-software-brasileiras/&quot; title=&quot;https://codamos.com.br/comunidades-de-desenvolvimento-de-software-brasileiras/&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;comunidade desenvolvimento de software&lt;/a&gt; formada por pessoas que se identificam como pessoas femininas ou não-bináries. Essa galera é MUITO BRABA e produz conteúdo gratuito e de qualidade em diferentes plataformas como a twitch, dev.to, instagram e youtube.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2257&quot;&gt;Desde Maio de 2021 essa comunidade toca o &lt;strong data-renderer-mark=&quot;true&quot;&gt;Feministech Podcast que traz episódios relacionados a tecnologia e desenvolvimento de software, programação, carreira, comunidades, universidade, estudos e bastante entrevistas com gente muito qualificada!&lt;/strong&gt;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2493&quot;&gt;O Feministech Podcast está disponível no &lt;a href=&quot;https://open.spotify.com/show/5C1LL8H7iFCmUCoEmGJkd5&quot; title=&quot;https://open.spotify.com/show/5C1LL8H7iFCmUCoEmGJkd5&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Spotify&lt;/a&gt;, &lt;a href=&quot;https://podcasts.google.com/feed/aHR0cHM6Ly9hbmNob3IuZm0vcy81OTZhZjNmYy9wb2RjYXN0L3Jzcw==&quot; title=&quot;https://podcasts.google.com/feed/aHR0cHM6Ly9hbmNob3IuZm0vcy81OTZhZjNmYy9wb2RjYXN0L3Jzcw==&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Google Podcasts,&lt;/a&gt; &lt;a href=&quot;https://anchor.fm/feministech&quot; title=&quot;https://anchor.fm/feministech&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Anchor FM&lt;/a&gt; e também via &lt;a href=&quot;https://anchor.fm/s/596af3fc/podcast/rss&quot; title=&quot;https://anchor.fm/s/596af3fc/podcast/rss&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;RSS&lt;/a&gt;!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2493&quot;&gt;Você também pode acessar &lt;a href=&quot;https://feministech.com.br/&quot; rel=&quot;nofollow&quot;&gt;o site oficial&lt;/a&gt; para saber mais sobre o projeto que vai muito além dos podcasts.&lt;/p&gt;
&lt;h3 id=&quot;QuebraDev&quot; data-renderer-start-pos=&quot;2589&quot;&gt;QuebraDev&lt;/h3&gt;
&lt;figure class=&quot;post__image post__image--right&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/60/podcast-quebradev-2.jpg&quot; alt=&quot;Logo do podcast QuebraDev&quot; width=&quot;255&quot; height=&quot;255&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Quebradev&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;2603&quot;&gt;É simplesmente IMPOSSÍVEL falar de podcast de tecnologia brasileiros sem mencionar o Quebradev! Este podcast é perfeito de tantas formas que merece uma página só pra si! Mas vamos lá:&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2788&quot;&gt;QuebraDev é um podcast de origem periférica, que veio da quebrada e representa a comunidade dev da periferia. Os episódios falam sobre tecnologia, programação, estudos, política e tudo mais que faz parte do dia a dia da pessoa periférica. E tudo isso com uma estrutura super informal e convidativa. Até quem não está na área deveria escutar, este podcast é perfeito! &lt;span data-emoji-id=&quot;2764&quot; data-emoji-short-name=&quot;:heart:&quot; data-emoji-text=&quot;❤️&quot;&gt;&lt;span class=&quot;emoji-common-main-styles emoji-common-node   emoji-common-emoji-image  css-1np3glt&quot; title=&quot;:heart:&quot; data-testid=&quot;image-emoji-:heart:&quot; data-emoji-type=&quot;image&quot; aria-label=&quot;:heart:&quot;&gt;&lt;img class=&quot;emoji&quot; src=&quot;https://pf-emoji-service--cdn.us-east-1.prod.public.atl-paas.net/standard/caa27a19-fc09-4452-b2b4-a301552fd69c/64x64/2764.png&quot; alt=&quot;:heart:&quot; width=&quot;20&quot; height=&quot;20&quot; loading=&quot;lazy&quot; data-emoji-short-name=&quot;:heart:&quot; data-emoji-id=&quot;2764&quot; data-emoji-text=&quot;❤️&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3158&quot;&gt;O QuebraDev tá no &lt;a href=&quot;https://open.spotify.com/show/1NT08wgK2hTh27mvMiVszh&quot; title=&quot;https://open.spotify.com/show/1NT08wgK2hTh27mvMiVszh&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Spotify,&lt;/a&gt; &lt;a href=&quot;https://podcasts.apple.com/br/podcast/quebradev/id1385870497&quot; title=&quot;https://podcasts.apple.com/br/podcast/quebradev/id1385870497&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Apple Podcasts&lt;/a&gt; e via &lt;a href=&quot;https://anchor.fm/s/1c1d0328/podcast/rss&quot; title=&quot;https://anchor.fm/s/1c1d0328/podcast/rss&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;RSS&lt;/a&gt;!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3212&quot;&gt;Você também pode acessar &lt;a href=&quot;https://quebra.dev/&quot; title=&quot;https://quebra.dev/&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;o site oficial&lt;/a&gt; para listar os episódios e saber mais sobre o projeto.&lt;/p&gt;
&lt;h3 id=&quot;Mlkda-da-deepweb&quot; data-renderer-start-pos=&quot;3308&quot;&gt;Mlkda da deepweb&lt;/h3&gt;
&lt;figure class=&quot;post__image post__image--left&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/60/podcast-mlkda-da-deepweb-2.jpg&quot; alt=&quot;Logo do podcast Mlkda da Deepweb&quot; width=&quot;225&quot; height=&quot;225&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Mlkda da deepweb&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;3329&quot;&gt;O podcast Mlkda da DeepWeb (molecada da deepweb) nasceu em Janeiro de 2021 e já tem mais de 33 episódios.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3436&quot;&gt;Você pode acessar o catálogo de episódios na plataforma &lt;a href=&quot;https://dev.to/mlkdadeepweb&quot; title=&quot;https://dev.to/mlkdadeepweb&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;dev.to&lt;/a&gt; e também no &lt;a href=&quot;https://anchor.fm/mlkda-da-deepweb/&quot; title=&quot;https://anchor.fm/mlkda-da-deepweb/&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Anchor FM&lt;/a&gt;. Este podcast tem bastante entrevistas com diferentes pessoas conhecidas na comunidade brasileira de desenvolvimento como o Gabs Ferreira, PokémãoBR e PachiCodes.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3685&quot;&gt;O podcast Mlkda da DeepWeb está disponível no &lt;a href=&quot;https://open.spotify.com/show/3yNzmQH8cEgm1sLzb4E4G9&quot; title=&quot;https://open.spotify.com/show/3yNzmQH8cEgm1sLzb4E4G9&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Spotify&lt;/a&gt;, &lt;a href=&quot;https://www.google.com/podcasts?feed=aHR0cHM6Ly9hbmNob3IuZm0vcy80ODAyMGVjMC9wb2RjYXN0L3Jzcw==&quot; title=&quot;https://www.google.com/podcasts?feed=aHR0cHM6Ly9hbmNob3IuZm0vcy80ODAyMGVjMC9wb2RjYXN0L3Jzcw==&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Google Podcasts&lt;/a&gt;, &lt;a href=&quot;https://anchor.fm/mlkda-da-deepweb/&quot; title=&quot;https://anchor.fm/mlkda-da-deepweb/&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Anchor FM&lt;/a&gt; e também via &lt;a href=&quot;https://anchor.fm/s/48020ec0/podcast/rss&quot; title=&quot;https://anchor.fm/s/48020ec0/podcast/rss&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;RSS&lt;/a&gt;!&lt;/p&gt;
&lt;h3 id=&quot;Devnaestrada&quot; data-renderer-start-pos=&quot;3786&quot;&gt;Devnaestrada&lt;/h3&gt;
&lt;figure class=&quot;post__image post__image--right&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/60/podcast-devnaestrada-2.jpg&quot; alt=&quot;Logo do podcast DevNaEstrada&quot; width=&quot;255&quot; height=&quot;255&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;DevNaEstrada&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;3803&quot;&gt;O podcast DEVNAESTRADA já tem mais de 360 episódios e lança um episódio novo toda sexta-feira.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3803&quot;&gt;Essa galera faz episódios com entrevistas, eventos, notícias e discussões sobre desenvolvimento web.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3803&quot;&gt;DEVNAESTRADA está disponível no &lt;a href=&quot;https://open.spotify.com/show/1yQ2qrscxoTmdUvZgMoY4a&quot; title=&quot;https://open.spotify.com/show/1yQ2qrscxoTmdUvZgMoY4a&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Spotify&lt;/a&gt;, &lt;a href=&quot;https://podcasts.apple.com/br/podcast/devnaestrada/id997779431&quot; title=&quot;https://podcasts.apple.com/br/podcast/devnaestrada/id997779431&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Apple Podcasts&lt;/a&gt;, &lt;a href=&quot;https://www.deezer.com/show/944902&quot; title=&quot;https://www.deezer.com/show/944902&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Deezer&lt;/a&gt; e também via &lt;a href=&quot;https://devnaestrada.com.br/feed.xml&quot; title=&quot;https://devnaestrada.com.br/feed.xml&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;RSS&lt;/a&gt;! Também tem &lt;a href=&quot;https://devnaestrada.com.br/&quot; title=&quot;https://devnaestrada.com.br/&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;o site oficial&lt;/a&gt; para quem quiser saber mais.&lt;/p&gt;
&lt;h3 id=&quot;Castálio-podcast&quot; data-renderer-start-pos=&quot;4139&quot;&gt;Castálio podcast&lt;/h3&gt;
&lt;figure class=&quot;post__image post__image--left&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/60/podcast-castalio-podcast.jpg&quot; alt=&quot;Logo do podcast Castálio Podacast&quot; width=&quot;225&quot; height=&quot;225&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Castálio podcast&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;4160&quot;&gt;O Castálio podcast é um “Podcast inspirado prá castálio”, que começou em 2011 e que fala sobre tecnologia, desenvolvimento de software, linguagens de programação e código aberto.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;4340&quot;&gt;O bacana deste podcast é que ele tem vários episódios temáticos e mais de 150 episódios disponíveis. São discussões, entrevistas e uma visão de dentro das comunidades de software.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;4521&quot;&gt;Outro diferencial deste podcast é que ele conta com alguns episódios em inglês – o que é ótimo para quem quer praticar.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;4642&quot;&gt;O Castálio Podcast está disponível no &lt;a href=&quot;https://open.spotify.com/show/5wR7497LQwCIDbCsdNhXVn&quot; title=&quot;https://open.spotify.com/show/5wR7497LQwCIDbCsdNhXVn&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Spotify&lt;/a&gt; e via &lt;a href=&quot;http://feeds.feedburner.com/CastalioPodcastMP3&quot; title=&quot;http://feeds.feedburner.com/CastalioPodcastMP3&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;RSS&lt;/a&gt;! Você também pode conferir &lt;a href=&quot;https://castalio.info/&quot; title=&quot;https://castalio.info/&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;o site oficial&lt;/a&gt; para descobrir mais.&lt;/p&gt;
&lt;h3 id=&quot;Hipsters.tech&quot; data-renderer-start-pos=&quot;4762&quot;&gt;Hipsters.tech&lt;/h3&gt;
&lt;figure class=&quot;post__image post__image--right&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/60/podcasts-hipsters-ponto-tech-2.jpg&quot; alt=&quot;Logo do podcast Hipsters ponto Tech&quot; width=&quot;255&quot; height=&quot;255&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Hipsters ponto tech&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;4780&quot;&gt;O Hipsters ponto tech já é bem famosinho e provavelmente qualquer dev que conhece podcasts já ouviu ou ouviu falar do Hipsters ponto tech.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;4920&quot;&gt;Este podcast é mantido e apresentado pela galera da Alura e da Caelum e seus episódios são entrevistas e discussões sobre programação, design, experiência de usuário, startups e tudo que está bombando na área de tecnologia.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;5145&quot;&gt;O Hipsters ponto tech está disponível no &lt;a href=&quot;https://open.spotify.com/show/2p0Vx75OmfsXktyLBuLuSf&quot; title=&quot;https://open.spotify.com/show/2p0Vx75OmfsXktyLBuLuSf&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Spotify&lt;/a&gt;, &lt;a href=&quot;https://www.google.com/podcasts?feed=aHR0cHM6Ly93d3cuaGlwc3RlcnMudGVjaC9mZWVkL3BvZGNhc3Qv&quot; title=&quot;https://www.google.com/podcasts?feed=aHR0cHM6Ly93d3cuaGlwc3RlcnMudGVjaC9mZWVkL3BvZGNhc3Qv&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Google Podcasts&lt;/a&gt; e via &lt;a href=&quot;https://www.hipsters.tech/feed/podcast/&quot; title=&quot;https://www.hipsters.tech/feed/podcast/&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;RSS&lt;/a&gt;!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;5223&quot;&gt;Você também pode acessar &lt;a href=&quot;https://www.hipsters.tech/&quot; title=&quot;https://www.hipsters.tech/&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;o site oficial&lt;/a&gt; para navegar os episódios e saber mais.&lt;/p&gt;
&lt;h3 id=&quot;Lambda3-podcast&quot; data-renderer-start-pos=&quot;5304&quot;&gt;Lambda3 podcast&lt;/h3&gt;
&lt;figure class=&quot;post__image post__image--left&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/60/podcast-lambda3.jpg&quot; alt=&quot;Logo do podcast Lambda3&quot; width=&quot;225&quot; height=&quot;225&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Lambda3 podcast&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;5324&quot;&gt;O podcast Lambda3 é um dos produtos que a empresa Lambda3, uma &lt;em data-renderer-mark=&quot;true&quot;&gt;venture&lt;/em&gt; da TIVIT, oferece.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;5415&quot;&gt;Neste podcast você ouve sobre tecnologia, programação e tecnicas e práticas de desenvolvimento.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;5512&quot;&gt;O Lambda3 está disponível no &lt;a href=&quot;https://lb3.io/spotify-site&quot; title=&quot;https://lb3.io/spotify-site&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Spotify&lt;/a&gt;, &lt;a href=&quot;https://lb3.io/apple-podcasts-site&quot; title=&quot;https://lb3.io/apple-podcasts-site&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Apple Podcasts&lt;/a&gt; e &lt;a href=&quot;https://lb3.io/google-podcast-site&quot; title=&quot;https://lb3.io/google-podcast-site&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Google Podcasts&lt;/a&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;5512&quot;&gt; &lt;/p&gt;
&lt;h3 id=&quot;P-de-Podcast&quot; data-renderer-start-pos=&quot;5585&quot;&gt;P de Podcast&lt;/h3&gt;
&lt;figure class=&quot;post__image post__image--right&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/60/podcast-p-de-podcast-2.jpg&quot; alt=&quot;Logo do podcast P de Podcast&quot; width=&quot;225&quot; height=&quot;225&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;P de Podcast&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;5602&quot;&gt;P de Podcast é um podcast focado em arquitetura de software, boas práticas e outros temas relacionados ao ciclo de desenvolvimento de software.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;5747&quot;&gt;Este projeto é parte do &lt;a href=&quot;https://segunda.tech/sobre/&quot; title=&quot;https://segunda.tech/sobre/&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;segunda.tech&lt;/a&gt; e começou a publicar episódios desde 2020.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;5828&quot;&gt;P de Podcast está disponível no &lt;a href=&quot;https://open.spotify.com/show/1g20eCicNnqRoWlObOLZ3k&quot; title=&quot;https://open.spotify.com/show/1g20eCicNnqRoWlObOLZ3k&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Spotify&lt;/a&gt;, &lt;a href=&quot;https://podcasts.apple.com/br/podcast/p-de-podcast/id1523873163&quot; title=&quot;https://podcasts.apple.com/br/podcast/p-de-podcast/id1523873163&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Apple Podcasts&lt;/a&gt;, &lt;a href=&quot;https://www.google.com/podcasts?feed=aHR0cHM6Ly9hbmNob3IuZm0vcy8yYzJjZTRmNC9wb2RjYXN0L3Jzcw==&quot; title=&quot;https://www.google.com/podcasts?feed=aHR0cHM6Ly9hbmNob3IuZm0vcy8yYzJjZTRmNC9wb2RjYXN0L3Jzcw==&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Google Podcasts&lt;/a&gt; e via &lt;a href=&quot;https://anchor.fm/s/2c2ce4f4/podcast/rss&quot; title=&quot;https://anchor.fm/s/2c2ce4f4/podcast/rss&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;RSS&lt;/a&gt;!&lt;/p&gt;
&lt;h3 id=&quot;Café-debug&quot; data-renderer-start-pos=&quot;5913&quot;&gt;Café debug&lt;/h3&gt;
&lt;figure class=&quot;post__image post__image--left&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/60/podcast-cafe-debug.jpg&quot; alt=&quot;Logo do podcast Café Debug&quot; width=&quot;225&quot; height=&quot;225&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Café Debug&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;5928&quot;&gt;O Café Debug já está na ativa desde 2017 e fala sobre vários temas diferentes na área de tecnologia como linguagens de programação, tecnicas e princípios, diversidade e inclusão, código aberto e faz várias entrevistas interessantíssimas!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;6167&quot;&gt;Este podcast também é bem descontraído e traz conteúdo de altíssima qualidade 💚&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;6249&quot;&gt;Café Debug está disponível no &lt;a href=&quot;https://open.spotify.com/show/3uqyj3GlhBHp1IJN8KJ1xU&quot; title=&quot;https://open.spotify.com/show/3uqyj3GlhBHp1IJN8KJ1xU&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Spotify&lt;/a&gt; e você também pode acessar o &lt;a href=&quot;https://cafedebug.com.br/&quot; title=&quot;https://cafedebug.com.br/&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;site oficial&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;Devs-Cansados&quot; data-renderer-start-pos=&quot;6331&quot;&gt;Devs Cansados&lt;/h3&gt;
&lt;figure class=&quot;post__image post__image--right&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/60/podcast-devs-cansados-2.jpg&quot; alt=&quot;Logo do podcast Devs Cansados&quot; width=&quot;225&quot; height=&quot;225&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Devs Cansados&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;6349&quot;&gt;O nome é bom demais né? 😂&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;6377&quot;&gt;Este podcast é uma jóia da podosfera brasileira! Seus episódios falam de programação, claro, mas também de histórias cabeludas, perrengues, amores e desamores com a carreira de programação.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;6568&quot;&gt;Devs Cansados está disponível no &lt;a href=&quot;https://open.spotify.com/show/7gNryNpuHuhZTwfbCdiOqL&quot; title=&quot;https://open.spotify.com/show/7gNryNpuHuhZTwfbCdiOqL&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Spotify&lt;/a&gt;, &lt;a href=&quot;https://www.google.com/podcasts?feed=aHR0cHM6Ly9hbmNob3IuZm0vcy9jOTQ2YzIwL3BvZGNhc3QvcnNz&quot; title=&quot;https://www.google.com/podcasts?feed=aHR0cHM6Ly9hbmNob3IuZm0vcy9jOTQ2YzIwL3BvZGNhc3QvcnNz&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Google Podcasts&lt;/a&gt;, &lt;a href=&quot;https://podcasts.apple.com/us/podcast/devs-cansados/id1472552309&quot; title=&quot;https://podcasts.apple.com/us/podcast/devs-cansados/id1472552309&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Apple Podcasts&lt;/a&gt; e via &lt;a href=&quot;https://anchor.fm/s/c946c20/podcast/rss&quot; title=&quot;https://anchor.fm/s/c946c20/podcast/rss&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;RSS&lt;/a&gt;!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;6654&quot;&gt;Você também pode acessar &lt;a href=&quot;https://www.devscansados.com.br/&quot; title=&quot;https://www.devscansados.com.br/&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;o site oficial&lt;/a&gt; para saber mais sobre o projeto.&lt;/p&gt;
&lt;h3 id=&quot;PodProgramar&quot; data-renderer-start-pos=&quot;6728&quot;&gt;PodProgramar&lt;/h3&gt;
&lt;figure class=&quot;post__image post__image--left&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/60/podcast-pod-programar.jpg&quot; alt=&quot;Logo do podcast PodProgramar&quot; width=&quot;225&quot; height=&quot;225&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;PodProgramar&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;6745&quot;&gt;O PodProgramar está na ativa desde 2016 e fala sobre desenvolvimento de software em geral. Trás consigo discussões, notícias, dicas e truques e tudo isso trazendo pros episódios um toque de diversidade importantíssimo!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;6965&quot;&gt;PodProgramar está disponível no &lt;a href=&quot;https://open.spotify.com/show/16ZtU9p6Pja5H87W35owjY&quot; title=&quot;https://open.spotify.com/show/16ZtU9p6Pja5H87W35owjY&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Spotify&lt;/a&gt;, &lt;a href=&quot;https://www.google.com/podcasts?feed=aHR0cHM6Ly9wb2Rwcm9ncmFtYXIuY29tLmJyL2ZlZWQvcG9kY2FzdC8&quot; title=&quot;https://www.google.com/podcasts?feed=aHR0cHM6Ly9wb2Rwcm9ncmFtYXIuY29tLmJyL2ZlZWQvcG9kY2FzdC8&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Google Podcasts&lt;/a&gt;, &lt;a href=&quot;https://itunes.apple.com/podcast/podprogramar-mundo-podcast/id1129404763?mt=2&amp;amp;ls=1&quot; title=&quot;https://itunes.apple.com/podcast/podprogramar-mundo-podcast/id1129404763?mt=2&amp;amp;ls=1&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Apple Podcasts&lt;/a&gt; e também via &lt;a href=&quot;https://podprogramar.com.br/feed/podcast/&quot; title=&quot;https://podprogramar.com.br/feed/podcast/&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;RSS&lt;/a&gt;!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;7057&quot;&gt;Você também pode acessar &lt;a href=&quot;https://podprogramar.com.br/&quot; title=&quot;https://podprogramar.com.br/&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;o site oficial&lt;/a&gt; para saber mais sobre o projeto.&lt;/p&gt;
&lt;h3 id=&quot;Tecnocast&quot; data-renderer-start-pos=&quot;7131&quot;&gt;Tecnocast&lt;/h3&gt;
&lt;figure class=&quot;post__image post__image--right&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/60/podcast-tecnocast-2.jpg&quot; alt=&quot;Logo do podcast Tecnocast&quot; width=&quot;225&quot; height=&quot;225&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Tecnocast&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;7145&quot;&gt;Menos focado em desenvolvimento de software e mais focado em tecnologia da informação, o Tecnocast é um podcast bem massinha pra você dev que tá precisando descontrair e relaxar a mente.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;7333&quot;&gt;Tecnocast está disponível no &lt;a href=&quot;https://open.spotify.com/show/084hQAwpMi4PcidWPsO2fY&quot; title=&quot;https://open.spotify.com/show/084hQAwpMi4PcidWPsO2fY&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Spotify&lt;/a&gt;, &lt;a href=&quot;https://podcasts.google.com/feed/aHR0cHM6Ly90ZWNub2Jsb2cubmV0L3RlY25vY2FzdC1mZWVkLw&quot; title=&quot;https://podcasts.google.com/feed/aHR0cHM6Ly90ZWNub2Jsb2cubmV0L3RlY25vY2FzdC1mZWVkLw&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Google Podcasts&lt;/a&gt;, &lt;a href=&quot;https://podcasts.apple.com/br/podcast/tecnocast/id505204037&quot; title=&quot;https://podcasts.apple.com/br/podcast/tecnocast/id505204037&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Apple Podcasts&lt;/a&gt; e via &lt;a href=&quot;https://feeds.buzzsprout.com/2048054.rss&quot; title=&quot;https://feeds.buzzsprout.com/2048054.rss&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;RSS&lt;/a&gt;!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;7415&quot;&gt;Você também pode acessar &lt;a href=&quot;https://tecnoblog.net/tecnocast/&quot; title=&quot;https://tecnoblog.net/tecnocast/&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;o site oficial&lt;/a&gt; para saber mais.&lt;/p&gt;
&lt;h2 id=&quot;Bonus:-podcasts-de-tecnologia-em-inglês&quot; data-renderer-start-pos=&quot;7473&quot;&gt;Bonus: podcasts de tecnologia em inglês&lt;/h2&gt;
&lt;h3 id=&quot;The-array-cast&quot; data-renderer-start-pos=&quot;7514&quot;&gt;The array cast&lt;/h3&gt;
&lt;figure class=&quot;post__image post__image--left&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/60/podcast-array-cast.jpg&quot; alt=&quot;Logo do podcast The Array Cast&quot; width=&quot;225&quot; height=&quot;225&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;The Array Cast&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;7533&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;The Array Cast&lt;/em&gt; é um podcast sobre &lt;a href=&quot;https://en.wikipedia.org/wiki/Array_programming&quot; title=&quot;https://en.wikipedia.org/wiki/Array_programming&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;linguagens de programação orientadas a arrays&lt;/a&gt; – como &lt;a href=&quot;https://aplwiki.com/&quot; title=&quot;https://aplwiki.com/&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;APL&lt;/a&gt;, &lt;a href=&quot;https://code.jsoftware.com/wiki/Guides/Getting_Started&quot; title=&quot;https://code.jsoftware.com/wiki/Guides/Getting_Started&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;J&lt;/a&gt;, &lt;a href=&quot;https://code.kx.com/q/&quot; title=&quot;https://code.kx.com/q/&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;q&lt;/a&gt; e &lt;a href=&quot;https://k.miraheze.org/wiki/Learning_Resources&quot; title=&quot;https://k.miraheze.org/wiki/Learning_Resources&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;k&lt;/a&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;7636&quot;&gt;É um podcast bem nichado e não se aplica a tooodas as linguagens de programação. Mas com certeza você vai aprender MUITO sobre teoria de linguagens de programação e toda a matemática e poesia por trás das tecnicas e decisões de design das linguagens.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;7888&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;The Array Cast&lt;/em&gt; está disponível no &lt;a href=&quot;https://open.spotify.com/show/6DmSM7g050IczwljhP7nJC&quot; title=&quot;https://open.spotify.com/show/6DmSM7g050IczwljhP7nJC&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Spotify&lt;/a&gt; e via &lt;a href=&quot;https://arraycast.com/episodes?format=rss&quot; title=&quot;https://arraycast.com/episodes?format=rss&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;RSS&lt;/a&gt;!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;7942&quot;&gt;Você também pode acessar &lt;a href=&quot;https://www.arraycast.com/&quot; title=&quot;https://www.arraycast.com/&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;o site oficial&lt;/a&gt; para saber mais.&lt;/p&gt;
&lt;h3 id=&quot;PHP-Roundtable&quot; data-renderer-start-pos=&quot;8000&quot;&gt;PHP Roundtable&lt;/h3&gt;
&lt;figure class=&quot;post__image post__image--right&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/60/podcast-php-roundable-2.jpg&quot; alt=&quot;Logo do podcast PHPRoundtable&quot; width=&quot;225&quot; height=&quot;225&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;PHPRoundtable&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;8019&quot;&gt;O &lt;em data-renderer-mark=&quot;true&quot;&gt;PHP Roundtable&lt;/em&gt; é uma mesa redonda onde todas as pessoas presentes são tratadas como iguais: não importa se você tem 20 anos de experiência com PHP, está apenas começando ou é dev JS: todo mundo tem como contribuir para a evolução da linguagem PHP!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;8270&quot;&gt;Neste podcast as pessoas convidadas falam sobre a linguagem, &lt;em data-renderer-mark=&quot;true&quot;&gt;frameworks&lt;/em&gt;, tecnicas de aprendizado, emprego e tudo mais que possa interessar quem programa ou deseja programar PHP.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;8449&quot;&gt;O &lt;em data-renderer-mark=&quot;true&quot;&gt;PHP Roundtable&lt;/em&gt; está disponível no &lt;a href=&quot;https://open.spotify.com/show/2O1yKViyYoaMNeFaGdezEE&quot; title=&quot;https://open.spotify.com/show/2O1yKViyYoaMNeFaGdezEE&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Spotify&lt;/a&gt;, no &lt;a href=&quot;https://www.youtube.com/@PHPRoundtable&quot; title=&quot;https://www.youtube.com/@PHPRoundtable&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;YouTube&lt;/a&gt; e via &lt;a href=&quot;https://feeds.simplecast.com/sREPxPje&quot; title=&quot;https://feeds.simplecast.com/sREPxPje&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;RSS&lt;/a&gt;!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;8517&quot;&gt;Você também pode acessar &lt;a href=&quot;https://phproundtable.com/&quot; title=&quot;https://phproundtable.com/&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;o site oficial&lt;/a&gt; para saber mais.&lt;/p&gt;
&lt;h3 id=&quot;PHPUgly&quot; data-renderer-start-pos=&quot;8575&quot;&gt;PHPUgly&lt;/h3&gt;
&lt;figure class=&quot;post__image post__image--left&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/60/podcast-php-ugly.jpg&quot; alt=&quot;Logo do podcast PHPUgly&quot; width=&quot;225&quot; height=&quot;225&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;PHPUgly&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;8587&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;PHPUgly&lt;/em&gt; é um podcast sensacional, feito por alguns desenvolvedores PHP cansados que se reunem pra falar e reclamar de diversos tópicos: a linguagem, problemas que encontraram nas últimas semanas, seus pequenos negócios e por aí vai.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;8821&quot;&gt;Os episódios são conversas bem descontraídas e sempre têm algo a ensinar.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;8896&quot;&gt;O &lt;em data-renderer-mark=&quot;true&quot;&gt;PHPUgly&lt;/em&gt; está disponível no &lt;a href=&quot;https://open.spotify.com/show/1rmuLOaapKfFz4K03zBN4O&quot; title=&quot;https://open.spotify.com/show/1rmuLOaapKfFz4K03zBN4O&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Spotify&lt;/a&gt;, &lt;a href=&quot;https://itunes.apple.com/us/podcast/phpugly/id1093659401?mt=2&quot; title=&quot;https://itunes.apple.com/us/podcast/phpugly/id1093659401?mt=2&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Apple Podcasts&lt;/a&gt; e via &lt;a href=&quot;https://feeds.simplecast.com/iYRiH9ym&quot; title=&quot;https://feeds.simplecast.com/iYRiH9ym&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;RSS&lt;/a&gt;!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;8961&quot;&gt;Você também pode acessar &lt;a href=&quot;https://www.phpugly.com/&quot; title=&quot;https://www.phpugly.com/&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;o site oficial&lt;/a&gt; para saber mais.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1gv0mlcbj4&quot; data-renderer-start-pos=&quot;8961&quot;&gt;SudoShow&lt;/h3&gt;
&lt;figure class=&quot;post__image post__image--right&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/60/podcast-sudo-show-2.jpg&quot; alt=&quot;Logo do podcast SudoShow&quot; width=&quot;225&quot; height=&quot;225&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;SudoShow&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;9032&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;SudoShow&lt;/em&gt; é um podcast que fala sobre Código Aberto e Livre (&lt;em data-renderer-mark=&quot;true&quot;&gt;Open Source&lt;/em&gt;) em ambiente de negócios, gerenciamento de Nuvem (Cloud), &lt;em data-renderer-mark=&quot;true&quot;&gt;DevOps&lt;/em&gt;, times e cultura de empresas.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;9200&quot;&gt;Neste podcast você encontra analises, entrevistas e discussões.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;9265&quot;&gt;Você pode ouvir o &lt;em data-renderer-mark=&quot;true&quot;&gt;SudoShow&lt;/em&gt; no &lt;a href=&quot;https://open.spotify.com/show/7LRQhCQX5SeTgVqYX6QUQV&quot; title=&quot;https://open.spotify.com/show/7LRQhCQX5SeTgVqYX6QUQV&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Spotify&lt;/a&gt;, &lt;a href=&quot;https://podcasts.apple.com/us/podcast/sudo-show/id1519282435&quot; title=&quot;https://podcasts.apple.com/us/podcast/sudo-show/id1519282435&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Apple Podcasts&lt;/a&gt;, &lt;a href=&quot;https://podcasts.google.com/feed/aHR0cHM6Ly9zdWRvLnNob3cvcnNz&quot; title=&quot;https://podcasts.google.com/feed/aHR0cHM6Ly9zdWRvLnNob3cvcnNz&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Google Podcasts&lt;/a&gt; e via &lt;a href=&quot;https://sudo.show/rss&quot; title=&quot;https://sudo.show/rss&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;RSS&lt;/a&gt;!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;9348&quot;&gt;Você também pode acessar &lt;a href=&quot;https://sudo.show/&quot; title=&quot;https://sudo.show/&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;o site oficial&lt;/a&gt; para saber mais.&lt;/p&gt;
&lt;/div&gt;</content:encoded><category>carreira</category><category>podcast</category><category>produtividade</category></item><item><title>Como fazer um commit vazio no Git, Github ou Gitlab</title><link>https://codamos.com.br/como-fazer-um-commit-vazio-no-git-github-ou-gitlab/</link><guid isPermaLink="true">https://codamos.com.br/como-fazer-um-commit-vazio-no-git-github-ou-gitlab/</guid><description>Sempre que você tenta fazer um git commit sem ter nenhum arquivo alterado, sua tentativa de commit vai ser rejeitada. Neste artigo você aprende como fazer! Para fazer um commit sem nenhum arquivo no g</description><pubDate>Mon, 16 Jan 2023 11:35:03 GMT</pubDate><content:encoded>&lt;p data-renderer-start-pos=&quot;4&quot;&gt;Sempre que você tenta fazer um &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;git commit&lt;/code&gt; sem ter nenhum arquivo alterado, sua tentativa de &lt;em data-renderer-mark=&quot;true&quot;&gt;commit&lt;/em&gt; vai ser rejeitada. Neste artigo você aprende como fazer!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;123&quot;&gt;Para fazer um commit sem nenhum arquivo no &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;git&lt;/code&gt; e subir este commit para o Github ou Gitlab, basta usar o seguinte comando:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;123&quot;&gt;$ git commit --allow-empty -m &apos;&amp;lt;SUA MENSAGEM DE COMMIT AQUI&amp;gt;&apos;&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;310&quot;&gt;A figura abaixo ilustra o comando e seu resultado:&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/59/git-commit-vazio-sem-arquivos-allow-empty.jpg&quot; alt=&quot;Criando um commit vazio com git commit --allow-empty&quot; width=&quot;1014&quot; height=&quot;79&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;css-lmzmsq&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;364&quot;&gt;Criando um commit vazio com &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;git commit --allow-empty&lt;/code&gt;&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/59/git-log-commit-vazio-sem-arquivos.jpg&quot; alt=&quot;Listagem de commits (git log) mostrando o novo commit vazio.&quot; width=&quot;763&quot; height=&quot;149&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;css-lmzmsq&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;421&quot;&gt;Listagem de commits (&lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;git log&lt;/code&gt;) mostrando o novo &lt;em data-renderer-mark=&quot;true&quot;&gt;commit&lt;/em&gt; vazio.&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;484&quot;&gt;Note que no comando acima utilizamos a flag &lt;a href=&quot;https://git-scm.com/docs/git-commit#Documentation/git-commit.txt---allow-empty&quot; title=&quot;https://git-scm.com/docs/git-commit#Documentation/git-commit.txt---allow-empty&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;--allow-empty&lt;/a&gt; da ferramenta Git. Esta flag é justamente o que nos permite criar um commit mesmo sem ter alterado nenhum arquivo.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;658&quot;&gt;A partir deste momento você pode subir seu commit normalmente, como ensinado no nosso &lt;a href=&quot;/subindo-arquivos-no-github/&quot;&gt;tutorial de como subir arquivos no Gtihub&lt;/a&gt;:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;658&quot;&gt;$ git push origin &amp;lt;NOME_DO_SEU_BRANCH&amp;gt;&lt;/pre&gt;
&lt;h2 id=&quot;Para-que-criar-commits-vazios?&quot; data-renderer-start-pos=&quot;828&quot;&gt;Para que criar commits vazios?&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;860&quot;&gt;Alguns times desenvolvimento usam ferramentas de automação como o &lt;a href=&quot;https://docs.gitlab.com/ee/ci/&quot; title=&quot;https://docs.gitlab.com/ee/ci/&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Gitlab CI/CD&lt;/a&gt;, &lt;a href=&quot;https://docs.github.com/en/actions&quot; title=&quot;https://docs.github.com/en/actions&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Github Actions&lt;/a&gt; ou &lt;a href=&quot;https://circleci.com/&quot; title=&quot;https://circleci.com/&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Circle CI&lt;/a&gt;. Estas ferramentas nos permitem realizar algumas tarefas quando uma alteração no nosso repositório acontece.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1078&quot;&gt;Por exemplo, podemos rodar testes unitários e de integração sempre que um &lt;em data-renderer-mark=&quot;true&quot;&gt;Pull Request&lt;/em&gt; for aberto, ou sempre que um novo commit chegar ao &lt;em data-renderer-mark=&quot;true&quot;&gt;branch&lt;/em&gt; principal. Algumas empresas e equipes até mesmo lançam o código para produção sempre que um novo &lt;em data-renderer-mark=&quot;true&quot;&gt;commit&lt;/em&gt; chega ao &lt;em data-renderer-mark=&quot;true&quot;&gt;branch&lt;/em&gt; principal, utilizando tecnicas como &lt;a href=&quot;https://www.martinfowler.com/bliki/ContinuousDelivery.html&quot; title=&quot;https://www.martinfowler.com/bliki/ContinuousDelivery.html&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;Continuous Delivery&lt;/em&gt;&lt;/a&gt; ou Entrega Contínua.&lt;/p&gt;
&lt;p class=&quot;msg msg--info&quot; data-renderer-start-pos=&quot;1078&quot;&gt;As vezes para testar estes mecanismos de automação, ou até mesmo para fazer com que rode novamente o mecanismo, é prático enviar um &lt;em data-renderer-mark=&quot;true&quot;&gt;commit&lt;/em&gt; vazio.&lt;/p&gt;</content:encoded><category>git</category><category>ferramentas</category><category>produtividade</category></item><item><title>Guia definitivo de arrays no PHP</title><link>https://codamos.com.br/guia-arrays-no-php/</link><guid isPermaLink="true">https://codamos.com.br/guia-arrays-no-php/</guid><description>O que é um array no PHP? array é um dos diversos tipos de dados que a linguagem PHP oferece. É uma forma de armazenar vários valores numa única variável. Numa única variável $numeros nós podemos armaz</description><pubDate>Mon, 02 Jan 2023 10:15:21 GMT</pubDate><content:encoded>&lt;h2 id=&quot;O-que-é-um-array-no-PHP?&quot; data-renderer-start-pos=&quot;7&quot;&gt;O que é um array no PHP?&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;33&quot;&gt;&lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;array&lt;/code&gt; é um dos diversos &lt;a href=&quot;/tipos-em-php/&quot;&gt;tipos de dados&lt;/a&gt; que a linguagem PHP oferece. É uma forma de armazenar vários valores numa única variável. Numa única variável &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$numeros&lt;/code&gt; nós podemos armazenar 5 números de uma vez só, como no exemplo a seguir:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;33&quot;&gt;/*&lt;br&gt; * A variável $numeros possui os 5 valores listados&lt;br&gt; * dentro dos colchetes: 4, 3, 2, 1 e 0.&lt;br&gt; */&lt;br&gt;$numeros = [4, 3, 2, 1, 0];&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;394&quot;&gt;Desta forma é possível acessar estes valores através da &lt;a href=&quot;https://www.php.net/manual/pt_BR/language.types.array.php#language.types.array.syntax.accessing&quot; title=&quot;https://www.php.net/manual/pt_BR/language.types.array.php#language.types.array.syntax.accessing&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;sintaxe de colchetes&lt;/a&gt;. Ainda considerando a variável &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$numeros&lt;/code&gt; que criamos acima, podemos acessar cada elemento como no trecho de código a seguir:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;394&quot;&gt;echo &quot;O segundo elemento é: &quot; . $numeros[1];&lt;br&gt;// O segundo elemento é: 3&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;669&quot;&gt;Note que o valor &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$numeros[1]&lt;/code&gt; faz referência ao segundo valor que colocamos entre colchetes ao criar a variável &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$numeros&lt;/code&gt;, o número inteiro 3.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;811&quot;&gt;De forma parecida a gente pode acessar o valor &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$numeros[0]&lt;/code&gt; (inteiro 4) ou &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$numero[3]&lt;/code&gt; (inteiro 1).&lt;/p&gt;
&lt;h2 id=&quot;O-array-do-PHP-é-mais-poderoso-que-o-de-outras-linguagens&quot; data-renderer-start-pos=&quot;910&quot;&gt;O &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;array&lt;/code&gt; do PHP é mais poderoso que o de outras linguagens&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;969&quot;&gt;É importante notar que o &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;array&lt;/code&gt; do PHP é muito mais flexível e poderoso do que em diversas outras linguagens, dada a natureza do sistema de tipos que o PHP oferece. Isto porque o &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;array&lt;/code&gt; do PHP pode se comportar como &lt;a href=&quot;https://www.inf.pucrs.br/~pinho/LaproI/Vetores/Vetores.htm&quot; title=&quot;https://www.inf.pucrs.br/~pinho/LaproI/Vetores/Vetores.htm&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;vetor&lt;/a&gt;, &lt;a href=&quot;https://mange.ifrn.edu.br/python/aprenda-com-py3/capitulo_08.html&quot; title=&quot;https://mange.ifrn.edu.br/python/aprenda-com-py3/capitulo_08.html&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;lista&lt;/a&gt;, &lt;a href=&quot;https://mange.ifrn.edu.br/python/aprenda-com-py3/capitulo_18.html&quot; title=&quot;https://mange.ifrn.edu.br/python/aprenda-com-py3/capitulo_18.html&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;pilha&lt;/a&gt;, &lt;a href=&quot;https://mange.ifrn.edu.br/python/aprenda-com-py3/capitulo_19.html&quot; title=&quot;https://mange.ifrn.edu.br/python/aprenda-com-py3/capitulo_19.html&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;fila&lt;/a&gt;, &lt;a href=&quot;https://mange.ifrn.edu.br/python/aprenda-com-py3/capitulo_09.html&quot; title=&quot;https://mange.ifrn.edu.br/python/aprenda-com-py3/capitulo_09.html&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;tupla&lt;/a&gt; ou &lt;a href=&quot;https://mange.ifrn.edu.br/python/aprenda-com-py3/capitulo_10.html&quot; title=&quot;https://mange.ifrn.edu.br/python/aprenda-com-py3/capitulo_10.html&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;dicionário&lt;/a&gt;. Tudo num único tipo, integrado com diferentes aspectos da linguagem.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1301&quot;&gt;Para efeito de comparação, vamos ver o quão poderoso o tipo &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;array&lt;/code&gt; é comparado com conceitos de outras linguagens:&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot;&gt;
&lt;thead style=&quot;display: table; width: 100%; background: #eee;&quot;&gt;
&lt;tr&gt;
&lt;th style=&quot;width: 33.2843%;&quot;&gt;&lt;strong&gt;Conceito&lt;/strong&gt;&lt;/th&gt;
&lt;th style=&quot;width: 33.2843%;&quot;&gt;&lt;strong&gt;Outra linguagem&lt;/strong&gt;&lt;/th&gt;
&lt;th style=&quot;width: 33.2889%;&quot;&gt;&lt;strong&gt;PHP&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody style=&quot;display: block; white-space: normal;&quot;&gt;
&lt;tr style=&quot;display: flex;&quot;&gt;
&lt;td style=&quot;width: 33.2843%; background: #eee;&quot;&gt;&lt;strong&gt;Vetor&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.2843%;&quot;&gt;Na linguagem C (e muitas outras) os vetores possuem somente um tipo de dado. Por exemplo &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;int numeros[10]&lt;/code&gt; só pode conter elementos do tipo &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;int&lt;/code&gt;. &lt;a href=&quot;https://www.inf.pucrs.br/~pinho/LaproI/Vetores/Vetores.htm&quot; title=&quot;https://www.inf.pucrs.br/~pinho/LaproI/Vetores/Vetores.htm&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Ver mais sobre&lt;/a&gt;.&lt;/td&gt;
&lt;td style=&quot;width: 33.2889%;&quot;&gt;Em PHP vetores podem conter elementos de qualquer tipo: strings, inteiros e objetos num mesmo vetor, sem problema algum.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;display: flex;&quot;&gt;
&lt;td style=&quot;width: 33.2843%; background: #eee;&quot;&gt;&lt;strong&gt;Listas, filhas e pilhas&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.2843%;&quot;&gt;Em Java usam-se diferentes classes para cada comportamento: List, Queue e Stack. &lt;a href=&quot;https://docente.ifsc.edu.br/vilson.junior/ed/04_Listas_Filas_Pilhas.pdf&quot; title=&quot;https://docente.ifsc.edu.br/vilson.junior/ed/04_Listas_Filas_Pilhas.pdf&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Ver mais sobre&lt;/a&gt;.&lt;/td&gt;
&lt;td style=&quot;width: 33.2889%;&quot;&gt;Em PHP o tipo &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;array&lt;/code&gt; pode ser utilizado como lista, filha ou pilha naturalmente. Basta utilizar as funções específicas como &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;array_shift()&lt;/code&gt; ou &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;array_pop()&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;display: flex;&quot;&gt;
&lt;td style=&quot;width: 33.2843%; background: #eee;&quot;&gt;&lt;strong&gt;Dicionário&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.2843%;&quot;&gt;A linguagem C++ tem uma biblioteca específica chamada STL (Standard Template Library) que oferece o tipo &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;map&amp;lt;I,T&amp;gt;&lt;/code&gt; para implementação de dicionários. Com limitações semelhantes aos vetores da linguagem C. &lt;a href=&quot;https://rcosta62br.unifei.edu.br/OBI/aula_06.pdf&quot; title=&quot;https://rcosta62br.unifei.edu.br/OBI/aula_06.pdf&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Ver mais sobre&lt;/a&gt;.&lt;/td&gt;
&lt;td style=&quot;width: 33.2889%;&quot;&gt;Arrays em PHP podem se comportar como &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;maps&lt;/code&gt; ou &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;hashmaps&lt;/code&gt; sem qualquer necessidade de adaptar a linguagem.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-renderer-start-pos=&quot;811&quot;&gt;É claro que nem tudo são flores, e o &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;array&lt;/code&gt; do PHP não é melhor em absolutamente TUDO quando comparado a outras linguagens. O &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;map&amp;lt;I,T&amp;gt;&lt;/code&gt; do C++ por exemplo consegue garantir o tipo interno dos dados, enquanto em PHP é necessário fazer algumas verificações adicionais em código ou via análise estática com ferramentas como o &lt;a href=&quot;https://phpstan.org/blog/generics-in-php-using-phpdocs&quot; title=&quot;https://phpstan.org/blog/generics-in-php-using-phpdocs&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;PHPStan&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;Como-criar-arrays-de-índice-numérico-ou-do-tipo-lista-em-PHP?&quot; data-renderer-start-pos=&quot;2716&quot;&gt;Como criar arrays de índice numérico ou do tipo lista em PHP?&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;2779&quot;&gt;Para criar um &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;array&lt;/code&gt;de índice numérico, ou vetor, basta omitir as chaves e passar apenas valores para o array entre colchetes (&lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;[&lt;/code&gt; e &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;]&lt;/code&gt;).&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2914&quot;&gt;No exemplo abaixo vamos criar um &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;array&lt;/code&gt; de índice numérico com 3 frutas: banana, maçã e manga:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;2914&quot;&gt;$frutas = [&apos;manga&apos;, &apos;maçã&apos;, &apos;banana&apos;];&lt;br&gt;&lt;br&gt;echo $frutas[0]; // manga&lt;br&gt;echo $frutas[1]; // maçã&lt;br&gt;echo $frutas[2]; // banana&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;3128&quot;&gt;Podemos notar algumas coisas:&lt;/p&gt;
&lt;ul class=&quot;ak-ul&quot; data-indent-level=&quot;1&quot;&gt;
&lt;li&gt;
&lt;p data-renderer-start-pos=&quot;3161&quot;&gt;Acessamos cada elemento através de seu índice usando a &lt;a href=&quot;https://www.php.net/manual/pt_BR/language.types.array.php#language.types.array.syntax.accessing&quot; title=&quot;https://www.php.net/manual/pt_BR/language.types.array.php#language.types.array.syntax.accessing&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;sintaxe de colchetes&lt;/a&gt;;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-renderer-start-pos=&quot;3241&quot;&gt;Os índices estão em ordem crescente, começando em 0 (zero);&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-renderer-start-pos=&quot;3304&quot;&gt;Os elementos (banana, maçã e manga) não são ordenados alfabeticamente mas por ordem de inserção&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-renderer-start-pos=&quot;3403&quot;&gt;&lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;manga&lt;/code&gt; é o primeiro elemento, portanto recebe o índice &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;0&lt;/code&gt;. &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;maçã&lt;/code&gt; é o segundo, recebe o índice &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;1&lt;/code&gt;. &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;banana&lt;/code&gt; é o terceiro elemento e recebe o índice &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;2&lt;/code&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3548&quot;&gt;Na linguagem PHP, em contrates com Java ou C/C++, é possível misturar tipos dentro de um vetor. O exemplo a seguir é um código válido:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;3548&quot;&gt;$balaio = [&apos;comida de gato&apos;, new Gato(), false];&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;3734&quot;&gt;Independentemente de como usaríamos este vetor, temos a flexibilidade de inserir uma &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;string&lt;/code&gt;, um &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;objeto&lt;/code&gt; e um &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;boolean&lt;/code&gt; no mesmo balaio.&lt;/p&gt;
&lt;h2 id=&quot;Como-criar-arrays-associativos,-mapas-dicionários-em-PHP?&quot; data-renderer-start-pos=&quot;3868&quot;&gt;Como criar arrays associativos, mapas dicionários em PHP?&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;3927&quot;&gt;Linguagens como Python ou JavaScript têm o conceito de Dicionário, enquanto Java e C++ possuem seus Mapas. O PHP une todos estes conceitos num formato especial de array: o array associativo.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;4119&quot;&gt;Um array associativo em PHP é um &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;array&lt;/code&gt; parecido com o de índice numérico, com a diferença que nós escolhemos o índice de cada elemento em vez de deixar a linguagem escolher a ordem crescente natural. Além disso, nós podemos também escolher índices que sejam strings em vez de números. Veja:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;4119&quot;&gt;$ranking_frutas = [&lt;br&gt;  0 =&amp;gt; &apos;manga&apos;,&lt;br&gt;  5 =&amp;gt; &apos;uva&apos;,&lt;br&gt;  15 =&amp;gt; &apos;maçã&apos;,&lt;br&gt;];&lt;br&gt;&lt;br&gt;$frutas_fotos = [&lt;br&gt;  &apos;manga&apos; =&amp;gt; &apos;/fotos/manga.jpg&apos;,&lt;br&gt;  &apos;uva&apos; =&amp;gt; &apos;/fotos/uva.jpg&apos;,&lt;br&gt;  &apos;maçã&apos; =&amp;gt; &apos;/fotos/maca.jpg&apos;,&lt;br&gt;];&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;4785&quot;&gt;Enquanto o primeiro array &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$ranking_frutas&lt;/code&gt; ainda tem índice numérico, sua ordenação não é mais natural: nós forçamos que &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;manga&lt;/code&gt;, a melhor fruta do planeta terra, fique em primeiríssimo lugar, e apesar de não saber quem seria o segundo ou terceiro, colocamos &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;maçã&lt;/code&gt;, a fruta mais desnecessária que tem, na posição 15.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;5099&quot;&gt;Já o segundo array é associativo e usa chaves do tipo &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;string&lt;/code&gt;. Note que &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$frutas_fotos&lt;/code&gt; não usa números do lado esquerdo, mas sim o nome das frutas. E do lado direito o link para fotos que representam aquela fruta: &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;fruta =&amp;gt; foto&lt;/code&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;5327&quot;&gt;Desta forma podemos acessar os dois arrays usando a mesma &lt;a href=&quot;https://www.php.net/manual/pt_BR/language.types.array.php#language.types.array.syntax.accessing&quot; title=&quot;https://www.php.net/manual/pt_BR/language.types.array.php#language.types.array.syntax.accessing&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;sintaxe de colchetes&lt;/a&gt;:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;5327&quot;&gt;echo &quot;A melhor fruta do mundo é: $ranking_frutas[0].&quot;;&lt;br&gt;// A melhor fruta do mundo é: manga&lt;br&gt;&lt;br&gt;echo &quot;Aqui tem uma foto de manga: {$frutas_fotos[&apos;manga&apos;]}.&quot;&lt;br&gt;// Aqui tem uma foto de manga: /fotos/manga.jpg&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;5677&quot;&gt;Portanto as sintaxes &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$array[0]&lt;/code&gt; e &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$array[&apos;string&apos;]&lt;/code&gt; são válidas.&lt;/p&gt;
&lt;h2 id=&quot;Como-criar-arrays-híbridos-no-PHP?&quot; data-renderer-start-pos=&quot;5741&quot;&gt;Como criar arrays híbridos no PHP?&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;5777&quot;&gt;Você já deve ter calculado que já que é possível criar arrays de índices numéricos e arrays associativos usando a mesma sintaxe, talvez seja possível misturar os dois. E o pensamento é 100% correto.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;5977&quot;&gt;Em PHP é possível utilizar índices numéricos e de texto numa mesma variável como no exemplo a seguir:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;5977&quot;&gt;$tudo_junto_e_misturado = [&lt;br&gt;  0 =&amp;gt; &apos;manga&apos;,&lt;br&gt;  &apos;manga&apos; =&amp;gt; &apos;Melhor fruta, slc!&apos;&lt;br&gt;];&lt;br&gt;&lt;br&gt;echo $tudo_junto_e_misturado[0]; // manga&lt;br&gt;echo $tudo_junto_e_misturado[&apos;manga&apos;]; // Melhor fruta, slc!&lt;/pre&gt;
&lt;p&gt;Algumas funções são específicas para arrays de índice numérico, outras para arrays associativos, outras para todos os arrays. Com o tempo e prática você vai entender em quais cenários faz sentido usar um array híbrido. &lt;em data-renderer-mark=&quot;true&quot;&gt;Spoiler: quase nunca faz sentido.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;Como-criar-arrays-bidimensionais-ou-matrizes-em-PHP?&quot; data-renderer-start-pos=&quot;6520&quot;&gt;Como criar arrays bidimensionais ou matrizes em PHP?&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;6574&quot;&gt;Como em todas as linguagens em que é possível criar vetores, o princípio da composição nos permite criar vetores de múltiplas dimensões, também conhecidos como matrizes. Na teoria é exatamente o contrário: matrizes podem ter diferentes dimensões, inclusive uma única e neste caso a matriz de única dimensão é chamada de vetor.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;6902&quot;&gt;Enfim… tudo isso pra te dizer que um array pode conter outros arrays. Por exemplo, podemos representar um tabuleiro de &lt;a href=&quot;https://pt.wikipedia.org/wiki/Jogo_da_velha&quot; title=&quot;https://pt.wikipedia.org/wiki/Jogo_da_velha&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;jogo da velha&lt;/em&gt;&lt;/a&gt; com um array bidimensional assim:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;6902&quot;&gt;$tabuleiro = [&lt;br&gt;  [&apos;O&apos;, &apos;&apos;, &apos;X&apos;],&lt;br&gt;  [&apos;O&apos;, &apos;X&apos;, &apos;&apos;],&lt;br&gt;  [&apos;X&apos;, &apos;O&apos;, &apos;&apos;],&lt;br&gt;];&lt;br&gt;&lt;br&gt;echo &quot;A posição (0, 2) tem o valor $tabuleiro[0][2].&quot;;&lt;br&gt;// A posição (0, 2) tem o valor X.&lt;br&gt;&lt;br&gt;echo &quot;A posição (2, 1) tem o valor $tabuleiro[2][1].&quot;;&lt;br&gt;// A posição (2, 0) tem o valor O.&lt;/pre&gt;
&lt;p&gt;E portanto para acessar a primeira “linha” usamos &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$tabuleiro[0]&lt;/code&gt; e a última linha &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$tabuleiro[2]&lt;/code&gt;. Enquanto a primeira célula da primeira linha podemos acessar com &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$tabuleiro[0][0]&lt;/code&gt; e a última célula da primeira linha com &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$tabuleiro[0][2]&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;Como-adicionar-um-elemento-ao-array-do-PHP?&quot; data-renderer-start-pos=&quot;7562&quot;&gt;Como adicionar um elemento ao &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;array&lt;/code&gt; do PHP?&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;7607&quot;&gt;Em PHP, diferentemente da linguagem C, o &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;array&lt;/code&gt; tem tamanho dinâmico. Portanto você pode expandir um array o quanto quiser (e de acordo com a memória RAM disponível em seu ambiente).&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;7790&quot;&gt;Suponha o array &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$pares&lt;/code&gt; com os seguintes números pares: &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;[0, 2, 4, 6]&lt;/code&gt;. Vamos ver diferentes formas de adicionar os próximos pares:&lt;/p&gt;
&lt;h3 id=&quot;Como-adicionar-um-elemento-usando-a-sintaxe-de-índice?&quot; data-renderer-start-pos=&quot;7920&quot;&gt;Como adicionar um elemento usando a sintaxe de índice?&lt;/h3&gt;
&lt;p data-renderer-start-pos=&quot;7976&quot;&gt;Já vimos que é possível acessar um valor através de seu índice numérico. Por exemplo &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$pares[2]&lt;/code&gt; nos traria o valor &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;4&lt;/code&gt;. Mas também é possível alterar valores usando esta sintaxe.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;8153&quot;&gt;Portanto caso queiramos adicionar o próximo par à variável &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$pares&lt;/code&gt; podemos associar seu &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;último índice + 1&lt;/code&gt; com o próximo número. Assim:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;8153&quot;&gt;// Último índice = 3&lt;br&gt;$pares[4] = 8;&lt;/pre&gt;
&lt;p&gt;Neste caso nós sabíamos que o último índice era &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;3&lt;/code&gt;, mas podemos fazer isso de forma dinâmica quando não soubermos quais índices existem no array:&lt;/p&gt;
&lt;pre&gt;$indice = count($pares); // $indice = 5&lt;br&gt;$pares[$indice] = 10;&lt;/pre&gt;
&lt;p&gt;No exemplo acima associamos o valor &lt;a href=&quot;https://www.php.net/manual/pt_BR/function.count.php&quot; title=&quot;https://www.php.net/manual/pt_BR/function.count.php&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;count($pares)&lt;/em&gt;&lt;/a&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt; &lt;/em&gt;à variável &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$indice&lt;/code&gt;. Nós já tínhamos os valores &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;0, 2, 4 e 6&lt;/code&gt;, e depois adicionamos o valor &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;8&lt;/code&gt; ao final. Portanto &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$indice&lt;/code&gt; aqui possui o valor 5, que é o número de elementos existentes no array &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$pares&lt;/code&gt;. Depois associamos o valor &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;10&lt;/code&gt; ao índice &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$indice&lt;/code&gt; (5).&lt;/p&gt;
&lt;h3 id=&quot;Como-adicionar-um-elemento-usando-a-sintaxe-de-associativa?&quot; data-renderer-start-pos=&quot;8834&quot;&gt;Como adicionar um elemento usando a sintaxe de associativa?&lt;/h3&gt;
&lt;p&gt;É muito semelhante à forma de trabalhar com índices numéricos, porém utilizamos &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;string&lt;/code&gt; como índices. Vamos por exemplo criar um array associativo do tipo matriz para armazenar números pares e ímpares:&lt;/p&gt;
&lt;pre&gt;$numeros = [&lt;br&gt;  &apos;pares&apos; =&amp;gt; [0, 2, 4, 6],&lt;br&gt;  &apos;impares&apos; =&amp;gt; [1, 3, 5, 7],&lt;br&gt;];&lt;br&gt;&lt;br&gt;echo $numeros[&apos;pares&apos;][2]; // 4&lt;br&gt;echo $numeros[&apos;impares&apos;][1]; // 3&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;9238&quot;&gt;Perceba que:&lt;/p&gt;
&lt;ul class=&quot;ak-ul&quot; data-indent-level=&quot;1&quot;&gt;
&lt;li&gt;
&lt;p data-renderer-start-pos=&quot;9254&quot;&gt;A sintaxe é a mesma: acessamos o elemento &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;pares&lt;/code&gt; com a sintaxe de colchetes &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$numeros[&apos;pares&apos;]&lt;/code&gt;;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-renderer-start-pos=&quot;9351&quot;&gt;É possível guardar qualquer coisa dentro de um &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;array&lt;/code&gt;, inclusive outro &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;array&lt;/code&gt;: nós guardamos o array &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$pares&lt;/code&gt; dentro do array &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$numeros&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;A-sintaxe-antiga-de-arrays-do-PHP&quot; data-renderer-start-pos=&quot;9485&quot;&gt;A sintaxe antiga de arrays do PHP&lt;/h2&gt;
&lt;p&gt;Em alguns tutoriais e livros mais antigos, você vai encontrar uma sintaxe diferente para trabalhar com &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;array&lt;/code&gt; no PHP. Então deixa eu te mostrar como nós costumávamos criar arrays no PHP na idade da pedra da computação:&lt;/p&gt;
&lt;pre&gt;$meuArray = array(0, 1, 2, 3, 4);&lt;br&gt;&lt;br&gt;echo &quot;O terceiro elemento é o número $meuArray[2].&quot;;&lt;br&gt;// O terceiro elemento é o número 3.&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;9865&quot;&gt;Esta sintaxe ainda funciona na linguagem PHP, mas está sendo abandonada aos poucos. Portanto utilize colchetes para criar arrays SEMPRE.&lt;/p&gt;
&lt;h2 id=&quot;Diferentes-utilidades-do-array-no-PHP&quot; data-renderer-start-pos=&quot;10003&quot;&gt;Diferentes utilidades do array no PHP&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;10043&quot;&gt;Arrays são praticamente o coração da linguagem PHP. Um dos motivos de o PHP ser tão popular, na minha opinião, é a flexibilidade agregada pelos arrays e como eles se integram a praticamente tudo no ecossistema PHP.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;10259&quot;&gt;Algumas utilidades do array no PHP incluem, mas não se limitam a:&lt;/p&gt;
&lt;ul&gt;
&lt;li data-renderer-start-pos=&quot;10259&quot;&gt;Listas&lt;/li&gt;
&lt;li data-renderer-start-pos=&quot;10259&quot;&gt;Dicionários&lt;/li&gt;
&lt;li data-renderer-start-pos=&quot;10259&quot;&gt;Tuplas&lt;/li&gt;
&lt;li data-renderer-start-pos=&quot;10259&quot;&gt;Pilhas e filas&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-renderer-start-pos=&quot;10381&quot;&gt;Vamos ver cada um destes itens com exemplos.&lt;/p&gt;
&lt;h3 id=&quot;Utilizando-arrays-PHP-como-listas&quot; data-renderer-start-pos=&quot;10427&quot;&gt;Utilizando arrays PHP como listas&lt;/h3&gt;
&lt;p data-renderer-start-pos=&quot;10462&quot;&gt;Listas são segmentos de valores que podem ou não ser ordenados. Os arrays PHP tornam este trabalho muito simples de se realizar.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;10592&quot;&gt;Por exemplo, abaixo temos uma lista de frutas completamente desordenada:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;10592&quot;&gt;$frutas = [&apos;manga&apos;, &apos;banana&apos;, &apos;maçã&apos;];&lt;br&gt;&lt;br&gt;echo $frutas[0]; // manga&lt;br&gt;echo $frutas[1]; // banana&lt;br&gt;echo $frutas[2]; // maçã&lt;/pre&gt;
&lt;p&gt;Adicionalmente, se quisermos garantir que a lista seja ordenada, podemos aplicar a função &lt;a href=&quot;https://www.php.net/manual/pt_BR/function.sort.php&quot; title=&quot;https://www.php.net/manual/pt_BR/function.sort.php&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;sort()&lt;/em&gt;&lt;/a&gt; para ordenar seus elementos:&lt;/p&gt;
&lt;pre&gt;$frutas = [&apos;manga&apos;, &apos;banana&apos;, &apos;maçã&apos;];&lt;br&gt;&lt;br&gt;if (sort($frutas)) {&lt;br&gt;  echo $frutas[0]; // banana&lt;br&gt;  echo $frutas[1]; // maçã&lt;br&gt;  echo $frutas[2]; // manga&lt;br&gt;}&lt;/pre&gt;
&lt;h3 id=&quot;Utilizando-arrays-PHP-como-dicionários&quot; data-renderer-start-pos=&quot;11060&quot;&gt;Utilizando arrays PHP como dicionários&lt;/h3&gt;
&lt;p data-renderer-start-pos=&quot;11100&quot;&gt;Dicionários são estruturas no formato &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;chave =&amp;gt; valor&lt;/code&gt;, em PHP são chamados arrays associativos.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;11196&quot;&gt;Um exemplo de utilização de dicionários é o agrupamento de dados para gerar relatórios. Por exemplo, podemos representar o preço de uma ação em diferentes horários do dia no exemplo a seguir:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;11196&quot;&gt;$seriePrecos = [&lt;br&gt;  &apos;10am&apos; =&amp;gt; 19.20,&lt;br&gt;  &apos;3pm&apos; =&amp;gt; &apos;21.02&apos;,&lt;br&gt;  &apos;5pm&apos; =&amp;gt; &apos;20.59&apos;,&lt;br&gt;];&lt;br&gt;&lt;br&gt;echo &quot;A ação CODAMOS tinha o preço $seriePrecos[&apos;10am&apos;] às 10am de hoje.&quot;;&lt;br&gt;// A ação CODAMOS tinha o preço 19.20 às 10am de hoje.&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;11600&quot;&gt;Eu citei acima o formato &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;chave =&amp;gt; valor&lt;/code&gt;, para deixar claro o que aquilo significa: no array acima, &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;10am, 3pm e 5pm&lt;/code&gt; são chaves enquanto &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;19.20, 21.02 e 20.59&lt;/code&gt; são valores.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;11770&quot;&gt;O maior motivo para utilizarmos dicionários no PHP é adicionar semântica ao nosso código. Esta é uma estrutura de dados muito poderosa e flexível que nos permite representar diferentes conceitos usando o formato &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;chave =&amp;gt; valor&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;Utilizando-arrays-PHP-como-tuplas&quot; data-renderer-start-pos=&quot;11999&quot;&gt;Utilizando arrays PHP como tuplas&lt;/h3&gt;
&lt;p data-renderer-start-pos=&quot;12034&quot;&gt;Tuplas são dados que estão relacionados e têm pouco ou nenhum significado quando isolados.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;12126&quot;&gt;Por exemplo, num plano cartesiano as coordenadas são tuplas de dois elementos: x e y. Portanto o valor &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;(x, y)&lt;/code&gt; pode ser considerado uma tupla.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;12269&quot;&gt;De forma semelhante, num espaço de três dimensões, as coordenadas seriam &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;(x, y, z)&lt;/code&gt; que também é uma tupla mas de 3 elementos.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;12396&quot;&gt;Arrays em PHP podem ser utilizados como tuplas naturalmente:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;12396&quot;&gt;$coordenadas = [10, 20]; // tupla de 2 inteiros&lt;br&gt;[$x, $y] = $coordenadas; // extraindo valores da tupla&lt;br&gt;&lt;br&gt;echo &quot;A tupla (x, y) tem valor ($x, $y).&quot;;&lt;br&gt;// A tupla (x, y) tem valor (10, 20).&lt;/pre&gt;
&lt;h3 id=&quot;Utilizando-arrays-PHP-para-trabalhar-com-pilhas-e-filas&quot; data-renderer-start-pos=&quot;12644&quot;&gt;Utilizando arrays PHP para trabalhar com pilhas e filas&lt;/h3&gt;
&lt;p data-renderer-start-pos=&quot;12701&quot;&gt;Pilhas são listas em que sempre inserimos valores ao fim do array, e sempre retiramos valores do fim do array. Como uma pilha de pratos: você normalmente coloca o prato no topo da pilha, e tira sempre o prato que está mais ao topo da pilha.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;12943&quot;&gt;Pilhas sempre utilizam o algoritmo &lt;em data-renderer-mark=&quot;true&quot;&gt;LIFO – Last in, first out&lt;/em&gt;. Ou seja: o último elemento que chegou, é o primeiro que vai sair.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;13072&quot;&gt;Em PHP, os arrays podem ser tratados como pilha ao utilizar as funções &lt;a href=&quot;https://www.php.net/manual/pt_BR/function.array-push.php&quot; title=&quot;https://www.php.net/manual/pt_BR/function.array-push.php&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;array_push()&lt;/em&gt;&lt;/a&gt; e &lt;a href=&quot;https://www.php.net/manual/pt_BR/function.array-pop.php&quot; title=&quot;https://www.php.net/manual/pt_BR/function.array-pop.php&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;array_pop()&lt;/em&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;13072&quot;&gt;$pratos = [];&lt;br&gt;array_push($pratos, &apos;porcelana&apos;);&lt;br&gt;array_push($pratos, &apos;plástico&apos;);&lt;br&gt;&lt;br&gt;$pratoDoTopo = array_pop($pratos);&lt;br&gt;echo &quot;O prato que estava no topo da pilha é feito de $pratoDoTopo.&quot;;&lt;br&gt;// O prato que estava no topo da pilha é feito de plástico.&lt;/pre&gt;
&lt;p&gt;Exatamente ao contrário do que pilhas fazem, as filas seguem o algoritmo &lt;em data-renderer-mark=&quot;true&quot;&gt;FIFO – First in, first out&lt;/em&gt;. Ou seja: quem chega primeiro, sai primeiro! E podemos fazer isso também com a função &lt;a href=&quot;https://www.php.net/manual/pt_BR/function.array-push.php&quot; title=&quot;https://www.php.net/manual/pt_BR/function.array-push.php&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;array_push()&lt;/em&gt;&lt;/a&gt; para adicionar ao final da fila, e com &lt;a href=&quot;https://www.php.net/manual/pt_BR/function.array-shift.php&quot; title=&quot;https://www.php.net/manual/pt_BR/function.array-shift.php&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;array_shift()&lt;/em&gt;&lt;/a&gt; para remover do começo da fila. Para furar a fila podemos também utilizar o &lt;a href=&quot;https://www.php.net/manual/pt_BR/function.array-unshift.php&quot; title=&quot;https://www.php.net/manual/pt_BR/function.array-unshift.php&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;array_unshift()&lt;/em&gt;&lt;/a&gt; que adiciona um elemento logo no começo da fila.&lt;/p&gt;
&lt;pre&gt;$fila_do_mercado = [&apos;Marcio&apos;, &apos;Maria&apos;, &apos;João&apos;];&lt;br&gt;&lt;br&gt;$proximo = array_shift($fila_do_mercado);&lt;br&gt;echo &quot;Vamos atender $proximo agora!&quot;;&lt;br&gt;// Vamos atender Marcio agora!&lt;br&gt;&lt;br&gt;// Vitória tem preferência na fila&lt;br&gt;array_unshift($fila_do_mercado, &apos;Vitória&apos;);&lt;br&gt;&lt;br&gt;$proximo = array_shift($fila_do_mercado);&lt;br&gt;echo &quot;Vamos atender $proximo agora!&quot;;&lt;br&gt;// Vamos atender Vitória agora!&lt;/pre&gt;
&lt;p&gt;Note que &lt;a href=&quot;https://www.php.net/manual/pt_BR/function.array-unshift.php&quot; title=&quot;https://www.php.net/manual/pt_BR/function.array-unshift.php&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;array_unshift()&lt;/em&gt;&lt;/a&gt; jogou o nome “Vitória” para o começo da fila e portanto este foi o próximo nome a ser chamado.&lt;/p&gt;
&lt;h2 id=&quot;Como-visitar-cada-elemento-de-um-array-no-PHP?&quot; data-renderer-start-pos=&quot;14287&quot;&gt;Como visitar cada elemento de um array no PHP?&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;14335&quot;&gt;Na maioria dos casos nós não queremos acessar apenas um elemento do &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;array&lt;/code&gt;, mas sim percorrer o array inteiro para executar alguma ação.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;14472&quot;&gt;Para arrays de índice numérico, uma saída comum em outras linguagens como o C, é utilizar um laço de repetição como um &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;for&lt;/code&gt; ou &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;while&lt;/code&gt; juntamente de um contador como no exemplo a seguir:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;14472&quot;&gt;$frutas = [&apos;manga&apos;, &apos;banana&apos;, &apos;maçã&apos;];&lt;br&gt;&lt;br&gt;$i = 0;&lt;br&gt;while ($i &amp;lt; count($frutas)) {&lt;br&gt;  echo &quot;A fruta do índice $i é $frutas[$i].&quot;;&lt;br&gt;  $i++;&lt;br&gt;}&lt;br&gt;&lt;br&gt;// A fruta do índice 0 é manga.&lt;br&gt;// A fruta do índice 1 é banana.&lt;br&gt;// A fruta do índice 2 é maçã.&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;14889&quot;&gt;O laço acima, como você provavelmente já entendeu, é equivalente ao laço &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;for&lt;/code&gt; a seguir:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;14889&quot;&gt;$frutas = [&apos;manga&apos;, &apos;banana&apos;, &apos;maçã&apos;];&lt;br&gt;&lt;br&gt;for ($i = 0; $i &amp;lt; count($frutas); $i++) {&lt;br&gt;  echo &quot;A fruta do índice $i é $frutas[$i].&quot;;&lt;br&gt;}&lt;br&gt;&lt;br&gt;// A fruta do índice 0 é manga.&lt;br&gt;// A fruta do índice 1 é banana.&lt;br&gt;// A fruta do índice 2 é maçã.&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;15205&quot;&gt;O método acima funciona na maioria dos casos, mas é problemático caso você precise iterar um &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;array&lt;/code&gt; do tipo dicionário, em que as chaves não são números ordenados.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;15369&quot;&gt;O jeito mais fácil de percorrer um array, independente do tipo de índice que tiver, é através da estrutura de iteração &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;foreach&lt;/code&gt;. Vejamos o exemplo a seguir:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;15369&quot;&gt;$frutas = [&apos;manga&apos;, &apos;banana&apos;, &apos;maçã&apos;];&lt;br&gt;&lt;br&gt;foreach ($frutas as $fruta) {&lt;br&gt;  echo &quot;Fruta: $fruta&quot;;&lt;br&gt;}&lt;br&gt;&lt;br&gt;// Fruta: manga&lt;br&gt;// Fruta: banana&lt;br&gt;// Fruta: maçã&lt;/pre&gt;
&lt;p&gt;Note que a variável &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$i&lt;/code&gt; não é necessária para iterar o array. Mas caso você &lt;em data-renderer-mark=&quot;true&quot;&gt;precise&lt;/em&gt; desta variável para saber o índice, pode utilizar uma variação do &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;foreach&lt;/code&gt; como no exemplo a seguir:&lt;/p&gt;
&lt;pre&gt;$frutas = [&apos;manga&apos;, &apos;banana&apos;, &apos;maçã&apos;];&lt;br&gt;&lt;br&gt;foreach ($frutas as $i =&amp;gt; $fruta) {&lt;br&gt;  echo &quot;A fruta do índice $i é $fruta.&quot;;&lt;br&gt;}&lt;br&gt;&lt;br&gt;// A fruta do índice 0 é manga.&lt;br&gt;// A fruta do índice 1 é banana.&lt;br&gt;// A fruta do índice 2 é maçã.&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;16073&quot;&gt;Note que &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$i&lt;/code&gt; no exemplo acima &lt;em data-renderer-mark=&quot;true&quot;&gt;não é um contador&lt;/em&gt;, mas sim o índice do array &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$frutas&lt;/code&gt;. De forma semelhante, caso o array possua índices do tipo string em vez de numéricos, a mesma sintaxe vai ser de grande ajuda:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;16073&quot;&gt;$frutas_favoritas = [&lt;br&gt;  &apos;nawarian&apos; =&amp;gt; &apos;manga&apos;,&lt;br&gt;  &apos;joana&apos; =&amp;gt; &apos;abacate&apos;,&lt;br&gt;  &apos;pedro&apos; =&amp;gt; &apos;mamão&apos;,&lt;br&gt;];&lt;br&gt;&lt;br&gt;foreach ($frutas_favoritas as $nome =&amp;gt; $fruta) {&lt;br&gt;  echo &quot;A fruta favorita de $nome é $fruta.&quot;;&lt;br&gt;}&lt;br&gt;&lt;br&gt;// A fruta favorita de nawarian é manga.&lt;br&gt;// A fruta favorita de joana é abacate.&lt;br&gt;// A fruta favorita de pedro é mamão.&lt;/pre&gt;
&lt;p&gt;Reparou como a porção &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$nome =&amp;gt; $fruta&lt;/code&gt; são nomes que eu escolhi? Estas variáveis poderiam ter &lt;em data-renderer-mark=&quot;true&quot;&gt;qualquer&lt;/em&gt; outro nome. Não é obrigatório chamar sempre de &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$key =&amp;gt; $value&lt;/code&gt; ou &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$i =&amp;gt; $x&lt;/code&gt;. Você pode escolher nomes que façam mais sentido na hora de ler o seu código.&lt;/p&gt;
&lt;p class=&quot;msg msg--highlight &quot;&gt;💡 &lt;a href=&quot;/guia-estilo-de-codigo-para-iniciantes/&quot;&gt;Leia também: como escrever código fácil de ler e de dar manutenção.&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;Como-desestruturar-arrays-no-PHP?&quot; data-renderer-start-pos=&quot;16924&quot;&gt;Como desestruturar arrays no PHP?&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;16959&quot;&gt;Esta sintaxe é relativamente nova e lembra muito o que fazemos no JavaScript!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;17038&quot;&gt;Como sabemos, dentro do array podemos ter qualquer tipo de dado, mas as vezes estes dados vêm em pares que fazem algum sentido lógico. Se sabemos desta sequência, podemos desestruturar o array e transformar cada elemento em uma variável com um nome que tenha um sentido semântico maior.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;17326&quot;&gt;Veja o exemplo em que a variável &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$coordenadas&lt;/code&gt; sabidamente tem dois elementos: o primeiro é um valor de &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;x&lt;/code&gt; enquanto o segundo elemento é &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;y&lt;/code&gt;. Podemos desestruturar este array para obter estes dois valores como variáveis:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;17326&quot;&gt;$coordenadas = [10, 20];&lt;br&gt;&lt;br&gt;[$x, $y] = $coordenadas;&lt;/pre&gt;
&lt;p&gt;Nós já vimos este exemplo enquanto falávamos sobre tuplas. Mas vamos utilizar um exemplo mais interessante: percorrer dados de uma série histórica de valores e imprimir na tela cada data. E aqui nós vamos desestruturar o array dentro do &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;foreach&lt;/code&gt;! Veja como funciona:&lt;/p&gt;
&lt;pre&gt;$serie = [&lt;br&gt;  [&apos;2022-10-10&apos;, 100],&lt;br&gt;  [&apos;2022-10-11&apos;, 115],&lt;br&gt;  [&apos;2022-10-12&apos;, 120],&lt;br&gt;];&lt;br&gt;&lt;br&gt;foreach ($serie as [$data, $valor]) { // 👈 olha aqui!&lt;br&gt;  echo &quot;Em $data o valor era de $valor.&quot;;&lt;br&gt;}&lt;br&gt;&lt;br&gt;// Em 2022-10-10 o valor era de 100.&lt;br&gt;// Em 2022-10-11 o valor era de 115.&lt;br&gt;// Em 2022-10-11 o valor era de 120.&lt;/pre&gt;
&lt;p&gt;Também é possível ignorar alguns valores simplesmente adicionando uma vírgula &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;,&lt;/code&gt; sem nenhum nome de variável. No exemplo a seguir o segundo elemento do array é completamente ignorado:&lt;/p&gt;
&lt;pre&gt;$frutas = [&apos;manga&apos;, &apos;maçã&apos;, &apos;banana&apos;];&lt;br&gt;&lt;br&gt;[$manga, , $banana] = $frutas; // maçã nem deveria ser fruta&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;18445&quot;&gt;Isto é bastante útil quando extraímos dados de expressões regulares, por exemplo.&lt;/p&gt;
&lt;h2 id=&quot;Como-extrair-elementos-do-array-usando-a-sintaxe-de-desempacotamento-no-PHP?&quot; data-renderer-start-pos=&quot;18528&quot;&gt;Como extrair elementos do array usando a sintaxe de desempacotamento no PHP?&lt;/h2&gt;
&lt;p&gt;O desempacotamento de array pode também ser entendido como “expandir” seus elementos, e pra isso a gente usa o operador ellipsis &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;...&lt;/code&gt;. Você pode misturar esta sintaxe com diversas outras no PHP como podemos ver a seguir.&lt;/p&gt;
&lt;pre&gt;$pares = [2, 4, 6];&lt;br&gt;&lt;br&gt;$pares_com_zero = [0, ...$pares];&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;18883&quot;&gt;Note que o array &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$pares&lt;/code&gt; começa com apenas 3 elementos e que &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$pares_com_zero&lt;/code&gt; é criado com &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;0&lt;/code&gt; sendo seu primeiro elemento, seguido de todos os outros presentes em &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$pares&lt;/code&gt;. Portanto &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$pares_com_zero&lt;/code&gt; efetivamente tem os valores &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;[0, 2, 4, 6]&lt;/code&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;19119&quot;&gt;Desta forma é possível extrair e combinar diferentes arrays.&lt;/p&gt;
&lt;h2 id=&quot;Como-unir-dois-ou-mais-arrays-no-PHP?&quot; data-renderer-start-pos=&quot;19181&quot;&gt;Como unir dois ou mais arrays no PHP?&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;19220&quot;&gt;Para unir os elementos de dois ou mais arrays existe três formas:&lt;/p&gt;
&lt;ul&gt;
&lt;li data-renderer-start-pos=&quot;19220&quot;&gt;A função &lt;em&gt;array_merge()&lt;/em&gt;&lt;/li&gt;
&lt;li data-renderer-start-pos=&quot;19220&quot;&gt;A soma de array através do operador &lt;code&gt;+&lt;/code&gt;&lt;/li&gt;
&lt;li data-renderer-start-pos=&quot;19220&quot;&gt;Desempacotamento de arrays&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;Como-unir-dois-arrays-utilizando-a-função-array_merge()&quot; data-renderer-start-pos=&quot;19387&quot;&gt;Como unir dois arrays utilizando a função &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;array_merge()&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;A função &lt;a href=&quot;https://www.php.net/manual/pt_BR/function.array-merge.php&quot; title=&quot;https://www.php.net/manual/pt_BR/function.array-merge.php&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;array_merge()&lt;/em&gt;&lt;/a&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt; &lt;/em&gt;existe justamente pra mesclar (merge) dois arrays em PHP. Você pode passar quantos arrays quiser como argumento, e o retorno será um novo array que une todos os argumentos:&lt;/p&gt;
&lt;pre&gt;$pares = [0, 2, 4, 6];&lt;br&gt;$impares = [1, 3, 5, 7];&lt;br&gt;$numeros = array_merge($pares, $impares);&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;19732&quot;&gt;No exemplo acima o array &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$numeros&lt;/code&gt; combina números pares e impares. Note que os arrays foram apenas unidos, a ordem dos elementos é a mesma que a original.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;19888&quot;&gt;Para ordenar os números ímpares e pares no array &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$numeros&lt;/code&gt; seria necessário aplicar a função &lt;a href=&quot;https://www.php.net/manual/pt_BR/function.sort.php&quot; title=&quot;https://www.php.net/manual/pt_BR/function.sort.php&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;sort()&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;Como-unir-dois-arrays-utilizando-o-operador-+&quot; data-renderer-start-pos=&quot;19989&quot;&gt;Como unir dois arrays utilizando o operador &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;+&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Uma alternativa sintática ao &lt;a href=&quot;https://www.php.net/manual/pt_BR/function.array-merge.php&quot; title=&quot;https://www.php.net/manual/pt_BR/function.array-merge.php&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;array_merge()&lt;/em&gt;&lt;/a&gt; é p operador &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;+&lt;/code&gt;, que quando utilizado entre dois arrays realiza a operação de união.&lt;/p&gt;
&lt;pre&gt;$pares = [0, 2, 4, 6];&lt;br&gt;$impares = [1, 3, 5, 7];&lt;br&gt;$numeros = $pares + $impares;&lt;/pre&gt;
&lt;h3 id=&quot;Como-unir-dois-arrays-utilizando-desempacotamento-de-arrays&quot; data-renderer-start-pos=&quot;20243&quot;&gt;Como unir dois arrays utilizando desempacotamento de arrays&lt;/h3&gt;
&lt;p data-renderer-start-pos=&quot;20304&quot;&gt;Como vimos antes, é possível obter elementos de um array utilizando a sintaxe de desempacotamento usando o operador ellipsis (&lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;...&lt;/code&gt;).&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;20437&quot;&gt;Para unir dois arrays utilizando desempacotamento, podemos fazer como no exemplo a seguir:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;20437&quot;&gt;$pares = [0, 2, 4, 6];&lt;br&gt;$impares = [1, 3, 5, 7];&lt;br&gt;&lt;br&gt;$numeros = [...$pares, ...$impares];&lt;/pre&gt;
&lt;p&gt;Repare que como nos exemplos anteriores, a união dos arrays não é ordenada e portanto a variável &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;$numeros&lt;/code&gt; agora possui o valor &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;[0, 2, 4, 6, 1, 3, 5, 7]&lt;/code&gt;. Para ordenar os valores, é necessário utilizar a função &lt;a href=&quot;https://www.php.net/manual/pt_BR/function.sort.php&quot; title=&quot;https://www.php.net/manual/pt_BR/function.sort.php&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;sort()&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;Principais-funções-para-trabalhar-com-array-no-PHP&quot; data-renderer-start-pos=&quot;20834&quot;&gt;Principais funções para trabalhar com array no PHP&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;20886&quot;&gt;Arrays em PHP possuem diversas funções especiais. A documentação oficial da linguagem possui &lt;a href=&quot;https://www.php.net/manual/pt_BR/ref.array.php&quot; title=&quot;https://www.php.net/manual/pt_BR/ref.array.php&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;uma lista completa de funções para trabalhar com arrays no PHP&lt;/a&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;21044&quot;&gt;Vou listar aqui as funções mais comuns e importantes de acordo com a minha experiência.&lt;/p&gt;
&lt;h3 id=&quot;Função-count():-contar-elementos-de-um-array&quot; data-renderer-start-pos=&quot;21133&quot;&gt;Função &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;count()&lt;/code&gt;: contar elementos de um array&lt;/h3&gt;
&lt;pre&gt;$numeros = [0, 1, 2, 3, 4];&lt;br&gt;$total = count($numeros);&lt;br&gt;&lt;br&gt;echo &quot;O array &apos;numeros&apos; possui $total elementos.&quot;;&lt;br&gt;// O array &apos;numeros&apos; possui 5 elementos.&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://www.php.net/manual/pt_BR/function.count.php&quot; title=&quot;https://www.php.net/manual/pt_BR/function.count.php&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Visite a página da documentação oficial para aprender mais sobre a função &lt;em data-renderer-mark=&quot;true&quot;&gt;count()&lt;/em&gt;.&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;Função-in_array():-indica-se-elemento-existe-no-array&quot; data-renderer-start-pos=&quot;21411&quot;&gt;Função &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;in_array()&lt;/code&gt;: indica se elemento existe no array&lt;/h3&gt;
&lt;pre&gt;$numeros = [0, 1, 2, 3, 4];&lt;br&gt;$existe = in_array(2, $numeros) ? &apos;existe&apos; : &apos;não existe&apos;;&lt;br&gt;&lt;br&gt;echo &quot;O número 2 $existe no array &apos;numeros&apos;.&quot;;&lt;br&gt;// O número 2 existe no array numeros.&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;21641&quot;&gt;&lt;a href=&quot;https://www.php.net/manual/pt_BR/function.in-array.php&quot; title=&quot;https://www.php.net/manual/pt_BR/function.in-array.php&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Visite a página da documentação oficial para aprender mais sobre a função &lt;em data-renderer-mark=&quot;true&quot;&gt;in_array()&lt;/em&gt;.&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;Função-sort():-ordena-elementos-de-um-array&quot; data-renderer-start-pos=&quot;21728&quot;&gt;Função &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;sort()&lt;/code&gt;: ordena elementos de um array&lt;/h3&gt;
&lt;pre&gt;$numeros = [4, 1, 0, 3, 2];&lt;br&gt;sort($numeros);&lt;br&gt;&lt;br&gt;foreach ($numeros as $numero) {&lt;br&gt;  echo &quot;Número: $numero&quot;;&lt;br&gt;}&lt;br&gt;&lt;br&gt;// Número: 0&lt;br&gt;// Número: 1&lt;br&gt;// Número: 2&lt;br&gt;// Número: 3&lt;br&gt;// Número: 4&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;21945&quot;&gt;&lt;a href=&quot;https://www.php.net/manual/pt_BR/function.sort.php&quot; title=&quot;https://www.php.net/manual/pt_BR/function.sort.php&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Visite a página da documentação oficial para aprender mais sobre a função &lt;em data-renderer-mark=&quot;true&quot;&gt;sort()&lt;/em&gt;.&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;Função-shuffle():-embaralha-o-array-colocando-seus-elementos-em-ordem-aleatória&quot; data-renderer-start-pos=&quot;22028&quot;&gt;Função &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;shuffle()&lt;/code&gt;: embaralha o array colocando seus elementos em ordem aleatória&lt;/h3&gt;
&lt;pre&gt;$numeros = [0, 1, 2, 3, 4];&lt;br&gt;shuffle($numeros);&lt;br&gt;&lt;br&gt;foreach ($numeros as $i =&amp;gt; $numero) {&lt;br&gt;  echo &quot;O número $i é $numero.&quot;;&lt;br&gt;}&lt;br&gt;&lt;br&gt;// O número 0 é 3&lt;br&gt;// O número 1 é 0&lt;br&gt;// O número 2 é 1&lt;br&gt;// O número 3 é 4&lt;br&gt;// O número 4 é 2&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;22322&quot;&gt;&lt;a href=&quot;https://www.php.net/manual/pt_BR/function.shuffle.php&quot; title=&quot;https://www.php.net/manual/pt_BR/function.shuffle.php&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Visite a página da documentação oficial para aprender mais sobre a função &lt;em data-renderer-mark=&quot;true&quot;&gt;shuffle()&lt;/em&gt;.&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;Função-array_keys():-obtém-apenas-chaves-(índices)-do-array,-sem-valores&quot; data-renderer-start-pos=&quot;22408&quot;&gt;Função &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;array_keys()&lt;/code&gt;: obtém apenas chaves (índices) do array, sem valores&lt;/h3&gt;
&lt;pre&gt;$site_pontuacao = [&lt;br&gt;  &apos;https://codamos.com.br&apos; =&amp;gt; 10,&lt;br&gt;  &apos;https://thephp.website&apos; =&amp;gt; 7,&lt;br&gt;  &apos;https://locaweb.com.br&apos; =&amp;gt; 10,&lt;br&gt;];&lt;br&gt;&lt;br&gt;$chaves = array_keys($site_pontuacao);&lt;br&gt;foreach ($chaves as $i =&amp;gt; $chave) {&lt;br&gt;  echo &quot;O site $i é $chave.&quot;;&lt;br&gt;}&lt;br&gt;// O site 0 é https://codamos.com.br&lt;br&gt;// O site 1 é https://thephp.website&lt;br&gt;// O site 2 é https://locaweb.com.br&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;22826&quot;&gt;&lt;a href=&quot;https://www.php.net/manual/pt_BR/function.array-keys.php&quot; title=&quot;https://www.php.net/manual/pt_BR/function.array-keys.php&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Visite a página da documentação oficial para aprender mais sobre a função &lt;em data-renderer-mark=&quot;true&quot;&gt;array_keys()&lt;/em&gt;.&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;Função-array_values():-obtém-apenas-os-valores-do-array,-sem-chaves-(índices)&quot; data-renderer-start-pos=&quot;22915&quot;&gt;Função &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;array_values()&lt;/code&gt;: obtém apenas os valores do array, sem chaves (índices)&lt;/h3&gt;
&lt;pre&gt;$site_pontuacao = [&lt;br&gt;  &apos;https://codamos.com.br&apos; =&amp;gt; 10,&lt;br&gt;  &apos;https://thephp.website&apos; =&amp;gt; 7,&lt;br&gt;  &apos;https://locaweb.com.br&apos; =&amp;gt; 10,&lt;br&gt;];&lt;br&gt;&lt;br&gt;$pontuacao = array_values($site_pontuacao);&lt;br&gt;foreach ($pontuacao as $i =&amp;gt; $valor) {&lt;br&gt;  echo &quot;A pontuação $i é $valor.&quot;;&lt;br&gt;}&lt;br&gt;&lt;br&gt;// A pontuação 0 é 10&lt;br&gt;// A pontuação 1 é 7&lt;br&gt;// A pontuação 2 é 10&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;23307&quot;&gt;&lt;a href=&quot;https://www.php.net/manual/pt_BR/function.array-values.php&quot; title=&quot;https://www.php.net/manual/pt_BR/function.array-values.php&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Visite a página da documentação oficial para aprender mais sobre a função &lt;em data-renderer-mark=&quot;true&quot;&gt;array_values()&lt;/em&gt;.&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;Função-array_combine():-une-um-array-de-chaves-e-um-array-de-valores-num-único-array-associativo&quot; data-renderer-start-pos=&quot;23398&quot;&gt;Função &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;array_combine()&lt;/code&gt;: une um array de chaves e um array de valores num único array associativo&lt;/h3&gt;
&lt;pre&gt;$sites = [&lt;br&gt;  &apos;https://codamos.com.br&apos;,&lt;br&gt;  &apos;https://thephp.website&apos;,&lt;br&gt;  &apos;https://locaweb.com.br&apos;,&lt;br&gt;];&lt;br&gt;$pontuacao = [10, 7, 10];&lt;br&gt;&lt;br&gt;$site_pontuacao = array_combine($sites, $pontuacao);&lt;br&gt;&lt;br&gt;foreach ($site_pontuacao as $site =&amp;gt; $pontos) {&lt;br&gt;  echo &quot;O site $site tem $pontos pontos.&quot;;&lt;br&gt;}&lt;br&gt;&lt;br&gt;// O site https://codamos.com.br tem 10 pontos.&lt;br&gt;// O site https://thephp.website tem 7 pontos.&lt;br&gt;// O site https://locaweb.com.br tem 10 pontos.&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;23913&quot;&gt;&lt;a href=&quot;https://www.php.net/manual/pt_BR/function.array-combine.php&quot; title=&quot;https://www.php.net/manual/pt_BR/function.array-combine.php&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Visite a página da documentação oficial para aprender mais sobre a função &lt;em data-renderer-mark=&quot;true&quot;&gt;array_combine()&lt;/em&gt;.&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;Função-array_diff():-indica-a-diferença-entre-dois-ou-mais-arrays&quot; data-renderer-start-pos=&quot;24005&quot;&gt;Função &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;array_diff()&lt;/code&gt;: indica a diferença entre dois ou mais arrays&lt;/h3&gt;
&lt;pre&gt;$numeros = [0, 1, 2, 3, 4];&lt;br&gt;$pares = [0, 2, 4];&lt;br&gt;&lt;br&gt;$diff = array_diff($numeros, $pares);&lt;br&gt;foreach ($diff as $numero) {&lt;br&gt;  echo &quot;O número $numero existe no array &apos;numeros&apos; mas não no array &apos;pares&apos;.&quot;;&lt;br&gt;}&lt;br&gt;&lt;br&gt;// O número 1 existe no array &apos;numeros&apos; mas não no array &apos;pares&apos;.&lt;br&gt;// O número 3 existe no array &apos;numeros&apos; mas não no array &apos;pares&apos;.&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;24403&quot;&gt;&lt;a href=&quot;https://www.php.net/manual/pt_BR/function.array-diff.php&quot; title=&quot;https://www.php.net/manual/pt_BR/function.array-diff.php&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Visite a página da documentação oficial para aprender mais sobre a função &lt;em data-renderer-mark=&quot;true&quot;&gt;array_diff()&lt;/em&gt;.&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;Função-array_merge():-unindo-dois-ou-mais-arrays&quot; data-renderer-start-pos=&quot;24492&quot;&gt;Função &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;array_merge()&lt;/code&gt;: unindo dois ou mais arrays&lt;/h3&gt;
&lt;pre&gt;$pares = [0, 2];&lt;br&gt;$mais_pares = [4, 6];&lt;br&gt;$impares = [1, 3, 5];&lt;br&gt;&lt;br&gt;$numeros = array_merge($pares, $mais_pares, $impares);&lt;br&gt;foreach ($numeros as $i =&amp;gt; $numero) {&lt;br&gt;  echo &quot;O número $i é $numero.&quot;;&lt;br&gt;}&lt;br&gt;&lt;br&gt;// O número 0 é 0&lt;br&gt;// O número 1 é 2&lt;br&gt;// O número 2 é 4&lt;br&gt;// O número 3 é 6&lt;br&gt;// O número 4 é 1&lt;br&gt;// O número 4 é 3&lt;br&gt;// O número 5 é 5&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;24860&quot;&gt;&lt;a href=&quot;https://www.php.net/manual/pt_BR/function.array-merge.php&quot; title=&quot;https://www.php.net/manual/pt_BR/function.array-merge.php&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Visite a página da documentação oficial para aprender mais sobre a função &lt;em data-renderer-mark=&quot;true&quot;&gt;array_merge()&lt;/em&gt;.&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;Função-array_unique():-remove-elementos-repetidos-do-array&quot; data-renderer-start-pos=&quot;24950&quot;&gt;Função &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;array_unique()&lt;/code&gt;: remove elementos repetidos do array&lt;/h3&gt;
&lt;pre&gt;$numeros = [0, 2, 2, 4, 6, 4];&lt;br&gt;$numeros_sem_repeticao = array_unique($numeros);&lt;br&gt;&lt;br&gt;foreach ($numeros as $i =&amp;gt; $numero) {&lt;br&gt;  echo &quot;O número $i é $numero.&quot;;&lt;br&gt;}&lt;br&gt;&lt;br&gt;// O número 0 é 0&lt;br&gt;// O número 1 é 2&lt;br&gt;// O número 2 é 4&lt;br&gt;// O número 3 é 6&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;25238&quot;&gt;&lt;a href=&quot;https://www.php.net/manual/pt_BR/function.array-unique.php&quot; title=&quot;https://www.php.net/manual/pt_BR/function.array-unique.php&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Visite a página da documentação oficial para aprender mais sobre a função &lt;em data-renderer-mark=&quot;true&quot;&gt;array_unique()&lt;/em&gt;.&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;Função-array_fill():-cria-array-com-tamanho-e-conteúdo-definidos&quot; data-renderer-start-pos=&quot;25329&quot;&gt;Função &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;array_fill()&lt;/code&gt;: cria array com tamanho e conteúdo definidos&lt;/h3&gt;
&lt;pre&gt;$quatro_zeros = array_fill(0, 4, 0);&lt;br&gt;&lt;br&gt;foreach ($quatro_zeros as $i =&amp;gt; $valor) {&lt;br&gt;  echo &quot;O número $i é $valor.&quot;;&lt;br&gt;}&lt;br&gt;&lt;br&gt;// O número 0 é 0&lt;br&gt;// O número 1 é 0&lt;br&gt;// O número 2 é 0&lt;br&gt;// O número 3 é 0&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;25583&quot;&gt;&lt;a href=&quot;https://www.php.net/manual/pt_BR/function.array-fill.php&quot; title=&quot;https://www.php.net/manual/pt_BR/function.array-fill.php&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Visite a página da documentação oficial para aprender mais sobre a função &lt;em data-renderer-mark=&quot;true&quot;&gt;array_fill()&lt;/em&gt;.&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;Função-array_sum():-soma-todos-elementos-de-um-array&quot; data-renderer-start-pos=&quot;25672&quot;&gt;Função &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;array_sum()&lt;/code&gt;: soma todos elementos de um array&lt;/h3&gt;
&lt;pre&gt;$numeros = [0, 1, 2, 3, 4];&lt;br&gt;$soma = array_sum($numeros);&lt;br&gt;&lt;br&gt;echo &quot;A soma dos 5 primeiros números é $soma.&quot;;&lt;br&gt;// A soma dos 5 primeiros números é 10&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;25872&quot;&gt;&lt;a href=&quot;https://www.php.net/manual/pt_BR/function.array-sum.php&quot; title=&quot;https://www.php.net/manual/pt_BR/function.array-sum.php&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Visite a página da documentação oficial para aprender mais sobre a função &lt;em data-renderer-mark=&quot;true&quot;&gt;array_sum()&lt;/em&gt;.&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;Função-array_map():-aplica-uma-função-a-cada-elemento-do-array-e-retorna-um-novo-array&quot; data-renderer-start-pos=&quot;25960&quot;&gt;Função &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;array_map()&lt;/code&gt;: aplica uma função a cada elemento do array e retorna um novo array&lt;/h3&gt;
&lt;pre&gt;function dobrar_numero(int $x): int&lt;br&gt;{&lt;br&gt;  return $x * 2;&lt;br&gt;}&lt;br&gt;&lt;br&gt;$numeros = [0, 1, 2, 3, 4];&lt;br&gt;$dobro = array_map(&apos;dobrar_numero&apos;, $numeros);&lt;br&gt;&lt;br&gt;for ($i = 0; $i &amp;lt; count($numeros); $i++ ) {&lt;br&gt;  echo &quot;O dobro de $numeros[$i] é $dobro[$i].&quot;;&lt;br&gt;}&lt;br&gt;&lt;br&gt;// O dobro de 0 é 0&lt;br&gt;// O dobro de 1 é 2&lt;br&gt;// O dobro de 2 é 4&lt;br&gt;// O dobro de 3 é 6&lt;br&gt;// O dobro de 4 é 8&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;26378&quot;&gt;&lt;a href=&quot;https://www.php.net/manual/pt_BR/function.array-map.php&quot; title=&quot;https://www.php.net/manual/pt_BR/function.array-map.php&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Visite a página da documentação oficial para aprender mais sobre a função &lt;em data-renderer-mark=&quot;true&quot;&gt;array_map()&lt;/em&gt;.&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;Função-array_filter():-remove-elementos-de-um-array-de-acordo-com-um-critério&quot; data-renderer-start-pos=&quot;26466&quot;&gt;Função &lt;code class=&quot;code css-z5oxh7&quot; data-renderer-mark=&quot;true&quot;&gt;array_filter()&lt;/code&gt;: remove elementos de um array de acordo com um critério&lt;/h3&gt;
&lt;pre&gt;function numero_eh_par(int $x): bool&lt;br&gt;{&lt;br&gt;  return $x % 2 == 0;&lt;br&gt;}&lt;br&gt;&lt;br&gt;$numeros = [0, 1, 2, 3, 4];&lt;br&gt;$pares = array_filter($numeros, &apos;numero_eh_par&apos;);&lt;br&gt;&lt;br&gt;foreach ($pares as $i =&amp;gt; $numero) {&lt;br&gt;  echo &quot;O número par $i é $numero.&quot;;&lt;br&gt;}&lt;br&gt;&lt;br&gt;// O número par 0 é 0&lt;br&gt;// O número par 1 é 2&lt;br&gt;// O número par 2 é 4&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;26831&quot;&gt;&lt;a href=&quot;https://www.php.net/manual/pt_BR/function.array-filter.php&quot; title=&quot;https://www.php.net/manual/pt_BR/function.array-filter.php&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Visite a página da documentação oficial para aprender mais sobre a função &lt;em data-renderer-mark=&quot;true&quot;&gt;array_filter()&lt;/em&gt;.&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;Como-trabalhar-com-JSON-e-arrays-no-PHP?&quot; data-renderer-start-pos=&quot;26922&quot;&gt;Como trabalhar com JSON e arrays no PHP?&lt;/h2&gt;
&lt;p&gt;Podemos transformar arrays de índice numérico ou associativos para transformar uma variável em JSON utilizando a função &lt;a href=&quot;https://www.php.net/manual/pt_BR/function.json-encode&quot; title=&quot;https://www.php.net/manual/pt_BR/function.json-encode&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;json_encode()&lt;/em&gt;&lt;/a&gt;, e podemos também transformar uma string JSON em array utilizando a função &lt;a href=&quot;https://www.php.net/manual/pt_BR/function.json-decode.php&quot; title=&quot;https://www.php.net/manual/pt_BR/function.json-decode.php&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;json_decode()&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;$json = &apos;{&quot;site&quot;: &quot;https://codamos.com.br&quot;, &quot;nota&quot;: 10.0}&apos;;&lt;br&gt;&lt;br&gt;$avaliacao = json_decode($json);&lt;br&gt;echo &quot;O site {$avaliacao[&apos;site&apos;]} é nota {$avaliacao[&apos;nota&apos;]}!&quot;;&lt;br&gt;// O site https://codamos.com.br é nota 10.0!&lt;br&gt;&lt;br&gt;$avaliacao[&apos;fonte&apos;] = &apos;Eu mesmo&apos;;&lt;br&gt;$novo_json = json_encode($avaliacao);&lt;br&gt;echo $novo_json;&lt;br&gt;// {&quot;site&quot;: &quot;https://codamos.com.br&quot;, &quot;nota&quot;: 10.0, &quot;fonte&quot;: &quot;Eu mesmo&quot;}&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;27555&quot;&gt;Isto é muito útil para trabalhar com APIs rest ou mesmo para ler e escrever configurações em arquivos.&lt;/p&gt;
&lt;h2 id=&quot;Conclusão&quot; data-renderer-start-pos=&quot;27659&quot;&gt;Conclusão&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;27670&quot;&gt;Arrays são um dos principais elementos que tornam a linguagem PHP tão poderosa e este artigo, por maior que pareça ser grande e extensivo, apenas toca na superfície do tópico.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;27847&quot;&gt;Assim que dominar os tópicos apresentados aqui eu recomendo que você leia mais sobre &lt;a href=&quot;https://www.php.net/manual/pt_BR/class.iterator&quot; title=&quot;https://www.php.net/manual/pt_BR/class.iterator&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Iterators&lt;/a&gt; e, por conseguinte, classes do tipo Iterator como o &lt;a href=&quot;https://www.php.net/manual/pt_BR/class.arrayobject&quot; title=&quot;https://www.php.net/manual/pt_BR/class.arrayobject&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;ArrayObject&lt;/a&gt;, &lt;a href=&quot;https://www.php.net/manual/pt_BR/class.splstack.php&quot; title=&quot;https://www.php.net/manual/pt_BR/class.splstack.php&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;SplStack&lt;/a&gt; e &lt;a href=&quot;https://www.php.net/manual/pt_BR/spl.iterators.php&quot; title=&quot;https://www.php.net/manual/pt_BR/spl.iterators.php&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;classes iteradores especiais da linguagem&lt;/a&gt;. A partir daqui você também deverá ter um arcabouço maior para entender como funcionam as &lt;a href=&quot;https://laravel.com/docs/9.x/collections&quot; title=&quot;https://laravel.com/docs/9.x/collections&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;Collections&lt;/em&gt; do Laravel&lt;/a&gt;.&lt;/p&gt;
&lt;p class=&quot;msg msg--info&quot; data-renderer-start-pos=&quot;27847&quot;&gt;Não esquece de compartilhar este artigo com amigos e colegas de curso ou de trabalho, isto ajuda bastante o blog a crescer e produzir mais conteúdo de qualidade pra quem é dev!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;28355&quot;&gt;Num futuro próximo eu devo escrever também sobre como arrays se comportam em memória e como otimizar a utilização de memória quando trabalhamos com listas.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;28512&quot;&gt;Até a próxima 👋&lt;/p&gt;</content:encoded><category>junior</category><category>php</category></item><item><title>Como começar com programação em 2023 de graça e online</title><link>https://codamos.com.br/aprender-a-programar-online-de-graca-em-2023/</link><guid isPermaLink="true">https://codamos.com.br/aprender-a-programar-online-de-graca-em-2023/</guid><description>Já faz um bom tempo que venho mentorando pessoas que querem ingressar ou melhorar na área de desenvolvimento de software. E com o tempo comecei a identificar alguns erros e dificuldades comuns que atr</description><pubDate>Thu, 24 Nov 2022 02:25:53 GMT</pubDate><content:encoded>&lt;p data-renderer-start-pos=&quot;4&quot;&gt;Já faz um bom tempo que venho mentorando pessoas que querem ingressar ou melhorar na área de desenvolvimento de software. E com o tempo comecei a identificar alguns erros e dificuldades comuns que atrapalhavam a vida da pessoa desenvolvedora que está iniciando.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;4&quot;&gt;Este guia vai te mostrar os primeiros passos que você deve tomar para aprender a programar para web em 2023. &lt;strong&gt;Você precisa começar a entender a mecânica da linguagem (sintaxe) e depois avançar com lógica na prática, através de projetos e cursos.&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;post__toc&quot;&gt;
&lt;h3&gt;Conteúdos do artigo&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1gijmloas6&quot;&gt;Entre no nosso grupo de apoio no Telegram&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1gijn2ktp9t&quot;&gt;Comece pelo HTML&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1gijn2ktp9u&quot;&gt;Passeie pelo CSS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1gijn2ktp9v&quot;&gt;Primeira linguagem de programação: JavaScript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1gijn2ktpa0&quot;&gt;Familiarize-se com a linha de comando&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1gijn2ktpa1&quot;&gt;Aprenda o básico sobre git e github&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1gijn2ktpa2&quot;&gt;Faça uma aplicação clone&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1gijn2ktpa3&quot;&gt;Revise sua aplicação clona&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1gijn2ktpa4&quot;&gt;Dê uma pausa e reflita sobre onde você está&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1gijn2ktpa5&quot;&gt;Conclusão&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id=&quot;mcetoc_1gijmloas6&quot; data-renderer-start-pos=&quot;501&quot;&gt;Entre no nosso grupo de apoio no Telegram&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;548&quot;&gt;A comunidade Codamos está crescendo e está pronta pra te ajudar em todas as fases da sua jornada com desenvolvimento de software!&lt;/p&gt;
&lt;div class=&quot;ak-editor-panel css-ppieed&quot; data-panel-type=&quot;custom&quot; data-panel-color=&quot;#ABF5D1&quot; data-panel-icon=&quot;:info:&quot; data-panel-icon-id=&quot;atlassian-info&quot;&gt;
&lt;div class=&quot;ak-editor-panel__content&quot;&gt;
&lt;p class=&quot;msg msg--success&quot; data-renderer-start-pos=&quot;680&quot;&gt;Nós temos &lt;a href=&quot;https://t.me/codamos_forum&quot; title=&quot;https://t.me/codamos_forum&quot; rel=&quot;nofollow&quot;&gt;um canal no telegram&lt;/a&gt; onde compartilhamos conhecimento, trocamos dúvidas e respostas e indicamos vídeos e cursos.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-renderer-start-pos=&quot;805&quot;&gt;Estudar com o apoio de outras pessoas ajuda muito a manter a motivação lá no alto. Principalmente no começo, quando não sabemos nem sequer como fazer a pergunta certa.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;974&quot;&gt;Entra no grupo, é de graça e você só tende a crescer!&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1gijn2ktp9t&quot; data-renderer-start-pos=&quot;1029&quot;&gt;Comece pelo HTML&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;1051&quot;&gt;&lt;a href=&quot;https://pt.wikipedia.org/wiki/HTML&quot; title=&quot;https://pt.wikipedia.org/wiki/HTML&quot; rel=&quot;nofollow&quot;&gt;A linguagem HTML&lt;/a&gt; é uma linguagem de marcação de hipertexto, que serve para criar páginas da internet que você vê através de navegadores como Google Chrome ou Mozilla Firefox. Apesar de não ser considerada uma linguagem de programação, é uma das bases da internet.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1316&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Quem quer trabalhar com web precisa saber ao menos o mínimo sobre HTML&lt;/strong&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1389&quot;&gt;Eu gosto de recomendar iniciantes a aprender HTML porque é uma linguagem relativamente simples mas bastante poderosa. &lt;strong data-renderer-mark=&quot;true&quot;&gt;Você vê os resultados de seus estudos imediatamente!&lt;/strong&gt;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1561&quot;&gt;Toda linguagem de programação tem uma série de regrinhas de escrita, chamada &lt;em data-renderer-mark=&quot;true&quot;&gt;sintaxe&lt;/em&gt;. Aprender HTML é uma forma incrível de se acostumar com a ideia de sintaxe porque você consegue entender melhor como o computador analisa a sintaxe com uma linguagem simples e com regras bem definidas.&lt;/p&gt;
&lt;div class=&quot;ak-editor-panel css-431guk&quot; data-panel-type=&quot;custom&quot; data-panel-color=&quot;#E3FCEF&quot; data-panel-icon=&quot;:info:&quot; data-panel-icon-id=&quot;atlassian-info&quot;&gt;
&lt;div class=&quot;ak-editor-panel__content&quot;&gt;
&lt;p class=&quot;msg msg--success&quot; data-renderer-start-pos=&quot;1850&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Dica de ouro – curso gratuito! 🤩&lt;br&gt;&lt;br&gt;&lt;/strong&gt;O site freeCodeCamp oferece um curso MARAVILHOSO de HTML que é 100% gratuito e tem tradução para o Português. Eu recomendo começar por lá: é um curso que te ensina HTML na prática e te mostra cada detalhezinho da linguagem. &lt;a href=&quot;https://www.freecodecamp.org/learn/2022/responsive-web-design/&quot; title=&quot;https://www.freecodecamp.org/learn/2022/responsive-web-design/&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Clica aqui pra acessar o curso&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-renderer-start-pos=&quot;2143&quot;&gt;Começar com HTML vai te ajudar a:&lt;/p&gt;
&lt;ul class=&quot;ak-ul&quot; data-indent-level=&quot;1&quot;&gt;
&lt;li&gt;
&lt;p data-renderer-start-pos=&quot;2180&quot;&gt;Entender como funciona a sintaxe de uma linguagem;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;Se motivar com resultados imediatos;&lt;/li&gt;
&lt;li&gt;Escrever suas próprias páginas web&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;mcetoc_1gijn2ktp9u&quot; data-renderer-start-pos=&quot;2312&quot;&gt;Passeie pelo CSS&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;2334&quot;&gt;Com o HTML você é capaz de fazer muita coisa, mas a internet já mudou muito desde que o HTML apareceu e hoje em dia nós temos requisitos de aparência visual de uma página web muito elevados!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2526&quot;&gt;Com CSS você consegue alterar a aparência da sua página HTML de forma a mudar as fontes, cores, posição de elementos, deixar algumas coisas fixas no &lt;em data-renderer-mark=&quot;true&quot;&gt;layout&lt;/em&gt; e por aí vai.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2697&quot;&gt;Eu acho interessante aprender pelo menos o básico de CSS pra entender como a tecnologia funciona, além de te forçar a aprender mais sobre como funciona o seu navegador web.&lt;/p&gt;
&lt;div class=&quot;ak-editor-panel css-431guk&quot; data-panel-type=&quot;custom&quot; data-panel-color=&quot;#E3FCEF&quot; data-panel-icon=&quot;:info:&quot; data-panel-icon-id=&quot;atlassian-info&quot;&gt;
&lt;div class=&quot;ak-editor-panel__content&quot;&gt;
&lt;p class=&quot;msg msg--success&quot; data-renderer-start-pos=&quot;2872&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Dica de ouro – curso gratuito! 🤩&lt;br&gt;&lt;br&gt;&lt;/strong&gt;O mesmo curso de HTML citado acima tem um módulo inteirinho só de CSS. No mesmo estilo: cada parte do curso é um teste prático que você precisa resolver para ir ao próximo. &lt;a href=&quot;https://www.freecodecamp.org/learn/2022/responsive-web-design/&quot; title=&quot;https://www.freecodecamp.org/learn/2022/responsive-web-design/&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Clica aqui pra acessar o curso&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-renderer-start-pos=&quot;3114&quot;&gt;Alguns sites interessantes para ver mais sobre CSS são o &lt;a href=&quot;https://tableless.com.br/categories/css/&quot; title=&quot;https://tableless.com.br/categories/css/&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Tableless&lt;/a&gt; (em português) e &lt;a href=&quot;https://css-tricks.com/&quot; title=&quot;https://css-tricks.com/&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;CSS Tricks&lt;/a&gt; (em inglês).&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3223&quot;&gt;Aprender CSS mesmo que superficialmente vai te ajudar a:&lt;/p&gt;
&lt;ul class=&quot;ak-ul&quot; data-indent-level=&quot;1&quot;&gt;
&lt;li&gt;
&lt;p data-renderer-start-pos=&quot;3283&quot;&gt;Entender regras de sintaxe de outra linguagem;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;Obter resultados visuais;&lt;/li&gt;
&lt;li&gt;Fazer projetos web completos e funcionais;&lt;/li&gt;
&lt;li&gt;Acompanhar vídeo tutoriais e mini cursos que desenvolvem projetos e clones&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-renderer-start-pos=&quot;3486&quot;&gt;Ao conseguir trabalhar, mesmo que só com o básico, de HTML e CSS você já consegue fazer alguns projetos para praticar e montar seu portfolio. Existe centenas de milhares de vídeos na internet de pessoas que fazem projetos passo a passo com HTML e CSS que você pode acompanhar para praticar.&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1gijn2ktp9v&quot; data-renderer-start-pos=&quot;3778&quot;&gt;Primeira linguagem de programação: JavaScript&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;3829&quot;&gt;A primeira linguagem de programação que eu recomendo pra quem começa agora em 2023 é o JavaScript.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3929&quot;&gt;Isso porque no começo você não sabe bem o que quer fazer: back end, front end, DevOps… e o JavaScript vai te acompanhar em quase todas as áreas.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;4075&quot;&gt;Eu particularmente não gosto de JavaScript, prefiro ensinar com PHP que é muito mais simples e fácil de aprender na minha opinião. Mas em termos de utilidade o JavaScript vai te acompanhar por mais tempo.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;4281&quot;&gt;Quando aprender JavaScript eu recomendo separar seu estudo em duas partes: sintaxe (como escrever código) e lógica (como fazer um código útil).&lt;/p&gt;
&lt;div class=&quot;ak-editor-panel css-431guk&quot; data-panel-type=&quot;custom&quot; data-panel-color=&quot;#E3FCEF&quot; data-panel-icon=&quot;:info:&quot; data-panel-icon-id=&quot;atlassian-info&quot;&gt;
&lt;div class=&quot;ak-editor-panel__content&quot;&gt;
&lt;p class=&quot;msg msg--success&quot; data-renderer-start-pos=&quot;4427&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Dica de ouro – curso gratuito! 🤩&lt;br&gt;&lt;br&gt;&lt;/strong&gt;Ainda fazendo propaganda gratuita do freecodecamp, a plataforma tem um curso gratuito focado em JavaScript. &lt;a href=&quot;https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/&quot; title=&quot;https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Clica aqui pra acessar o curso&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-renderer-start-pos=&quot;4604&quot;&gt;Estudar lógica é um pouco mais complicado: você precisa praticar bastante. Então é melhor praticar de um jeito que você goste pra não perder a motivação!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;4759&quot;&gt;Você pode fazer exercícios de programação em JavaScript em sites como o &lt;a href=&quot;https://www.hackerrank.com/products/main/&quot; title=&quot;https://www.hackerrank.com/products/main/&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;HackerRank&lt;/a&gt;. Mas eu recomendo imensamente fazer projetos acompanhando vídeos. No YouTube você encontra diferentes guias de como escrever jogos, clones de sites conhecidos como Twitter ou Netflix.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;5027&quot;&gt;Um exemplo incrível desses projetinhos em vídeo é a Pokédex do Manual do Dev, se liga:&lt;/p&gt;
&lt;div class=&quot;ak-renderer-extension  &quot; data-layout=&quot;default&quot;&gt;
&lt;div class=&quot;ak-renderer-extension-overflow-container&quot;&gt;
&lt;div class=&quot;css-1hi6bj2 e1ihjts80&quot; data-fabric-macro=&quot;6aadefce20bf5b7d21cabf0dcaba1952&quot; data-macro-body=&quot;&quot; data-macro-parameters=&quot;{&amp;quot;overlay&amp;quot;:&amp;quot;youtube&amp;quot;,&amp;quot;_parentId&amp;quot;:&amp;quot;74940417&amp;quot;,&amp;quot;_template&amp;quot;:&amp;quot;com/atlassian/confluence/extra/widgetconnector/templates/youtube.vm&amp;quot;,&amp;quot;width&amp;quot;:&amp;quot;740px&amp;quot;,&amp;quot;url&amp;quot;:&amp;quot;https://www.youtube.com/watch?v=SjtdH3dWLa8&amp;quot;,&amp;quot;height&amp;quot;:&amp;quot;400px&amp;quot;}&quot; data-testid=&quot;legacy-macro-element&quot;&gt;&lt;iframe width=&quot;560&quot; height=&quot;314&quot; class=&quot;youtube-player conf-macro output-block&quot; data-hasbody=&quot;false&quot; data-local-id=&quot;57084b88-489f-4bee-aac9-fdbea44935d1&quot; data-macro-id=&quot;6aadefce20bf5b7d21cabf0dcaba1952&quot; data-macro-name=&quot;widget&quot; frameborder=&quot;0&quot; src=&quot;https://www.youtube.com/embed/SjtdH3dWLa8&quot; type=&quot;text/html&quot; data-mce-fragment=&quot;1&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&quot;mcetoc_1gijn2ktpa0&quot; data-renderer-start-pos=&quot;5116&quot;&gt;Familiarize-se com a linha de comando&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;5159&quot;&gt;Trabalhar com linha de comando não é obrigatório, mas vai te ajudar MUITO a entender como o computador funciona. A minha intenção em te falar pra aprender a usar a linha de comando não está nem relacionada com aprender algo novo, mas sim de fazer imersão!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;5416&quot;&gt;Se você usa o Windows, pode começar com o Windows Power Shell. Esta é a ferramenta padrão do Windows e te dá uma flexibilidade incrível na hora de trabalhar. Aqui tem um vídeo de como abrir o terminal e com alguns comandos básicos pra você começar no Windows.&lt;/p&gt;
&lt;div class=&quot;ak-renderer-extension  &quot; data-layout=&quot;default&quot;&gt;
&lt;div class=&quot;ak-renderer-extension-overflow-container&quot;&gt;
&lt;div class=&quot;css-1hi6bj2 e1ihjts80&quot; data-fabric-macro=&quot;3d92b0227838bd9f43c410101c177fe5&quot; data-macro-body=&quot;&quot; data-macro-parameters=&quot;{&amp;quot;overlay&amp;quot;:&amp;quot;youtube&amp;quot;,&amp;quot;_parentId&amp;quot;:&amp;quot;74940417&amp;quot;,&amp;quot;_template&amp;quot;:&amp;quot;com/atlassian/confluence/extra/widgetconnector/templates/youtube.vm&amp;quot;,&amp;quot;width&amp;quot;:&amp;quot;400px&amp;quot;,&amp;quot;url&amp;quot;:&amp;quot;https://www.youtube.com/watch?v=xOdfGoJfr9Q&amp;quot;,&amp;quot;height&amp;quot;:&amp;quot;300px&amp;quot;}&quot; data-testid=&quot;legacy-macro-element&quot;&gt;&lt;iframe width=&quot;560&quot; height=&quot;314&quot; class=&quot;youtube-player conf-macro output-block&quot; data-hasbody=&quot;false&quot; data-local-id=&quot;ca5b3f11-d15d-4b0a-a870-079ac40db702&quot; data-macro-id=&quot;3d92b0227838bd9f43c410101c177fe5&quot; data-macro-name=&quot;widget&quot; frameborder=&quot;0&quot; src=&quot;https://www.youtube.com/embed/xOdfGoJfr9Q&quot; type=&quot;text/html&quot; data-mce-fragment=&quot;1&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-renderer-start-pos=&quot;5678&quot;&gt;Pra quem usa Linux ou MacOS, o próprio sistema te oferece um terminal que te dá acesso a fazer tudo o que quiser e mais um pouco! E o legal destes desses dois sistemas é que normalmente o mesmo comando funciona tanto no Linux quanto no MacOS.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;5922&quot;&gt;Aqui um vídeo de como abrir o terminal no Linux (Ubuntu) e alguns comandos básicos.&lt;/p&gt;
&lt;div class=&quot;ak-renderer-extension  &quot; data-layout=&quot;default&quot;&gt;
&lt;div class=&quot;ak-renderer-extension-overflow-container&quot;&gt;
&lt;div class=&quot;css-1hi6bj2 e1ihjts80&quot; data-fabric-macro=&quot;09939706f81f004af04e1701ffdcad18&quot; data-macro-body=&quot;&quot; data-macro-parameters=&quot;{&amp;quot;overlay&amp;quot;:&amp;quot;youtube&amp;quot;,&amp;quot;_parentId&amp;quot;:&amp;quot;74940417&amp;quot;,&amp;quot;_template&amp;quot;:&amp;quot;com/atlassian/confluence/extra/widgetconnector/templates/youtube.vm&amp;quot;,&amp;quot;width&amp;quot;:&amp;quot;400px&amp;quot;,&amp;quot;url&amp;quot;:&amp;quot;https://www.youtube.com/watch?v=JEhVB4VHsTI&amp;quot;,&amp;quot;height&amp;quot;:&amp;quot;300px&amp;quot;}&quot; data-testid=&quot;legacy-macro-element&quot;&gt;&lt;iframe width=&quot;560&quot; height=&quot;314&quot; class=&quot;youtube-player conf-macro output-block&quot; data-hasbody=&quot;false&quot; data-local-id=&quot;09bb4619-5c62-42d0-b7cd-b3ba038115bc&quot; data-macro-id=&quot;09939706f81f004af04e1701ffdcad18&quot; data-macro-name=&quot;widget&quot; frameborder=&quot;0&quot; src=&quot;https://www.youtube.com/embed/JEhVB4VHsTI&quot; type=&quot;text/html&quot; data-mce-fragment=&quot;1&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&quot;mcetoc_1gijn2ktpa1&quot; data-renderer-start-pos=&quot;6008&quot;&gt;Aprenda o básico sobre git e github&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;6049&quot;&gt;GIT é uma ferramenta incrível pra armazenar e controlar seus arquivos. E o GitHub te permite fazer isso de graça online, sem limites. Pra além disso você consegue usar o GitHub como uma plataforma pra exibir seu portfólio e também pra contribuir com outros projetos!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;6317&quot;&gt;Aprender GIT vai te dar uma ajuda muito boa em procurar e navegar projetos escritos por outras pessoas.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;6422&quot;&gt;Mas não precisa fazer um mega curso e ficar especialista no assunto. O básico já é suficiente pros seus primeiros anos na carreira.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;6555&quot;&gt;Aqui no blog a gente tem &lt;strong data-renderer-mark=&quot;true&quot;&gt;&lt;a href=&quot;/subindo-arquivos-no-github/&quot;&gt;um artigo muito legal e detalhado pra te ajudar a começar com GIT&lt;/a&gt;&lt;/strong&gt;. Dá uma lida no artigo e aproveita pra ver o vídeo de apoio que tem lá. Vai te ensinar tudo o que você precisa de começo.&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1gijn2ktpa2&quot; data-renderer-start-pos=&quot;6769&quot;&gt;Faça uma aplicação clone&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;6799&quot;&gt;Nessa altura do campeonato você já aprendeu HTML, CSS, JS e GIT. Está mais do que na hora de fazer alguns projetos que possam te servir de portfólio pra subir no Github!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;6970&quot;&gt;Aplicações clone são uma forma incrível de montar seu portfólio, porque você não precisa se preocupar com conceitos, design, requisitos… você só precisa copiar o que já existe!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;7148&quot;&gt;Alguns cursos e vídeos online te mostram como fazer clones do Twitter, do Netflix, do site de alguma marca…&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;7257&quot;&gt;Eu encontrei, por exemplo, este vídeo incrível da Lari que mostra como ela montou um clone da tela de login do Netflix. Dá uma olhadinha:&lt;/p&gt;
&lt;div class=&quot;ak-renderer-extension  &quot; data-layout=&quot;default&quot;&gt;
&lt;div class=&quot;ak-renderer-extension-overflow-container&quot;&gt;
&lt;div class=&quot;css-1hi6bj2 e1ihjts80&quot; data-fabric-macro=&quot;def3140c0acb8ecaafe5db22e69e2268&quot; data-macro-body=&quot;&quot; data-macro-parameters=&quot;{&amp;quot;overlay&amp;quot;:&amp;quot;youtube&amp;quot;,&amp;quot;_parentId&amp;quot;:&amp;quot;74940417&amp;quot;,&amp;quot;_template&amp;quot;:&amp;quot;com/atlassian/confluence/extra/widgetconnector/templates/youtube.vm&amp;quot;,&amp;quot;width&amp;quot;:&amp;quot;400px&amp;quot;,&amp;quot;url&amp;quot;:&amp;quot;https://www.youtube.com/watch?v=hmkTPZ_nOik&amp;quot;,&amp;quot;height&amp;quot;:&amp;quot;300px&amp;quot;}&quot; data-testid=&quot;legacy-macro-element&quot;&gt;&lt;iframe width=&quot;560&quot; height=&quot;314&quot; class=&quot;youtube-player conf-macro output-block&quot; data-hasbody=&quot;false&quot; data-local-id=&quot;d482d36d-402e-425c-865c-e15095c75a85&quot; data-macro-id=&quot;def3140c0acb8ecaafe5db22e69e2268&quot; data-macro-name=&quot;widget&quot; frameborder=&quot;0&quot; src=&quot;https://www.youtube.com/embed/hmkTPZ_nOik&quot; type=&quot;text/html&quot; data-mce-fragment=&quot;1&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-renderer-start-pos=&quot;7397&quot;&gt;A parte bacana de fazer um curso de criar aplicação clone é que, se em algum momento você travar, ainda pode copiar diretamente do vídeo e continuar aprendendo outras coisas.&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1gijn2ktpa3&quot; data-renderer-start-pos=&quot;7573&quot;&gt;Revise sua aplicação clone&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;7605&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;&lt;a href=&quot;/programacao-por-coincidencia/&quot;&gt;Eu já escrevi aqui sobre erros comuns que iniciantes cometem&lt;/a&gt;&lt;/strong&gt;, que dificultam o aprendizado e até atrasam quem tá começando agora. E uma das técnicas pra evitar estes erros é a &lt;strong data-renderer-mark=&quot;true&quot;&gt;&lt;a href=&quot;/livro-refactoring-martin-fowler/&quot;&gt;refatoração&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;7795&quot;&gt;O simples exercício de você revisar e melhorar um código que você já escreveu vai te ajudar a entender melhor o que seu código faz e o que você ainda precisa estudar melhor.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;7970&quot;&gt;Muitas vezes quem é iniciante e escreve uma aplicação clone com apoio de vídeo aulas não consegue entender 100% do código que escreveu. Por isso o exercício de revisão e melhoramento do código é essencial.&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1gijn2ktpa4&quot; data-renderer-start-pos=&quot;8177&quot;&gt;Dê uma pausa e reflita sobre onde você está&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;8224&quot;&gt;Se você tiver concluído cada um dos passos que eu mencionei aqui, provavelmente estará bem mais confortável com o tópico programação e já tem dúvidas o suficiente pra saber o que perguntar e por onde ir.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;8429&quot;&gt;Um ponto importante é não se afobar e tentar dar passos maiores que a perna, pra evitar perda de tempo, de energia e até mesmo se frustrar no processo.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;8582&quot;&gt;O Leonardo Leitão da Cod3r Cursos fez um vídeo sensacional que explica as diferentes fases na vida de uma pessoa que resolve aprender a fazer desenvolvimento de software e como se portar em cada fase. Vídeo recomendadíssimo!&lt;/p&gt;
&lt;div class=&quot;ak-renderer-extension  &quot; data-layout=&quot;default&quot;&gt;
&lt;div class=&quot;ak-renderer-extension-overflow-container&quot;&gt;
&lt;div class=&quot;css-1hi6bj2 e1ihjts80&quot; data-fabric-macro=&quot;82f11d3fcec70594b9ceed387da0d856&quot; data-macro-body=&quot;&quot; data-macro-parameters=&quot;{&amp;quot;overlay&amp;quot;:&amp;quot;youtube&amp;quot;,&amp;quot;_parentId&amp;quot;:&amp;quot;74940417&amp;quot;,&amp;quot;_template&amp;quot;:&amp;quot;com/atlassian/confluence/extra/widgetconnector/templates/youtube.vm&amp;quot;,&amp;quot;width&amp;quot;:&amp;quot;400px&amp;quot;,&amp;quot;url&amp;quot;:&amp;quot;https://www.youtube.com/watch?v=WPppEWNgS3A&amp;quot;,&amp;quot;height&amp;quot;:&amp;quot;300px&amp;quot;}&quot; data-testid=&quot;legacy-macro-element&quot;&gt;&lt;iframe width=&quot;560&quot; height=&quot;314&quot; class=&quot;youtube-player conf-macro output-block&quot; data-hasbody=&quot;false&quot; data-local-id=&quot;289cb58e-7ea7-4d48-8273-da882313f054&quot; data-macro-id=&quot;82f11d3fcec70594b9ceed387da0d856&quot; data-macro-name=&quot;widget&quot; frameborder=&quot;0&quot; src=&quot;https://www.youtube.com/embed/WPppEWNgS3A&quot; type=&quot;text/html&quot; data-mce-fragment=&quot;1&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&quot;mcetoc_1gijn2ktpa5&quot; data-renderer-start-pos=&quot;8809&quot;&gt;Conclusão&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;8820&quot;&gt;A partir daqui você já sabe tudo o que precisa para estudar programação sem muito sofrimento: toda a mecânica de lidar com sintaxe de linguagem, alterar código, analisar resultados e melhorar o que fez deverá estar mais ou menos clara.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;9057&quot;&gt;Se você concluiu cada passo, já deve ter proficiência o suficiente pra estudar algoritmos e aprender outros conceitos como o de utilizar bancos de dados ou criar APIs.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;9226&quot;&gt;Desenvolvimento de software é uma profissão na qual você nunca para de estudar. Continue buscando artigos na internet, escute podcasts, leia livros, participe de conferências… enfim! Você já tem tudo o que precisa pra estudar programação.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;9466&quot;&gt;Boa sorte em sua jornada!&lt;/p&gt;</content:encoded><category>carreira</category><category>junior</category></item><item><title>Como visualizar e editar arquivos binários usando xxd</title><link>https://codamos.com.br/como-visualizar-e-editar-arquivos-binarios-com-xxd/</link><guid isPermaLink="true">https://codamos.com.br/como-visualizar-e-editar-arquivos-binarios-com-xxd/</guid><description>Recentemente eu resolvi aprender um pouco mais sobre engenharia reversa de arquivos na intenção de converter um arquivo do tipo studio3 para cwprj . Eu ainda não cheguei lá, mas já aprendi diferentes </description><pubDate>Mon, 31 Oct 2022 20:00:35 GMT</pubDate><content:encoded>&lt;p data-renderer-start-pos=&quot;4&quot;&gt;Recentemente eu resolvi aprender um pouco mais sobre engenharia reversa de arquivos na intenção de converter um arquivo do tipo &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;studio3&lt;/code&gt; para &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;cwprj&lt;/code&gt;. Eu ainda não cheguei lá, mas já aprendi diferentes truques interessantes e vim compartilhar um essencial contigo!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;267&quot;&gt;Neste artigo eu vou te dar uma dica rápida: como converter um arquivo binário em um &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;dump&lt;/code&gt; hexadecimal, e como transformar este &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;dump&lt;/code&gt; hexadecimal em binário novamente.&lt;/p&gt;
&lt;div class=&quot;post__toc&quot;&gt;
&lt;h3&gt;Conteúdos do post&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#Como-transformar-um-arquivo-binário-em-texto-hexadecimal-usando-xxd&quot;&gt;Como transformar um arquivo binário em texto hexadecimal usando xxd&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Como-converter-um-dump-em-hexadecimal-para-binário&quot;&gt;Como converter um dump em hexadecimal para binário&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Como-converter-um-binário-em-hexadecimal-e-abrir-imediatamente-no-VIM&quot;&gt;Como converter um binário em hexadecimal e abrir imediatamente no VIM&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Como-salvar-o-arquivo-hexadecimal-do-VIM-diretamente-para-binário&quot;&gt;Como salvar o arquivo hexadecimal do VIM diretamente para binário&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;ak-renderer-extension  &quot; data-layout=&quot;default&quot;&gt;
&lt;div class=&quot;ak-renderer-extension-overflow-container&quot;&gt;
&lt;div class=&quot;_1reo1wug _18m91wug _ugi3idpf _gutmidpf&quot; title=&quot;Macro (toc)&quot; data-fabric-macro=&quot;cb01eadd7b3c18f84a2d46c37d36bdad&quot; data-macro-body=&quot;true&quot; data-macro-parameters=&quot;{&amp;quot;minLevel&amp;quot;:{&amp;quot;value&amp;quot;:&amp;quot;1&amp;quot;},&amp;quot;maxLevel&amp;quot;:{&amp;quot;value&amp;quot;:&amp;quot;7&amp;quot;},&amp;quot;_parentId&amp;quot;:{&amp;quot;value&amp;quot;:&amp;quot;73596939&amp;quot;}}&quot; data-testid=&quot;printable-wrapper&quot;&gt;
&lt;div class=&quot;macro-core toc-macro conf-macro output-block&quot; data-headerelements=&quot;H1,H2,H3,H4,H5,H6&quot; data-hasbody=&quot;false&quot; data-macro-name=&quot;toc&quot; data-macro-id=&quot;cb01eadd7b3c18f84a2d46c37d36bdad&quot;&gt;
&lt;h2 id=&quot;Como-transformar-um-arquivo-binário-em-texto-hexadecimal-usando-xxd&quot; data-renderer-start-pos=&quot;434&quot;&gt;Como transformar um arquivo binário em texto hexadecimal usando &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;xxd&lt;/code&gt;&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;503&quot;&gt;Vamos supor um arquivo em formato binário. No meu caso, venho utilizando um arquivo do tipo &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;.studio3&lt;/code&gt;, mas você provavelmente já viu diversos exemplos por aí: &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;.bin&lt;/code&gt;, &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;.dat&lt;/code&gt;, &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;.spr&lt;/code&gt;, &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;.save&lt;/code&gt; ou o famoso &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;.wad&lt;/code&gt; do jogo DOOM.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;718&quot;&gt;Para converter este arquivo em hexadecimal, podemos utilizar o programa &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;xxd&lt;/code&gt; da seguinte maneira:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;718&quot;&gt;$ xxd empty.studio3&lt;br&gt;&lt;br&gt;00000000: 7369 6c68 6f75 6574 7465 3035 3b00 0000&lt;br&gt;00000010: 1425 0000 0000 0000 1100 0000 0000 0000&lt;br&gt;00000020: e815 0000 0000 0000 a0a6 0000 0000 0000&lt;br&gt;00000030: 8801 0000 0000 0000 3200 0000 0000 0000&lt;br&gt;00000040: 3600 0000 0000 0000 0400 0000 0000 0000&lt;br&gt;00000050: 0400 0000 0000 0000 a706 0000 0000 0000&lt;br&gt;00000060: 5e00 0000 0000 0000 5e00 0000 0000 0000&lt;br&gt;00000070: 0000 0000 0000 0000 5e00 0000 0000 0000&lt;br&gt;....&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;1387&quot;&gt;Note que o comando acima irá lançar a visualização hexadecimal do arquivo diretamente na tela. Isto é útil para fazer uma exploração inicial e se familiarizar com o formato do arquivo.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1573&quot;&gt;Para facilitar a exploração você pode utilizar o comando &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;less&lt;/code&gt; que lhe permite navegar melhor:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;1573&quot;&gt;$ xxd empty.studio3 | less&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;1696&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Para armazenar o arquivo com o conteúdo hexadecimal você pode oferecer um segundo parâmetro ao comando &lt;/strong&gt;&lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;xxd&lt;/code&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt; que recebe o nome do arquivo-destino&lt;/strong&gt;. O exemplo a seguir converte o arquivo &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;empty.studio3&lt;/code&gt; em hexadecimal e armazena seu conteúdo no arquivo &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;empty.dump&lt;/code&gt;.&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;1696&quot;&gt;$ xxd empty.studio3 empty.dump&lt;/pre&gt;
&lt;h2 id=&quot;Como-converter-um-dump-em-hexadecimal-para-binário&quot; data-renderer-start-pos=&quot;1988&quot;&gt;Como converter um &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;dump&lt;/code&gt; em hexadecimal para binário&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;2040&quot;&gt;Visualizar um arquivo binário em formato hexadecimal é utilíssimo! Mas quando buscamos fazer a engenharia reversa de um arquivo, é importante ser capaz de alterar seu conteúdo e visualizar como o software se comporta!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2259&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;O comando &lt;/strong&gt;&lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;xxd&lt;/code&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt; nos permite transformar um &lt;/strong&gt;&lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;dump&lt;/code&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt; em hexadecimal de volta para o formato binário!&lt;/strong&gt;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2354&quot;&gt;Para converter o &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;dump&lt;/code&gt; para binário novamente basta executar o comando &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;xxd&lt;/code&gt; com a opção &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;-r&lt;/code&gt; (reverse). Assim:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;2354&quot;&gt;$ xxd -r empty.dump empty.studio3&lt;/pre&gt;
&lt;p&gt;Desta forma o arquivo &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;empty.studio3&lt;/code&gt; passa a ter o conteúdo do arquivo &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;empty.dump&lt;/code&gt; porém em formato binário.&lt;/p&gt;
&lt;h2 id=&quot;Como-converter-um-binário-em-hexadecimal-e-abrir-imediatamente-no-VIM&quot; data-renderer-start-pos=&quot;2605&quot;&gt;Como converter um binário em hexadecimal e abrir imediatamente no VIM&lt;/h2&gt;
&lt;p&gt;Pra encurtar o ciclo de feedback ainda mais, podemos abrir o &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;dump&lt;/code&gt; diretamente no VIM da seguinte maneira:&lt;/p&gt;
&lt;pre&gt;$ xxd empty.studio3 | vim -&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;2812&quot;&gt;A linha acima vai abrir o programa &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;vim&lt;/code&gt; já com o conteúdo em hexadecimal do binário &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;empty.studio3&lt;/code&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2911&quot;&gt;A partir daqui você pode alterar o arquivo da forma como quiser. E para salvar num arquivo, basta rodar o comando VIM &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;:file nomedoarquivo.extensao&lt;/code&gt;.&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/54/abrir-binario-no-vim.png&quot; alt=&quot;Arquivo binário aberto como hexadecimal no VIM: xxd empty.studio3 | vim -.&quot; width=&quot;1080&quot; height=&quot;426&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;rich-media-item mediaSingleView-content-wrap image-center css-1mzi1es&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div class=&quot;css-lmzmsq&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;3062&quot;&gt;Arquivo binário aberto como hexadecimal no VIM: &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;xxd empty.studio3 | vim -&lt;/code&gt;.&lt;/div&gt;
&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;div class=&quot;ak-editor-panel css-d4tzhg&quot; data-panel-type=&quot;info&quot;&gt;
&lt;div class=&quot;ak-editor-panel__content&quot;&gt;
&lt;p class=&quot;msg msg--info&quot; data-renderer-start-pos=&quot;3140&quot;&gt;Eu escrevi um &lt;a href=&quot;/vim-basico/&quot; title=&quot;https://codamos.com.br/vim-basico&quot;&gt;artigo bacana sobre como começar a trabalhar com o VIM aqui no Codamos&lt;/a&gt;. Dá uma passada lá se estiver apanhando deste editor!&lt;/p&gt;
&lt;h2 id=&quot;Como-salvar-o-arquivo-hexadecimal-do-VIM-diretamente-para-binário&quot; data-renderer-start-pos=&quot;3281&quot;&gt;Como salvar o arquivo hexadecimal do VIM diretamente para binário&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;3348&quot;&gt;Nós podemos obter o conteúdo do &lt;em data-renderer-mark=&quot;true&quot;&gt;buffer&lt;/em&gt; atual do VIM e enviá-lo diretamente à linha de comando para executar o &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;xxd -r&lt;/code&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3467&quot;&gt;Suponhamos que nós abrimos o arquivo hexadecimal diretamente no VIM como no exemplo a seguir:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;3467&quot;&gt;$ xxd empty.studio3 | vim -&lt;/pre&gt;
&lt;p&gt;Pronto, agora com o VIM aberto e visualizando o conteúdo hexadecimal do arquivo, nós podemos transformar este conteúdo em binário com o seguinte comando VIM:&lt;/p&gt;
&lt;pre&gt;:%!xxd -r&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;3761&quot;&gt;O seu editor agora irá mostrar uma porção de caracteres estranhos, porque está em modo binário.&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/54/converter-hex-binario-vim.png&quot; alt=&quot;Hexadecimal transformado em binário após executar o comando :%!xxd -r no VIM.&quot; width=&quot;1080&quot; height=&quot;428&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;rich-media-item mediaSingleView-content-wrap image-center css-1mzi1es&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div class=&quot;css-lmzmsq&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;3861&quot;&gt;Hexadecimal transformado em binário após executar o comando &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;:%!xxd -r&lt;/code&gt; no VIM.&lt;/div&gt;
&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;3941&quot;&gt;Podemos então salvar o arquivo normalmente com o comando VIM:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;3941&quot;&gt;:file modified.studio3&lt;br&gt;:w&lt;/pre&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/54/mudar-nome-arquivo-vim.png&quot; alt=&quot;Alterando o arquivo de saída com o comando :file modified.studio3.&quot; width=&quot;1080&quot; height=&quot;429&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;rich-media-item mediaSingleView-content-wrap image-center css-1mzi1es&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div class=&quot;css-lmzmsq&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;4033&quot;&gt;Alterando o arquivo de saída com o comando &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;:file modified.studio3&lt;/code&gt;.&lt;/div&gt;
&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;div class=&quot;rich-media-item mediaSingleView-content-wrap image-center css-1mzi1es&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div class=&quot;css-14w00qg&quot;&gt;
&lt;div data-context-id=&quot;73596939&quot; data-type=&quot;file&quot; data-node-type=&quot;media&quot; data-width=&quot;1080&quot; data-height=&quot;428&quot; data-id=&quot;de02ecf6-0e10-45f3-8fed-26681ce0b824&quot; data-collection=&quot;contentId-73596939&quot; data-file-name=&quot;converter-hex-binario-vim.png&quot; data-file-size=&quot;58545&quot; data-file-mime-type=&quot;image/png&quot; data-alt=&quot;&quot;&gt;
&lt;div id=&quot;newFileExperienceWrapper&quot; class=&quot;new-file-experience-wrapper css-t4v28r&quot; data-testid=&quot;media-card-view&quot;&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</content:encoded><category>c</category><category>engenharia-reversa</category><category>vim</category></item><item><title>Como contribuir com a documentação do PHP</title><link>https://codamos.com.br/como-traduzir-manual-php/</link><guid isPermaLink="true">https://codamos.com.br/como-traduzir-manual-php/</guid><description>A comunidade PHP é maravilhosa porque consegue unir muita gente entusiasmada em torno deste projeto, um dos poucos verdadeiramente Open Source e conduzidos pela comunidade de forma orgânica! Esta form</description><pubDate>Mon, 31 Oct 2022 16:42:47 GMT</pubDate><content:encoded>&lt;p data-renderer-start-pos=&quot;4&quot;&gt;A comunidade PHP é maravilhosa porque consegue unir muita gente entusiasmada em torno deste projeto, um dos poucos verdadeiramente &lt;em data-renderer-mark=&quot;true&quot;&gt;Open Source&lt;/em&gt; e conduzidos pela comunidade de forma orgânica!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;196&quot;&gt;Esta forma orgânica de a comunidade se organizar apesar de bonita, não é infalível: nós sempre precisamos de mais e mais pessoas contribuindo para que a máquina continue girando. Neste artigo você vai conhecer um pouco mais sobre como contribuir com a linguagem através de traduções.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;481&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Para contribuir com traduções do PHP você precisa ter uma conta no &lt;/strong&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Github&lt;/strong&gt;&lt;/em&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt; e acessar o projeto &lt;/strong&gt;&lt;a href=&quot;https://github.com/php/doc-pt_br&quot; title=&quot;https://github.com/php/doc-pt_br&quot; rel=&quot;nofollow&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;php/doc-pt_BR&lt;/strong&gt;&lt;/a&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;.&lt;/strong&gt; Neste artigo eu te explico tintim por tintim, num passo a passo como proceder para traduzir o manual da linguagem!&lt;/p&gt;
&lt;div class=&quot;post__toc&quot;&gt;
&lt;h3&gt;Conteúdo do post&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#Passo-a-passo-de-como-contribuir-com-a-documentação-do-PHP&quot;&gt;Passo a passo de como contribuir com a documentação do PHP&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#Passo-1-–-Crie-uma-conta-no-Github&quot;&gt;Passo 1 – Crie uma conta no Github&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Passo-2-–-Faça-uma-cópia-do-projeto-php/doc-pt_BR&quot;&gt;Passo 2 – Faça uma cópia do projeto php/doc-pt_BR&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Passo-3-–-Escolha-com-qual-arquivo-quer-trabalhar&quot;&gt;Passo 3 – Escolha com qual arquivo quer trabalhar&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Passo-4-–-Se-familiarize-com-a-estrutura-do-documento&quot;&gt;Passo 4 – Se familiarize com a estrutura do documento&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Passo-5-–-Altere-o-arquivo-em-sua-cópia&quot;&gt;Passo 5 – Altere o arquivo em sua cópia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Passo-6-–-Faça-um-commit-de-suas-alterações&quot;&gt;Passo 6 – Faça um commit de suas alterações&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Passo-7-–-Abra-um-Pull-Request&quot;&gt;Passo 7 – Abra um Pull Request&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Modalidades-de-contribuição-com-a-documentação&quot;&gt;Modalidades de contribuição com a documentação&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Motivos-para-contribuir-com-a-documentação-do-PHP&quot;&gt;Motivos para contribuir com a documentação do PHP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#O-impacto-causado-ao-traduzir-o-manual-do-PHP-para-a-língua-portuguesa&quot;&gt;O impacto causado ao traduzir o manual do PHP para a língua portuguesa&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Conclusão&quot;&gt;Conclusão&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id=&quot;Passo-a-passo-de-como-contribuir-com-a-documentação-do-PHP&quot; data-renderer-start-pos=&quot;707&quot;&gt;Passo a passo de como contribuir com a documentação do PHP&lt;/h2&gt;
&lt;h3 id=&quot;Passo-1-–-Crie-uma-conta-no-Github&quot; data-renderer-start-pos=&quot;767&quot;&gt;Passo 1 – Crie uma conta no Github&lt;/h3&gt;
&lt;p data-renderer-start-pos=&quot;803&quot;&gt;Você possivelmente já tem um perfil no Github, mas não custa nada deixar aqui um guia para quem ainda não tem ou não sabe alterar arquivos no Github.&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image&quot; src=&quot;/media/posts/53/capa-subindo-arquivos-github.jpg&quot; alt=&quot;Artigo: como subir arquivos no github – um guia para iniciantes.&quot; width=&quot;1398&quot; height=&quot;786&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Artigo: como subir arquivos no github – um guia para iniciantes.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;803&quot;&gt;Nós temos &lt;a href=&quot;/subindo-arquivos-no-github/&quot; title=&quot;https://codamos.com.br/subindo-arquivos-no-github&quot;&gt;um artigo incrível sobre como começar com e subir arquivos no Github&lt;/a&gt;, bem explicadinho que é pra não ter erro!&lt;/p&gt;
&lt;h3 id=&quot;Passo-2-–-Faça-uma-cópia-do-projeto-php/doc-pt_BR&quot; data-renderer-start-pos=&quot;1079&quot;&gt;Passo 2 – Faça uma cópia do projeto &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;php/doc-pt_BR&lt;/code&gt;&lt;/h3&gt;
&lt;p data-renderer-start-pos=&quot;1130&quot;&gt;Com sua conta criada, é possível fazer uma cópia do repositório &lt;a href=&quot;https://github.com/php/doc-pt_br&quot; title=&quot;https://github.com/php/doc-pt_br&quot; rel=&quot;nofollow&quot;&gt;php/doc-pt_BR&lt;/a&gt; para sua conta pessoal. Desta forma você tem liberdade total para alterar os arquivos a forma como quiser e mais tarde poderá solicitar que suas mudanças sejam integradas à documentação oficial.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1404&quot;&gt;Na tela do Github, basta clicar no botão &lt;em data-renderer-mark=&quot;true&quot;&gt;Fork&lt;/em&gt; e seguir as instruções:&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/53/botao-fork-github.png&quot; alt=&quot;Captura de tela indicando onde está o botão Fork do Github.&quot; width=&quot;1080&quot; height=&quot;186&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;rich-media-item mediaSingleView-content-wrap image-center css-1mzi1es&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div class=&quot;css-lmzmsq&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;1477&quot;&gt;Captura de tela indicando onde está o botão &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;Fork&lt;/code&gt; do Github.&lt;/div&gt;
&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;1539&quot;&gt;Após fazer a cópia (Fork) do projeto, você deverá ter um repositório idêntico em seu perfil do Github. O meu ficou assim:&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/53/projeto-copiado-php-doc-pt_br.png&quot; alt=&quot;Captura de tela que ilustra um projeto copiado (fork) agora com o nome nawarian/doc-pt_BR.&quot; width=&quot;1080&quot; height=&quot;198&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;rich-media-item mediaSingleView-content-wrap image-center css-1mzi1es&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div class=&quot;css-lmzmsq&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;1664&quot;&gt;Captura de tela que ilustra um projeto copiado (fork) agora com o nome &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;nawarian/doc-pt_BR&lt;/code&gt;.&lt;/div&gt;
&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;Passo-3-–-Escolha-com-qual-arquivo-quer-trabalhar&quot; data-renderer-start-pos=&quot;1757&quot;&gt;Passo 3 – Escolha com qual arquivo quer trabalhar&lt;/h3&gt;
&lt;p data-renderer-start-pos=&quot;1808&quot;&gt;Caso você não queira procurar arquivos desatualizados ou mesmo não traduzidos e queira apenas achar uma forma rápida de contribuir, você pode &lt;a href=&quot;https://github.com/php/doc-pt_br/issues&quot; title=&quot;https://github.com/php/doc-pt_br/issues&quot; rel=&quot;nofollow&quot;&gt;verificar as &lt;em data-renderer-mark=&quot;true&quot;&gt;Issues&lt;/em&gt; abertas do projeto&lt;/a&gt;. Você provavelmente encontrará alguém que já está coordenando a tradução de uma parte do manual.&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image&quot; src=&quot;/media/posts/53/issue-manual-php-pt-br.png&quot; alt=&quot;Uma issue no github para coordenar a tradução do arquivo namespaces.xml&quot; width=&quot;699&quot; height=&quot;848&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Uma issue no github para coordenar a tradução do arquivo namespaces.xml&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;1808&quot;&gt;&lt;span style=&quot;color: var(--text-primary-color); font-family: var(--editor-font-family); font-size: inherit; font-weight: var(--font-weight-normal);&quot;&gt;Hoje, por exemplo, eu encontrei a &lt;/span&gt;&lt;a href=&quot;https://github.com/php/doc-pt_br/issues/150&quot; title=&quot;https://github.com/php/doc-pt_br/issues/150&quot; rel=&quot;nofollow&quot;&gt;Issue #150 que atualiza o arquivo language/namespaces.xml&lt;/a&gt;&lt;span style=&quot;color: var(--text-primary-color); font-family: var(--editor-font-family); font-size: inherit; font-weight: var(--font-weight-normal);&quot;&gt;, referente à &lt;/span&gt;&lt;a href=&quot;https://www.php.net/manual/pt_BR/language.namespaces.php&quot; title=&quot;https://www.php.net/manual/pt_BR/language.namespaces.php&quot; rel=&quot;nofollow&quot;&gt;página do manual Namespaces&lt;/a&gt;&lt;span style=&quot;color: var(--text-primary-color); font-family: var(--editor-font-family); font-size: inherit; font-weight: var(--font-weight-normal);&quot;&gt;. Este arquivo possui várias seções e o autor &lt;/span&gt;&lt;a href=&quot;https://github.com/alfsb&quot; title=&quot;https://github.com/alfsb&quot; rel=&quot;nofollow&quot;&gt;@alfsb&lt;/a&gt;&lt;span style=&quot;color: var(--text-primary-color); font-family: var(--editor-font-family); font-size: inherit; font-weight: var(--font-weight-normal);&quot;&gt; está coordenando a tradução de cada uma das partes.&lt;/span&gt;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1808&quot;&gt;Antes de começar a traduzir um arquivo ou parte dele, avise a comunidade através de issues como esta para evitar retrabalho e conflitos.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1808&quot;&gt;Note que, como o arquivo está separadinho em diversas seções, &lt;strong data-renderer-mark=&quot;true&quot;&gt;pessoas diferentes podem verificar o que está faltando e contribuir mesmo que com um pequeno pedacinho da documentação&lt;/strong&gt;!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1808&quot;&gt;Outra opção é encontrar arquivos desatualizados utilizando a &lt;a href=&quot;http://doc.php.net/revcheck.php?p=files&amp;amp;lang=pt_br&quot; title=&quot;http://doc.php.net/revcheck.php?p=files&amp;amp;lang=pt_br&quot; rel=&quot;nofollow&quot;&gt;ferramenta revcheck&lt;/a&gt; que a própria comunidade disponibiliza online.&lt;/p&gt;
&lt;h3 id=&quot;Passo-4-–-Se-familiarize-com-a-estrutura-do-documento&quot; data-renderer-start-pos=&quot;2778&quot;&gt;Passo 4 – Se familiarize com a estrutura do documento&lt;/h3&gt;
&lt;p data-renderer-start-pos=&quot;2833&quot;&gt;A documentação do PHP foi redigida utilizando a linguagem &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;xml&lt;/code&gt; no formato &lt;a href=&quot;https://docbook.org/&quot; title=&quot;https://docbook.org/&quot; rel=&quot;nofollow&quot;&gt;DocBook&lt;/a&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2916&quot;&gt;Ao navegar pelos arquivos você provavelmente vai entender o que cada elemento faz. Mas abaixo eu deixo uma tabelinha que talvez lhe ajude:&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;&lt;strong&gt;Elemento XML&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;&lt;strong&gt;Descrição&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;&lt;code&gt;&amp;lt;chapter&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Descrição do capítulo do manual&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;&lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Título de uma seção ou exemplo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;&lt;code&gt;&amp;lt;para&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Parágrafo de texto&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;&lt;code&gt;&amp;lt;example&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Seção de exemplo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;&lt;code&gt;&amp;lt;programlisting&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Exemplo de código, formatado&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;&lt;code&gt;&amp;lt;![CDATA[ ... ]]&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Texto puro, sem formatação&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;&lt;code&gt;&amp;lt;sect1&amp;gt;&lt;/code&gt; ou &lt;code&gt;&amp;lt;sect2&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Seção do documento, como cabeçalhos da página&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;Passo-5-–-Altere-o-arquivo-em-sua-cópia&quot; data-renderer-start-pos=&quot;3430&quot;&gt;Passo 5 – Altere o arquivo em sua cópia&lt;/h3&gt;
&lt;p data-renderer-start-pos=&quot;3471&quot;&gt;Aqui você pode optar por clonar a cópia do repositório (Fork) em sua máquina local, como descrito em nosso artigo de &lt;a href=&quot;/subindo-arquivos-no-github/&quot; title=&quot;https://codamos.com.br/subindo-arquivos-no-github&quot;&gt;como subir arquivos para o Github&lt;/a&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3624&quot;&gt;Outra opção é fazer a edição diretamente pela interface gráfica do Github. Foi o que eu fiz quando ajudava a traduzir a &lt;a href=&quot;https://github.com/php/doc-pt_br/issues/150&quot; title=&quot;https://github.com/php/doc-pt_br/issues/150&quot; rel=&quot;nofollow&quot;&gt;Issue #150&lt;/a&gt; que traduz o arquivo &lt;a href=&quot;https://github.com/php/doc-pt_br/blob/master/language/namespaces.xml&quot; title=&quot;https://github.com/php/doc-pt_br/blob/master/language/namespaces.xml&quot; rel=&quot;nofollow&quot;&gt;language/namespaces.xml&lt;/a&gt;. Para isto, na minha cópia (Fork) do repositório eu encontrei o arquivo language/namespaces.xml e abri o editor de texto como na imagem abaixo:&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/53/como-editar-arquivo-github.png&quot; alt=&quot;Imagem que mostra como abrir o modo de edição de arquivos no Github.&quot; width=&quot;1035&quot; height=&quot;457&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;rich-media-item mediaSingleView-content-wrap image-center css-1mzi1es&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div class=&quot;css-lmzmsq&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;3947&quot;&gt;Imagem que mostra como abrir o modo de edição de arquivos no Github.&lt;/div&gt;
&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;div class=&quot;rich-media-item mediaSingleView-content-wrap image-center css-1mzi1es&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div class=&quot;css-etfdwr&quot;&gt;
&lt;div data-context-id=&quot;72548353&quot; data-type=&quot;file&quot; data-node-type=&quot;media&quot; data-width=&quot;1035&quot; data-height=&quot;457&quot; data-id=&quot;1d88b7e0-baa0-458c-8210-4995309b48c6&quot; data-collection=&quot;contentId-72548353&quot; data-file-name=&quot;como-editar-arquivo-github.png&quot; data-file-size=&quot;116757&quot; data-file-mime-type=&quot;image/png&quot; data-alt=&quot;&quot;&gt;
&lt;div id=&quot;newFileExperienceWrapper&quot; class=&quot;new-file-experience-wrapper css-13nmqz5&quot; data-testid=&quot;media-card-view&quot;&gt;
&lt;div class=&quot;media-file-card-view css-1yn77bd&quot; data-testid=&quot;media-file-card-view&quot; data-test-status=&quot;complete&quot; data-test-media-name=&quot;como-editar-arquivo-github.png&quot; data-test-progress=&quot;1&quot;&gt;
&lt;h3 id=&quot;Passo-6-–-Faça-um-commit-de-suas-alterações&quot; data-renderer-start-pos=&quot;4018&quot;&gt;Passo 6 – Faça um &lt;em data-renderer-mark=&quot;true&quot;&gt;commit&lt;/em&gt; de suas alterações&lt;/h3&gt;
&lt;p data-renderer-start-pos=&quot;4063&quot;&gt;Ao finalizar suas alterações completa ou parcialmente, você pode salvar seu progresso ao realizar um &lt;em data-renderer-mark=&quot;true&quot;&gt;Commit&lt;/em&gt; de seus arquivos.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;4190&quot;&gt;Pela interface do Github, logo abaixo do editor de código, encontraremos uma caixa de texto com o título &lt;em data-renderer-mark=&quot;true&quot;&gt;Commit changes&lt;/em&gt;. A primeira caixa de texto é o título do &lt;em data-renderer-mark=&quot;true&quot;&gt;commit&lt;/em&gt; e a caixa logo abaixo te permite oferecer uma descrição mais detalhada.&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/53/como-fazer-commit-github-web.png&quot; alt=&quot;Onde realizar um commit na interface web do Gtihub.&quot; width=&quot;989&quot; height=&quot;873&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;rich-media-item mediaSingleView-content-wrap image-center css-1mzi1es&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div class=&quot;css-lmzmsq&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;4433&quot;&gt;Onde realizar um &lt;em data-renderer-mark=&quot;true&quot;&gt;commit&lt;/em&gt; na interface web do Gtihub.&lt;/div&gt;
&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;strong style=&quot;font-family: var(--editor-font-family); font-size: inherit;&quot; data-renderer-mark=&quot;true&quot;&gt;Não se preocupe&lt;/strong&gt;&lt;span style=&quot;color: var(--text-primary-color); font-family: var(--editor-font-family); font-size: inherit; font-weight: var(--font-weight-normal);&quot;&gt;! Como você está operando com uma cópia do projeto (Fork), ninguém vai receber suas alterações até que você faça um &lt;/span&gt;&lt;em style=&quot;color: var(--text-primary-color); font-family: var(--editor-font-family); font-size: inherit; font-weight: var(--font-weight-normal);&quot; data-renderer-mark=&quot;true&quot;&gt;Pull Request&lt;/em&gt;&lt;span style=&quot;color: var(--text-primary-color); font-family: var(--editor-font-family); font-size: inherit; font-weight: var(--font-weight-normal);&quot;&gt;, que é o último passo da nossa missão. Vamos à ele!&lt;/span&gt;
&lt;h3 id=&quot;Passo-7-–-Abra-um-Pull-Request&quot; data-renderer-start-pos=&quot;4684&quot;&gt;Passo 7 – Abra um &lt;em data-renderer-mark=&quot;true&quot;&gt;Pull Request&lt;/em&gt;&lt;/h3&gt;
&lt;p data-renderer-start-pos=&quot;4716&quot;&gt;Agora que você já possui as atualizações que gostaria de lançar à documentação oficial, é hora de solicitar que outras pessoas da comunidade revisem seu texto e aprovem ou solicitem modificações. Para isto nós precisamos abrir um &lt;em data-renderer-mark=&quot;true&quot;&gt;Pull Request&lt;/em&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;4961&quot;&gt;Em sua cópia do repositório (Fork), clique na aba &lt;em data-renderer-mark=&quot;true&quot;&gt;Pull Requests&lt;/em&gt; e clique no botão &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;New pull request&lt;/code&gt;:&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/53/como-abrir-novo-pull-request-github.png&quot; alt=&quot;Onde encontrar o botão New pull request.&quot; width=&quot;1080&quot; height=&quot;216&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;rich-media-item mediaSingleView-content-wrap image-center css-1mzi1es&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div class=&quot;css-lmzmsq&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;5064&quot;&gt;Onde encontrar o botão &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;New pull request&lt;/code&gt;.&lt;/div&gt;
&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;5107&quot;&gt;Ao apertar o botão &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;New pull request&lt;/code&gt;, assumindo que você fez o &lt;em data-renderer-mark=&quot;true&quot;&gt;commit&lt;/em&gt; de suas alterações como descrito no passo anterior, uma tela parecida com a seguinte deverá aparecer:&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/53/confirmar-abertura-do-pull-request-github.png&quot; alt=&quot;Resumo das alterações antes de abrir um Pull Request.&quot; width=&quot;1062&quot; height=&quot;915&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;rich-media-item mediaSingleView-content-wrap image-center css-1mzi1es&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div class=&quot;css-lmzmsq&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;5281&quot;&gt;Resumo das alterações antes de abrir um Pull Request.&lt;/div&gt;
&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;5337&quot;&gt;Se estiver tudo certo em sua opinião basta abrir o &lt;em data-renderer-mark=&quot;true&quot;&gt;Pull Request&lt;/em&gt; e aguardar a comunidade revisar. Daqui pra frente, você vai interagir com outras pessoas da comunidade que vão lhe indicar quais alterações realizar ou simplesmente aceitar suas contribuições de bom grado!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;5600&quot;&gt;O pull request que estou usando como exemplo aqui é o de &lt;a href=&quot;https://github.com/php/doc-pt_br/pull/188&quot; title=&quot;https://github.com/php/doc-pt_br/pull/188&quot; rel=&quot;nofollow&quot;&gt;número #188, disponível aqui&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;Modalidades-de-contribuição-com-a-documentação&quot; data-renderer-start-pos=&quot;5688&quot;&gt;Modalidades de contribuição com a documentação&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;5736&quot;&gt;O projeto &lt;a href=&quot;https://github.com/php/doc-pt_br&quot; title=&quot;https://github.com/php/doc-pt_br&quot; rel=&quot;nofollow&quot;&gt;php/doc-pt_br&lt;/a&gt; te permite contribuir de duas formas fundamentais: atualizando documentos já desatualizados ou traduzir documentos ainda sem tradução. &lt;strong data-renderer-mark=&quot;true&quot;&gt;A prioridade é sempre de documentos desatualizados.&lt;/strong&gt;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;5948&quot;&gt;Para além disso, você pode monitorar o repositório para ajudar a revisar &lt;em data-renderer-mark=&quot;true&quot;&gt;issues&lt;/em&gt; e &lt;em data-renderer-mark=&quot;true&quot;&gt;pull requests&lt;/em&gt;, de forma a permitir que outras pessoas tenham suas alterações aceitas mais cedo.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;6127&quot;&gt;Mais detalhes você encontra na página &lt;a href=&quot;https://github.com/php/doc-pt_br/wiki/Situa%C3%A7%C3%A3o-atual&quot; title=&quot;https://github.com/php/doc-pt_br/wiki/Situa%C3%A7%C3%A3o-atual&quot; rel=&quot;nofollow&quot;&gt;Situação atual da Wiki do php/doc-pt_br&lt;/a&gt;, que descreve exatamente como encontrar estes arquivos e o que fazer.&lt;/p&gt;
&lt;h2 id=&quot;Motivos-para-contribuir-com-a-documentação-do-PHP&quot; data-renderer-start-pos=&quot;6276&quot;&gt;Motivos para contribuir com a documentação do PHP&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;6327&quot;&gt;Se fazer parte de um projeto grandioso como o PHP não é motivo o suficiente, eu separei alguns motivos que podem te convencer a contribuir, ou talvez convidar mais pessoas a contribuir com o projeto:&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;6528&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Primeiro motivo: devolver à&lt;/strong&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt; comunidade&lt;/strong&gt;. O PHP já ajudou milhares de pessoas a mudar de vida direta ou indiretamente. E, na minha opinião, foi um dos maiores motores para o crescimento do que hoje nós conhecemos como &lt;em data-renderer-mark=&quot;true&quot;&gt;Internet&lt;/em&gt;. É um projeto que nasceu e cresceu totalmente aberto e gratuito, contribuir com sua tradução é uma forma de retribuir ao esforço empreendido pela comunidade.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;6753&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Segundo motivo: destacar seu currículo&lt;/strong&gt;. Eu ouço de diversas pessoas que estão iniciando agora em programação sobre como fazer com que seu currículo ganhe destaque frente a tantas outras pessoas que se candidatam a mesma vaga. Contribuir com projetos abertos é uma forma incrível de ganhar destaque, ainda mais um projeto complexo como o PHP.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;7096&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Terceiro motivo: aprender mais e mais detalhes sobre a linguagem PHP&lt;/strong&gt;. Ao traduzir a documentação você se força a ler, interpretar e entender o conteúdo daquele documento. É uma forma muito boa de solidificar seu conhecimento sobre a linguagem e também de descobrir funcionalidades novas que você talvez não conhecesse antes.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;7422&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Quarto motivo: treinar para a certificação.&lt;/strong&gt; &lt;a href=&quot;https://www.zend.com/training/php-certification-exam&quot; title=&quot;https://www.zend.com/training/php-certification-exam&quot; rel=&quot;nofollow&quot;&gt;A certificação PHP da Zend&lt;/a&gt; é a única certificação PHP reconhecida no mundo do trabalho hoje em dia, e te exige profundo conhecimento da linguagem. Traduzir a documentação com certeza te ajuda a revisar material e solidificar conhecimento.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;7706&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Quinto motivo: praticar o inglês.&lt;/strong&gt; A documentação original é escrita em inglês, língua essencial para pessoas que trabalham com desenvolvimento de software há muito tempo. Ao traduzir a documentação para o Português, você se força a exercitar seu inglês na forma de leitura, gramática e interpretação de texto com um tópico que você provavelmente já possui familiaridade.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;8078&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Sexto motivo: participar do Hacktoberfest&lt;/strong&gt;. O &lt;a href=&quot;https://hacktoberfest.com/&quot; title=&quot;https://hacktoberfest.com/&quot; rel=&quot;nofollow&quot;&gt;hacktoberfest&lt;/a&gt; acontece todo mês de Outubro e é organizado pela DigitalOcean. A ideia é influenciar mais pessoas a contribuírem com projetos de código aberto e, como recompensa, a DigitalOcean e empresas parceiras enviam brindes a quem contribui.&lt;/p&gt;
&lt;div class=&quot;ak-editor-panel css-d4tzhg&quot; data-panel-type=&quot;info&quot;&gt;
&lt;p class=&quot;msg msg--success&quot; data-renderer-start-pos=&quot;8371&quot;&gt;Gostaria de adicionar algum motivo aqui? Me dá um toque lá no Twitter: &lt;a href=&quot;https://twitter.com/nawarian&quot; title=&quot;https://twitter.com/nawarian&quot; rel=&quot;nofollow&quot;&gt;@nawarian&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;O-impacto-causado-ao-traduzir-o-manual-do-PHP-para-a-língua-portuguesa&quot; data-renderer-start-pos=&quot;8455&quot;&gt;O impacto causado ao traduzir o manual do PHP para a língua portuguesa&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;8527&quot;&gt;Cerca de &lt;strong data-renderer-mark=&quot;true&quot;&gt;290 milhões de pessoas no mundo inteiro já falam ou falarão Português&lt;/strong&gt; em breve! De acordo com a Wikipedia, os &lt;a href=&quot;https://pt.wikipedia.org/wiki/Lista_de_pa%C3%ADses_onde_o_portugu%C3%AAs_%C3%A9_l%C3%ADngua_oficial&quot; title=&quot;https://pt.wikipedia.org/wiki/Lista_de_pa%C3%ADses_onde_o_portugu%C3%AAs_%C3%A9_l%C3%ADngua_oficial&quot; rel=&quot;nofollow&quot;&gt;10 países a seguir têm Português como sua língua oficial&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Brasil&lt;/li&gt;
&lt;li&gt;Angola&lt;/li&gt;
&lt;li&gt;Moçambique&lt;/li&gt;
&lt;li&gt;Portugal&lt;/li&gt;
&lt;li&gt;Guiné-Bissau&lt;/li&gt;
&lt;li&gt;Timor-Leste&lt;/li&gt;
&lt;li&gt;Guiné Equatorial&lt;/li&gt;
&lt;li&gt;Macau&lt;/li&gt;
&lt;li&gt;Cabo Verde&lt;/li&gt;
&lt;li&gt;São Tomé e Príncipe&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-renderer-start-pos=&quot;8850&quot;&gt;Ao traduzir o manual da linguagem PHP para a língua portuguesa, você cria impacto direto a todos os países acima citados e ainda ajuda pessoas de outros países que queiram praticar e aperfeiçoar seu domínio da língua portuguesa.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;9080&quot;&gt;Sem contar com nossos hermanos que por muitas vezes não encontram documentação em espanhol e optam por adivinhar o que está escrito em português.&lt;/p&gt;
&lt;h2 id=&quot;Conclusão&quot; data-renderer-start-pos=&quot;9227&quot;&gt;Conclusão&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;9238&quot;&gt;Fica claro que &lt;strong data-renderer-mark=&quot;true&quot;&gt;para contribuir com a linguagem PHP você não precisa saber nada sobre a linguagem C&lt;/strong&gt;. Um pouco de tempo livre, boa vontade e um dicionário já são suficientes pra te colocar em posição de ajudar a comunidade a crescer.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;9467&quot;&gt;Além disso &lt;strong data-renderer-mark=&quot;true&quot;&gt;o impacto causado por uma pequena tradução para o português é multiplicado por 10&lt;/strong&gt;, visto que tantos países adotam a língua portuguesa como língua oficial. E tantos outros têm a opção de arriscar um portunhol.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;9688&quot;&gt;Por fim, participar da comunidade e contribuir com projetos &lt;em data-renderer-mark=&quot;true&quot;&gt;Open Source&lt;/em&gt; é uma forma sensacional de tornar-se uma profissional melhor, tanto como pessoa quanto tecnicamente.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;rich-media-item mediaSingleView-content-wrap image-center css-1mzi1es&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div class=&quot;css-rbm704&quot;&gt;
&lt;div data-context-id=&quot;72548353&quot; data-type=&quot;file&quot; data-node-type=&quot;media&quot; data-width=&quot;1062&quot; data-height=&quot;915&quot; data-id=&quot;e347bf56-5ec6-4ebb-b92c-5838b6c888b9&quot; data-collection=&quot;contentId-72548353&quot; data-file-name=&quot;confirmar-abertura-do-pull-request-github.png&quot; data-file-size=&quot;226887&quot; data-file-mime-type=&quot;image/png&quot; data-alt=&quot;&quot;&gt;
&lt;div id=&quot;newFileExperienceWrapper&quot; class=&quot;new-file-experience-wrapper css-1yneg4i&quot; data-testid=&quot;media-card-view&quot;&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;rich-media-item mediaSingleView-content-wrap image-center css-1mzi1es&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div class=&quot;css-ngqr0d&quot;&gt;
&lt;div data-context-id=&quot;72548353&quot; data-type=&quot;file&quot; data-node-type=&quot;media&quot; data-width=&quot;1080&quot; data-height=&quot;198&quot; data-id=&quot;b7461232-604c-43e2-8d9f-3e3f1c98144a&quot; data-collection=&quot;contentId-72548353&quot; data-file-name=&quot;projeto-copiado-php-doc-pt_br.png&quot; data-file-size=&quot;39853&quot; data-file-mime-type=&quot;image/png&quot; data-alt=&quot;&quot;&gt;
&lt;div id=&quot;newFileExperienceWrapper&quot; class=&quot;new-file-experience-wrapper css-198zj6g&quot; data-testid=&quot;media-card-view&quot;&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;rich-media-item mediaSingleView-content-wrap image-center css-1mzi1es&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div class=&quot;css-hnwjf0&quot;&gt;
&lt;div data-context-id=&quot;72548353&quot; data-type=&quot;file&quot; data-node-type=&quot;media&quot; data-width=&quot;1920&quot; data-height=&quot;1080&quot; data-id=&quot;9ade7aa9-ed50-4bba-aa87-9f314344667f&quot; data-collection=&quot;contentId-72548353&quot; data-file-name=&quot;capa-subindo-arquivos-github.png&quot; data-file-size=&quot;2523935&quot; data-file-mime-type=&quot;image/png&quot; data-alt=&quot;&quot;&gt;
&lt;div id=&quot;newFileExperienceWrapper&quot; class=&quot;new-file-experience-wrapper css-8v4zg7&quot; data-testid=&quot;media-card-view&quot;&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</content:encoded><category>codigo-aberto</category><category>php</category></item><item><title>Novidades do PHP 8.2 em 2022</title><link>https://codamos.com.br/novidades-php-82/</link><guid isPermaLink="true">https://codamos.com.br/novidades-php-82/</guid><description>Novembro está chegando, e com ele grandes novidades no ecossistema PHP! O PHP 8.2 traz otimizações de performance, mudanças na sintaxe da linguagem e funções utilitárias que vão tornar o desenvolvimen</description><pubDate>Mon, 24 Oct 2022 13:27:19 GMT</pubDate><content:encoded>&lt;p data-renderer-start-pos=&quot;5&quot;&gt;Novembro está chegando, e com ele grandes novidades no ecossistema PHP! O PHP 8.2 traz otimizações de performance, mudanças na sintaxe da linguagem e funções utilitárias que vão tornar o desenvolvimento com PHP ainda mais prazeiroso!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;240&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;O PHP 8.2 vai ser lançado no dia 08 de Dezembro de 2022&lt;/strong&gt; de acordo com a documentação oficial. Mas caso você queira experimentar antes do tempo, deixo aqui uma tabelinha com as principais datas antes do lançamento oficial:&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.2843%;&quot;&gt;&lt;strong&gt;Data&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.2843%;&quot;&gt;&lt;strong&gt;Versão&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.2889%;&quot;&gt;&lt;strong&gt;Detalhes&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.2843%;&quot;&gt;13 de Outubro de 2022&lt;/td&gt;
&lt;td style=&quot;width: 33.2843%;&quot;&gt;Release Candidate (RC) 4&lt;/td&gt;
&lt;td style=&quot;width: 33.2889%;&quot;&gt;&lt;a href=&quot;https://www.php.net/archive/2022.php#2022-10-13-1&quot; rel=&quot;nofollow&quot;&gt;Página de anúncio oficial&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.2843%;&quot;&gt;27 de Outubro de 2022&lt;/td&gt;
&lt;td style=&quot;width: 33.2843%;&quot;&gt;Release Candidate (RC) 4&lt;/td&gt;
&lt;td style=&quot;width: 33.2889%;&quot;&gt;&lt;a href=&quot;https://www.php.net/archive/2022.php#2022-10-27-1&quot; rel=&quot;nofollow&quot;&gt;Página de anúncio oficial&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.2843%;&quot;&gt;10 de Novembro de 2022&lt;/td&gt;
&lt;td style=&quot;width: 33.2843%;&quot;&gt;Release Candidate (RC) 6&lt;/td&gt;
&lt;td style=&quot;width: 33.2889%;&quot;&gt;&lt;a href=&quot;https://www.php.net/archive/2022.php#2022-11-10-1&quot; rel=&quot;nofollow&quot;&gt;Página de anúncio oficial&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.2843%;&quot;&gt;24 de Novembro de 2022&lt;/td&gt;
&lt;td style=&quot;width: 33.2843%;&quot;&gt;Release Candidate (RC) 7&lt;/td&gt;
&lt;td style=&quot;width: 33.2889%;&quot;&gt;--&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.2843%;&quot;&gt;08 de Dezembro de 2022&lt;/td&gt;
&lt;td style=&quot;width: 33.2843%;&quot;&gt;Versão final&lt;/td&gt;
&lt;td style=&quot;width: 33.2889%;&quot;&gt;--&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class=&quot;post__toc&quot;&gt;
&lt;h3&gt;Conteúdos deste artigo&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1gg52nh834u&quot;&gt;Classes somente-leitura&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Adeus-propriedades-dinâmicas-em-classes&quot;&gt;Adeus propriedades dinâmicas em classes&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#Como-permitir-propriedades-dinâmicas-no-PHP-8.2-via-métodos-mágicos-__get-e-__set&quot;&gt;Como permitir propriedades dinâmicas no PHP 8.2 via métodos mágicos __get e __set&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Como-permitir-propriedades-dinâmicas-no-PHP-8.2-utilizando-atributos&quot;&gt;Como permitir propriedades dinâmicas no PHP 8.2 utilizando atributos&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Extensão-nova:-Random-para-gerar-números-aleatórios&quot;&gt;Extensão nova: Random para gerar números aleatórios&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Novos-tipos:-null,-true-e-false&quot;&gt;Novos tipos: null, true e false&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Tipos-de-forma-normal-disjuntiva-(Disjunctive-normal-form-types-–-DNF)&quot;&gt;Tipos de forma normal disjuntiva (Disjunctive normal form types – DNF)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Constantes-em-traits&quot;&gt;Constantes em traits&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Esconder-parâmetros-em-backtraces&quot;&gt;Esconder parâmetros em backtraces&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Funções-utf8_encode()-e-utf8_decode()-descontinuadas&quot;&gt;Funções utf8_encode() e utf8_decode() descontinuadas&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1ggicv0cm13&quot;&gt;Mudança no retorno dos métodos que criam datas&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1ggicv0cm14&quot;&gt;Outras mudanças&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id=&quot;mcetoc_1gg52nh834u&quot;&gt;Classes somente-leitura&lt;/h2&gt;
&lt;p&gt;As propriedades somente-leitura chegaram ao &lt;a href=&quot;/novidades-php-81/&quot; title=&quot;https://www.php.net/releases/8.1/pt_BR.php&quot;&gt;PHP na versão 8.1&lt;/a&gt;. Esta RFC é o passo adiante, que permite transformar todas as propriedades da classe em somente-leitura duma vez só.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;961&quot;&gt;Em vez de escrever isso:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;961&quot;&gt;class Codamos&lt;br&gt;{&lt;br&gt;    public function __construct(&lt;br&gt;        public readonly array $artigos,&lt;br&gt;    ) {}&lt;br&gt;}&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;1088&quot;&gt;Nós vamos passar a escrever isso:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;1088&quot;&gt;readonly class Codamos&lt;br&gt;{&lt;br&gt;    public function __construct(&lt;br&gt;        public array $artigos,&lt;br&gt;    ) {}&lt;br&gt;}&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;1224&quot;&gt;O efeito prático do código acima é transformar todas as propriedades da classe &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;Codamos&lt;/code&gt; em valores somente-leitura.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1340&quot;&gt;Para além disso, as classes somente-leitura tornam impossível adicionar propriedades em tempo de execução de forma dinâmica. E também só é possível herdar de uma classe somente-leitura se a sub-classe também for somente-leitura. Então o seguinte código dá erro:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;1340&quot;&gt;$site = new Codamos();&lt;br&gt;$site-&amp;gt;layout = &apos;wide&apos;; // Gera erro&lt;br&gt;&lt;br&gt;// Uncaught Error: Cannot create dynamic property Codamos::$layout&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;1732&quot;&gt;Fonte: &lt;a href=&quot;https://wiki.php.net/rfc/readonly_classes&quot; title=&quot;https://wiki.php.net/rfc/readonly_classes&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;RFC e votação da comunidade “Readonly classes”&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;Adeus-propriedades-dinâmicas-em-classes&quot; data-renderer-start-pos=&quot;1788&quot;&gt;Adeus propriedades dinâmicas em classes&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;1829&quot;&gt;Desde que classes foram introduzidas ao PHP era possível criar propriedades de forma dinâmica como com o código abaixo:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;1829&quot;&gt;class Codamos {}&lt;br&gt;&lt;br&gt;$site = new Codamos();&lt;br&gt;$site-&amp;gt;layout = &apos;wide&apos;;&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;2016&quot;&gt;Na versão 8.2 do PHP este comportamento ainda irá funcionar, mas será marcado como descontinuado (deprecated) e lançará um &lt;em data-renderer-mark=&quot;true&quot;&gt;warning&lt;/em&gt;. E a partir da versão 9.0 do PHP lançará uma exceção do tipo &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;ErrorException&lt;/code&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2225&quot;&gt;Mas não se preocupe, se o seu código precisa criar propriedades de forma dinâmica não é o fim do mundo! Você tem duas opções:&lt;/p&gt;
&lt;h3 id=&quot;Como-permitir-propriedades-dinâmicas-no-PHP-8.2-via-métodos-mágicos-__get-e-__set&quot; data-renderer-start-pos=&quot;2352&quot;&gt;Como permitir propriedades dinâmicas no PHP 8.2 via métodos mágicos &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;__get&lt;/code&gt; e &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;__set&lt;/code&gt;&lt;/h3&gt;
&lt;p data-renderer-start-pos=&quot;2435&quot;&gt;Desde a versão 5 do PHP, os métodos mágicos nos permitem interceptar tentativas de acessar propriedades que não existem ou não estão visíveis no escopo público de uma instância.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2614&quot;&gt;Você pode utilizar os &lt;a href=&quot;https://www.php.net/manual/pt_BR/language.oop5.overloading.php#object.get&quot; title=&quot;https://www.php.net/manual/pt_BR/language.oop5.overloading.php#object.get&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;métodos mágicos __get() e __set()&lt;/a&gt; para gravar variáveis de forma dinâmica em sua classe.&lt;/p&gt;
&lt;h3 id=&quot;Como-permitir-propriedades-dinâmicas-no-PHP-8.2-utilizando-atributos&quot; data-renderer-start-pos=&quot;2726&quot;&gt;Como permitir propriedades dinâmicas no PHP 8.2 utilizando atributos&lt;/h3&gt;
&lt;p data-renderer-start-pos=&quot;2796&quot;&gt;Uma forma menos trabalhosa de permitir propriedades dinâmicas em suas classes no PHP 8.2, é utilizando o atributo &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;#[AllowDynamicProperties]&lt;/code&gt; que foi criado justamente para esta versão da linguagem!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2994&quot;&gt;A sua classe ficaria assim:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;2994&quot;&gt;#[AllowDynamicProperties]&lt;br&gt;class Codamos {}&lt;br&gt;&lt;br&gt;$site = new Codamos();&lt;br&gt;$site-&amp;gt;layout = &apos;wide&apos;; // Tudo certo aqui&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;3134&quot;&gt;Fonte: &lt;a href=&quot;https://wiki.php.net/rfc/deprecate_dynamic_properties&quot; title=&quot;https://wiki.php.net/rfc/deprecate_dynamic_properties&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;RFC e votação da comunidade “Deprecate dynamic properties”&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;Extensão-nova:-Random-para-gerar-números-aleatórios&quot; data-renderer-start-pos=&quot;3202&quot;&gt;Extensão nova: &lt;em data-renderer-mark=&quot;true&quot;&gt;Random&lt;/em&gt; para gerar números aleatórios&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;3255&quot;&gt;Antes de eu te explicar o que essa extensão resolve, deixa eu te mostrar uma coisa:&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3340&quot;&gt;No PHP é possível gerar números aleatórios de forma determinista, utilizando uma semente (seed). Dada uma mesma semente, os números aleatórios são gerados sempre igual a cada vez que você rodar o programa. Nós podemos definir a semente através da função &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;mt_srand(int $seed)&lt;/code&gt;e podemos obter um número aleatório com a função &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;mt_rand(int $min, int $max)&lt;/code&gt;. Assim:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;3340&quot;&gt;mt_srand(1234); // semente = 1234&lt;br&gt;var_dump(mt_rand(1, 100)); // int(76)&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;3772&quot;&gt;Não importa quantas vezes você rodar o programa acima, o valor gerado sempre será 76.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3859&quot;&gt;Acontece que a implementação atual utiliza estado global dentro da VM do PHP, de forma que algumas funções podem quebrar o comportamento do gerador de números aleatórios – caso você queira saber mais sobre como o PHP funciona por debaixo dos panos, dê uma olhada no &lt;a href=&quot;/php-8-jit/&quot; title=&quot;https://codamos.com.br/php-8-jit&quot;&gt;meu artigo sobre o JIT&lt;/a&gt; que eu explico passo a passo como funciona.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;4193&quot;&gt;Então o seguinte código não opera como esperaríamos:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;4193&quot;&gt;mt_srand(1234); // semente = 1234&lt;br&gt;str_shuffle(&apos;ABC&apos;); // redefiniu a semente :&apos;)&lt;br&gt;mt_rand(1, 100); // int(7)&lt;/pre&gt;
&lt;p&gt;Estes e outros problemas são resolvidos pela extensão &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;Random&lt;/code&gt; que traz uma classe &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;Randomizer&lt;/code&gt;. Com ela podemos escolher qual o motor utilizar para gerar números aleatórios. Mais ou menos assim:&lt;/p&gt;
&lt;pre&gt;$motor = new Random\Engine\MarsenneTwister(1234);&lt;br&gt;&lt;br&gt;$randomizer = new Random\Randomizer($motor);&lt;br&gt;var_dump($randomizer-&amp;gt;getInt(1, 100)); // int(76)&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;4696&quot;&gt;Fonte: &lt;a href=&quot;https://wiki.php.net/rfc/rng_extension&quot; title=&quot;https://wiki.php.net/rfc/rng_extension&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;RFC e votação da comunidade “Random extension 5.x”&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;Novos-tipos:-null,-true-e-false&quot; data-renderer-start-pos=&quot;4756&quot;&gt;Novos tipos: &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;null&lt;/code&gt;, &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;true&lt;/code&gt; e &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;false&lt;/code&gt;&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;4789&quot;&gt;O php já possui os tipos &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;void&lt;/code&gt; e &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;bool&lt;/code&gt; que representam a &lt;em data-renderer-mark=&quot;true&quot;&gt;ausência de retorno&lt;/em&gt; e a união &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;true|false&lt;/code&gt; respectivamente.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;4903&quot;&gt;A partir da versão 8.2 vamos poder explicitar melhor a assinatura de nossos métodos e funções indicando que o retorno será exatamente &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;null&lt;/code&gt;, &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;true&lt;/code&gt; ou &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;false&lt;/code&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;5059&quot;&gt;Um bom exemplo de função que operaria desta forma é a função &lt;a href=&quot;https://www.php.net/manual/pt_BR/function.fread.php&quot; title=&quot;https://www.php.net/manual/pt_BR/function.fread.php&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;fread()&lt;/a&gt; que retorna uma &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;string&lt;/code&gt; com o conteúdo lido ou &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;bool(false)&lt;/code&gt; em caso de erro. Uma assinatura válida para esta função, de acordo com o PHP 8.2, poderia ser a seguinte:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;5059&quot;&gt;function fread($handle, int $len): string|false&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;5342&quot;&gt;Fonte: &lt;a href=&quot;https://wiki.php.net/rfc/null-false-standalone-types&quot; title=&quot;https://wiki.php.net/rfc/null-false-standalone-types&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;RFC e votação da comunidade “Allow null and false as stand-alone types”&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;Tipos-de-forma-normal-disjuntiva-(Disjunctive-normal-form-types-–-DNF)&quot; data-renderer-start-pos=&quot;5423&quot;&gt;Tipos de forma normal disjuntiva (Disjunctive normal form types – DNF)&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;5495&quot;&gt;Dev é uma coisa né… que nome complicado pra uma parada simples!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;5560&quot;&gt;Esta feature nada mais é do que permitir utilizar &lt;a href=&quot;https://www.php.net/manual/pt_BR/language.types.declarations.php#language.types.declarations.composite.union&quot; title=&quot;https://www.php.net/manual/pt_BR/language.types.declarations.php#language.types.declarations.composite.union&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Union types&lt;/a&gt; e &lt;a href=&quot;https://www.php.net/manual/pt_BR/language.types.declarations.php#language.types.declarations.composite.intersection&quot; title=&quot;https://www.php.net/manual/pt_BR/language.types.declarations.php#language.types.declarations.composite.intersection&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;Intersection Types&lt;/a&gt; ao mesmo tempo!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;5660&quot;&gt;A condição pra isso, é que os &lt;em data-renderer-mark=&quot;true&quot;&gt;Intersection types&lt;/em&gt; estejam entre parênteses, desta forma:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;5660&quot;&gt;function minhaFuncao((TipoA &amp;amp; TipoB) | false $param)&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;5803&quot;&gt;Aqui o tipo DNF é &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;(TipoA &amp;amp; TipoB) | false&lt;/code&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;5847&quot;&gt;A ideia é massa, mas vai começar a ficar tenso fazer esse tipo de coisa sem poder apelidar tipos. Talvez esta possa ser a próxima adição ao &lt;em data-renderer-mark=&quot;true&quot;&gt;core&lt;/em&gt; – alô galera que programa em C!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;6025&quot;&gt;Fonte: &lt;a href=&quot;https://wiki.php.net/rfc/dnf_types&quot; title=&quot;https://wiki.php.net/rfc/dnf_types&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;RFC e votação da comunidade “Disjunctive normal form types”&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;Constantes-em-traits&quot; data-renderer-start-pos=&quot;6094&quot;&gt;Constantes em &lt;em data-renderer-mark=&quot;true&quot;&gt;traits&lt;/em&gt;&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;6116&quot;&gt;As &lt;a href=&quot;https://www.php.net/manual/pt_BR/language.oop5.traits.php&quot; title=&quot;https://www.php.net/manual/pt_BR/language.oop5.traits.php&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;traits do PHP&lt;/a&gt; já nos permitem compartilhar propriedades e métodos. A nova adição que veio na versão 8.2 do PHP agora nos permite a criar constantes dentro de &lt;em data-renderer-mark=&quot;true&quot;&gt;traits&lt;/em&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;6286&quot;&gt;Veja o código a seguir:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;6286&quot;&gt;trait MinhaTrait&lt;br&gt;{&lt;br&gt;    public const MINHA_CONST = 0xABC;&lt;br&gt;}&lt;br&gt;&lt;br&gt;class MinhaClasse&lt;br&gt;{&lt;br&gt;    use MinhaTrait;&lt;br&gt;}&lt;br&gt;&lt;br&gt;MinhaTrait::MINHA_CONST; // Erro&lt;br&gt;MinhaClasse::MINHA_CONST; // 0xABC&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;6483&quot;&gt;Portanto não é possível acessar a constante diretamente através da &lt;em data-renderer-mark=&quot;true&quot;&gt;trait&lt;/em&gt; mas sim de classes que a utilizem. Importante também notar que a &lt;a href=&quot;https://www.php.net/manual/en/language.oop5.visibility.php#language.oop5.visiblity-constants&quot; title=&quot;https://www.php.net/manual/en/language.oop5.visibility.php#language.oop5.visiblity-constants&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;visibilidade das constantes&lt;/a&gt; (public, protected ou private) será naturalmente respeitada.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;6711&quot;&gt;Fonte: &lt;a href=&quot;https://wiki.php.net/rfc/constants_in_traits&quot; title=&quot;https://wiki.php.net/rfc/constants_in_traits&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;RFC e votação da comunidade “Constants in Traits”&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;Esconder-parâmetros-em-backtraces&quot; data-renderer-start-pos=&quot;6770&quot;&gt;Esconder parâmetros em &lt;em data-renderer-mark=&quot;true&quot;&gt;backtraces&lt;/em&gt;&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;6805&quot;&gt;Quando um erro acontece na nossa aplicação, o PHP gera um &lt;em data-renderer-mark=&quot;true&quot;&gt;backtrace&lt;/em&gt; que mostra método a método o que aconteceu naquela execução. As vezes alguns parâmetros não deveriam ser mostrados nos logs, por questão de segurança. Por exemplo, o log a seguir é meio perigoso:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;6805&quot;&gt;function ftp_upload(&lt;br&gt;    string $login,&lt;br&gt;    string $senha,&lt;br&gt;    string $src,&lt;br&gt;    string $dst&lt;br&gt;) {&lt;br&gt;    throw new Exception(&quot;Não implementado.&quot;);&lt;br&gt;}&lt;br&gt;&lt;br&gt;ftp_uload(getenv(&apos;FTP_LOGIN&apos;), getenv(&apos;FTP_SENHA&apos;), &apos;./arquivo.txt&apos;, &apos;/home/nawarian/arquivo.txt&apos;);&lt;br&gt;&lt;br&gt;Stack trace:&lt;br&gt;#0 ftp.php(58): ftp_upload(&apos;nawarian&apos;, &apos;1337&apos;, &apos;./arquivo.txt&apos;, &apos;/home/nawarian/arquivo.txt&apos;)&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;7424&quot;&gt;O erro acima (que eu escrevi dessa forma só pra ilustrar o problema) acaba expondo as varáveis &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;$login&lt;/code&gt; e &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;$senha&lt;/code&gt; no stack trace.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;7552&quot;&gt;A partir do PHP 8.2 será possível anotar alguns parâmetros da função como &lt;em data-renderer-mark=&quot;true&quot;&gt;sensíveis&lt;/em&gt;, de forma que o PHP não irá mostrar seus valores no trace. Funciona assim: você adiciona o atributo &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;#[SensitiveParameter]&lt;/code&gt; ao parâmetro e o PHP cuida de todo o resto.&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;7552&quot;&gt;function ftp_upload(&lt;br&gt;    string $login,&lt;br&gt;    #[SensitiveParameter] string $senha,&lt;br&gt;    string $src,&lt;br&gt;    string $dst&lt;br&gt;) {&lt;br&gt;    throw new Exception(&quot;Não implementado.&quot;);&lt;br&gt;}&lt;br&gt;&lt;br&gt;ftp_uload(getenv(&apos;FTP_LOGIN&apos;), getenv(&apos;FTP_SENHA&apos;), &apos;./arquivo.txt&apos;, &apos;/home/nawarian/arquivo.txt&apos;);&lt;br&gt;&lt;br&gt;Stack trace:&lt;br&gt;#0 ftp.php(58): ftp_upload(&apos;nawarian&apos;, Object(SensitiveParameterValue), &apos;./arquivo.txt&apos;, &apos;/home/nawarian/arquivo.txt&apos;)&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;8204&quot;&gt;Note que no &lt;em data-renderer-mark=&quot;true&quot;&gt;stack trace&lt;/em&gt; o segundo parâmetro, agora marcado como sensível, é apresentado como &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;Object(SensitiveParameter)&lt;/code&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;8326&quot;&gt;Fonte: &lt;a href=&quot;https://wiki.php.net/rfc/redact_parameters_in_back_traces&quot; title=&quot;https://wiki.php.net/rfc/redact_parameters_in_back_traces&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow&quot;&gt;RFC e votação da comunidade “Redacting parameters in back traces”&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;Funções-utf8_encode()-e-utf8_decode()-descontinuadas&quot; data-renderer-start-pos=&quot;8401&quot;&gt;Funções &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;utf8_encode()&lt;/code&gt; e &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;utf8_decode()&lt;/code&gt; descontinuadas&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;8455&quot;&gt;A partir da versão 8.2 do PHP, as funções &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;utf8_encode()&lt;/code&gt; e &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;utf8_decode()&lt;/code&gt; serão descontinuadas e vão gerar um &lt;em data-renderer-mark=&quot;true&quot;&gt;notice&lt;/em&gt; no seu Log. No futuro estas duas funções serão removidas.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;8629&quot;&gt;A mensagem do tipo &lt;em data-renderer-mark=&quot;true&quot;&gt;notice&lt;/em&gt; se parece com o seguinte:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;8629&quot;&gt;Deprecated: Function utf8_encode() is deprecated&lt;br&gt;Deprecated: Function utf8_decode() is deprecated&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;8781&quot;&gt;Para realizar a migração, você pode optar por utilizar as função &lt;a href=&quot;https://www.php.net/manual/pt_BR/function.mb-convert-encoding.php&quot; title=&quot;https://www.php.net/manual/pt_BR/function.mb-convert-encoding.php&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;mb_convert_encoding()&lt;/em&gt;&lt;/a&gt; da extensão &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;Multibyte String&lt;/code&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;8899&quot;&gt;O grande Vinicius Dias, do canal Dias de Dev, fez um vídeo maravilhoso explicando a RFC, suas motivações e como fazer a migração:&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;8899&quot;&gt;&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/al47Lz_SWLc&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;allowfullscreen&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;8899&quot;&gt;Fonte: &lt;a href=&quot;https://wiki.php.net/rfc/remove_utf8_decode_and_utf8_encode&quot; title=&quot;https://wiki.php.net/rfc/remove_utf8_decode_and_utf8_encode&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot;&gt;RFC e votação da comunidade “Deprecate and Remove utf8_encode and utf8_decode”&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1ggicv0cm13&quot; data-renderer-start-pos=&quot;8899&quot;&gt;Mudança no retorno dos métodos que criam datas&lt;/h2&gt;
&lt;p&gt;As classes &lt;code&gt;DateTime&lt;/code&gt; e &lt;code&gt;DateTimeImmutable&lt;/code&gt; possuem métodos para criar datas com as seguintes assinaturas:&lt;/p&gt;
&lt;pre&gt;DateTime::createFromImmutable(): DateTime&lt;br&gt;DateTimeImmutable::createFromMutable(): DateTimeImmutable&lt;/pre&gt;
&lt;p&gt;A partir da versão 8.2 do PHP, ambas assinaturas passarão a retornar o tipo &lt;code&gt;static&lt;/code&gt;. Apesar de parecer não ter efeito colateral algum, isto muda fundamentalmente como podemos trabalhar com herança nas classes &lt;code&gt;DateTime&lt;/code&gt; e &lt;code&gt;DateTimeImmutable&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Esta é uma mudança que quebra compatibilidade com as versões anteriores caso seu código possua alguma herança das classes &lt;code&gt;DateTime&lt;/code&gt; ou &lt;code&gt;DateTimeImmutable&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Fonte: &lt;a href=&quot;https://github.com/php/php-src/blob/php-8.2.0RC5/UPGRADING#L22-L26&quot; rel=&quot;nofollow&quot;&gt;Manual de atualização do PHP 8.2 RC5&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1ggicv0cm14&quot;&gt;Outras mudanças&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;9854&quot;&gt;Também foram introduzidas outras mudanças menores de sintaxe e manutenção geral da plataforma, para remover suporte a algumas funções.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;9990&quot;&gt;A lista completa de mudanças você encontra no arquivo &lt;a href=&quot;https://github.com/php/php-src/blob/php-8.2.0RC5/UPGRADING&quot; title=&quot;https://github.com/php/php-src/blob/php-8.2.0RC5/UPGRADING&quot; rel=&quot;nofollow&quot;&gt;UPGRADING&lt;/a&gt; do repositório oficial do PHP.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;9990&quot;&gt;Não esquece de compartilhar este artigo em suas redes e com colegas de trabalho.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;10168&quot;&gt;Até a próxima! 👋&lt;/p&gt;</content:encoded><category>php</category></item><item><title>Como conectar com mongodb no node.js com TDD</title><link>https://codamos.com.br/como-conectar-mongodb-nodejs-com-mongoose-tdd/</link><guid isPermaLink="true">https://codamos.com.br/como-conectar-mongodb-nodejs-com-mongoose-tdd/</guid><description>Neste tutorial nós vamos ver como conectar sua aplicação Node.js com um banco de dados MongoDB. E como tem muita coisa acontecendo ao mesmo tempo, vamos trabalhar com TDL – aprendizado guiado por test</description><pubDate>Tue, 27 Sep 2022 22:51:31 GMT</pubDate><content:encoded>&lt;p data-renderer-start-pos=&quot;1&quot;&gt;Neste tutorial nós vamos ver como conectar sua aplicação Node.js com um banco de dados MongoDB. E como tem muita coisa acontecendo ao mesmo tempo, vamos trabalhar com &lt;a href=&quot;/tdl-aprendizado-por-testes/&quot;&gt;TDL – aprendizado guiado por testes&lt;/a&gt;. Ou seja: vamos escrever testes para entender o que cada passo está fazendo.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;282&quot;&gt;Este passo a passo vai te permitir:&lt;/p&gt;
&lt;ul&gt;
&lt;li data-renderer-start-pos=&quot;321&quot;&gt;Subir um banco de dados MongoDB via Docker para testes;&lt;/li&gt;
&lt;li data-renderer-start-pos=&quot;321&quot;&gt;Baixar e configurar o pacote &lt;a href=&quot;https://mongoosejs.com/docs/index.html&quot; title=&quot;https://mongoosejs.com/docs/index.html&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; style=&quot;font-family: var(--editor-font-family); font-size: inherit; font-weight: var(--font-weight-normal);&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;mongoose&lt;/a&gt;&lt;span style=&quot;color: var(--text-primary-color); font-family: var(--editor-font-family); font-size: inherit; font-weight: var(--font-weight-normal);&quot;&gt;;&lt;/span&gt;&lt;/li&gt;
&lt;li data-renderer-start-pos=&quot;321&quot;&gt;Criar coleções no MongoDB via mongoose;&lt;/li&gt;
&lt;li data-renderer-start-pos=&quot;321&quot;&gt;Inserir registros em coleções no MongoDB via mongoose; e&lt;/li&gt;
&lt;li data-renderer-start-pos=&quot;321&quot;&gt;Listar registros em coleções no MongoDB via mongoose&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-renderer-start-pos=&quot;581&quot;&gt;Então vem comigo que a gente vai começar!&lt;/p&gt;
&lt;div class=&quot;post__toc&quot;&gt;
&lt;h3&gt;Conteúdos do post&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1ge2jgeblr&quot;&gt;Passo 1 – instalar o pacote mongoose&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1ge2jgebls&quot;&gt;Passo 2 – instalar o pacote Jest para fazer TDD&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1ge2jgeblt&quot;&gt;Passo 3 – Subindo um servidor MongoDB para testes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1ge2jgeblu&quot;&gt;Passo 4 – vamos o esqueleto do nosso caso de teste&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1ge2jgeblv&quot;&gt;Passo 5 – testar a conexão com o MongoDB com mongoose e jest&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1ge2jgebl10&quot;&gt;Passo 6 – testar a inserção de entidades no MongoDB com mongoose e jest&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1ge2jgebl11&quot;&gt;Passo 7 – testar a obtenção de documentos no MongoDB com mongoose e jest&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1ge2jgebl12&quot;&gt;Código utilizado no artigo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1ge2jgebl13&quot;&gt;Recomendação de outros testes para rodar&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#Conclusão&quot;&gt;Conclusão&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2&gt;Vídeo de apoio&lt;/h2&gt;
&lt;p&gt;Caso você esteja sem energia para ler o texto, ou tenha se perdido em algum momento, eu fiz um vídeo de apoio pra te auxiliar a entender tudo sobre como começar a trabalhar com MongoDB usando Mongoose em sua aplicação node.js.&lt;/p&gt;
&lt;p&gt;&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/6rXfoarZmvg&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;allowfullscreen&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1ge2jgeblr&quot; class=&quot;p1&quot;&gt;Passo 1 – instalar o pacote mongoose&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;665&quot;&gt;Eu estou rodando o &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;node v16.17.0&lt;/code&gt; mas os passos abaixo devem funcionar bem em versões superiores à &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;11&lt;/code&gt; sem muitos problemas.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;789&quot;&gt;Vamos instalar o mongoose com &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;npm&lt;/code&gt; usando a seguinte linha:&lt;/p&gt;
&lt;pre class=&quot;p1&quot;&gt;$ npm install mongoose --save&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;880&quot;&gt;Caso você use &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;yarn&lt;/code&gt;, o comando é o seguinte:&lt;/p&gt;
&lt;pre class=&quot;p1&quot;&gt;$ yarn add mongoose&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;946&quot;&gt;O meu &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;package.json&lt;/code&gt; ficou assim:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;946&quot;&gt;&quot;dependencies&quot;: {&lt;br&gt;  &quot;mongoose&quot;: &quot;^6.6.2&quot;&lt;br&gt;}&lt;/pre&gt;
&lt;h2 id=&quot;mcetoc_1ge2jgebls&quot; class=&quot;p1&quot;&gt;Passo 2 – instalar o pacote Jest para fazer TDD&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;1072&quot;&gt;Como nós queremos trabalhar com testes, vamos instalar o pacote &lt;a href=&quot;https://jestjs.io/pt-BR/docs/getting-started&quot; title=&quot;https://jestjs.io/pt-BR/docs/getting-started&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;Jest&lt;/a&gt;:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;1072&quot;&gt;$ npm install --save-dev jest&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;1174&quot;&gt;Caso você utilize o Yarn, rode o seguinte comando:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;1174&quot;&gt;$ yarn add --dev jest&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;1249&quot;&gt;Meu &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;package.json&lt;/code&gt; ficou mais ou menos assim:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;1249&quot;&gt;&quot;devDependencies&quot;: {&lt;br&gt;  &quot;jest&quot;: &quot;^29.0.3&quot;&lt;br&gt;}&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;1338&quot;&gt;Agora vamos adicionar a seguinte seção ao arquivo &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;package.json&lt;/code&gt;:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;1338&quot;&gt;&quot;scripts&quot;: {&lt;br&gt;  &quot;test&quot;: &quot;jest&quot;&lt;br&gt;}&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;1436&quot;&gt;Com isso nós podemos rodar o seguinte comando no terminal. A cada novo arquivo que criarmos e cada vez que salvarmos um arquivo, Jest irá rodar todos os testes novamente:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;1436&quot;&gt;$ npm run test -- --watchAll&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;1632&quot;&gt;A sua tela deverá ficar mais ou menos assim:&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/51/jest-watch-all-sem-testes.png&quot; alt=&quot;Terminal rodando Jest e indicando que nenhum teste foi encontrado.&quot; width=&quot;1080&quot; height=&quot;414&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Terminal rodando Jest e indicando que nenhum teste foi encontrado.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;1681&quot;&gt;Deixa esse terminal rodando o comando, a gente já já vai voltar a prestar atenção nele.&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1ge2jgeblt&quot; class=&quot;p1&quot;&gt;Passo 3 – Subindo um servidor MongoDB para testes&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;1811&quot;&gt;Para acompanhar nosso tutorial a gente precisa de um servidor &lt;a href=&quot;https://www.mongodb.com/docs/manual/tutorial/getting-started/&quot; title=&quot;https://www.mongodb.com/docs/manual/tutorial/getting-started/&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;MongoDB&lt;/a&gt; rodando. Como eu não quero gastar tempo e energia subindo um servidor na minha máquina local, eu vou utilizar a &lt;a href=&quot;https://hub.docker.com/_/mongo&quot; title=&quot;https://hub.docker.com/_/mongo&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;imagem docker oficial do MongoDB&lt;/a&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2028&quot;&gt;Esta imagem exige duas variáveis de ambiente definidas:&lt;/p&gt;
&lt;ul&gt;
&lt;li data-renderer-start-pos=&quot;2028&quot;&gt;MONGO_INITDB_ROOT_USERNAME – o usuário padrão do banco de dados&lt;/li&gt;
&lt;li data-renderer-start-pos=&quot;2028&quot;&gt;MONGO_INITDB_ROOT_PASSWORD – a senha do usuário padrão&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-renderer-start-pos=&quot;2212&quot;&gt;Então vamos criar um arquivo &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;.env&lt;/code&gt; com o seguinte conteúdo:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;2212&quot;&gt;MONGO_INITDB_ROOT_USERNAME=root&lt;br&gt;MONGO_INITDB_ROOT_PASSWORD=root&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;2337&quot;&gt;Com o arquivo acima criado, podemos iniciar o servidor docker com o seguinte comando:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;2337&quot;&gt;$ docker run --rm -it --env-file .env -p27017:27017 mongo:latest&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;2490&quot;&gt;Deixa eu explicar o que comando acima está fazendo, item a item:&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2556&quot;&gt;A opção &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;--rm&lt;/code&gt; vai apagar o container docker assim que interrompermos sua execução. Dessa forma o container não fica em disco quando a gente terminar nosso teste.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2718&quot;&gt;A opção &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;-it&lt;/code&gt; vai manter o shell conectado à saída do servidor, desta forma você consegue ver os logs do servidor em seu terminar. Como na imagem a seguir:&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/51/terminal-docker-mongodb.png&quot; alt=&quot;Terminal exibindo logs do servidor MongoDB&quot; width=&quot;1080&quot; height=&quot;420&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Terminal exibindo logs do servidor MongoDB&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;2876&quot;&gt;A opção &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;--env-file .env&lt;/code&gt; vai usar o arquivo &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;.env&lt;/code&gt; que nós criamos para definir as variáveis de ambiente que ficam presentes no container docker. Como nós definimos &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;MONGO_INITDB_ROOT_USERNAME&lt;/code&gt; e &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;MONGO_INITDB_ROOT_PASSWORD&lt;/code&gt; o container vai inicializar o servidor utilizando aqueles dados como usuário e senha padrão do banco de dados.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3206&quot;&gt;Por fim, &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;-p27017:27017&lt;/code&gt; vai mapear a porta &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;27017&lt;/code&gt; do container à porta &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;27017&lt;/code&gt; da máquina local. A porta &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;27017&lt;/code&gt; é a &lt;a href=&quot;https://www.mongodb.com/docs/manual/reference/default-mongodb-port/&quot; title=&quot;https://www.mongodb.com/docs/manual/reference/default-mongodb-port/&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;porta padrão de conexão com o MongoDB&lt;/a&gt;. Ao fazer este mapeamento nós podemos acessar &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;mongodb://localhost:27017&lt;/code&gt; e o docker vai automaticamente nos rotear para o container.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3488&quot;&gt;O último argumento, &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;mongo:latest&lt;/code&gt;, é o nome da &lt;a href=&quot;https://hub.docker.com/_/mongo&quot; title=&quot;https://hub.docker.com/_/mongo&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;imagem MongoDB no Docker Hub&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1ge2jgeblu&quot; class=&quot;p1&quot;&gt;Passo 4 – vamos o esqueleto do nosso caso de teste&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;3617&quot;&gt;Agora é hora de colocar a mão na massa, vamos criar nosso caso de teste para testar nossa conexão com o MongoDB.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3731&quot;&gt;Adicione o seguinte esqueleto num arquivo &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;mongodb.test.js&lt;/code&gt;:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;3731&quot;&gt;// mongodb.test.js&lt;br&gt;const mongoose = require(&apos;mongoose&apos;)&lt;br&gt;&lt;br&gt;test(&apos;Meu primeiro teste&apos;, () =&amp;gt; {&lt;br&gt;  expect(true).toBeTruthy()&lt;br&gt;})&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;3915&quot;&gt;Ao salvar o arquivo acima, o terminal que nós deixamos rodando desde o passo 2 deverá ficar assim:&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/51/teste-exemplo-jest-terminal.png&quot; alt=&quot;Terminal exibindo que o teste de exemplo passou&quot; width=&quot;1077&quot; height=&quot;412&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Terminal exibindo que o teste de exemplo passou&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;4018&quot;&gt;Nosso ambiente está pronto para experimentarmos com o Mongoose!&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1ge2jgeblv&quot; class=&quot;p1&quot;&gt;Passo 5 – testar a conexão com o MongoDB com mongoose e jest&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;4145&quot;&gt;Vamos começar por conectar com o MongoDB usando o mongoose. De acordo com a documentação oficial nós podemos usar o método &lt;a href=&quot;https://mongoosejs.com/docs/api/mongoose.html#mongoose_Mongoose-connect&quot; title=&quot;https://mongoosejs.com/docs/api/mongoose.html#mongoose_Mongoose-connect&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;mongoose.connect()&lt;/a&gt;, que retorna uma &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise&quot; title=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;Promise&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;4314&quot;&gt;Portanto o &lt;em data-renderer-mark=&quot;true&quot;&gt;callback&lt;/em&gt; da função &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;then()&lt;/code&gt; pode fazer nosso teste passar, e o &lt;em data-renderer-mark=&quot;true&quot;&gt;callback&lt;/em&gt; da função &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;catch()&lt;/code&gt; deverá fazer o teste falhar. Assim nós saberemos se a conexão está funcionando.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;4494&quot;&gt;Vamos adicionar o seguinte caso de teste:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;4494&quot;&gt;const MONGODB_DSN = &apos;mongodb://root:root@localhost:27017&apos;&lt;br&gt;&lt;br&gt;test(&apos;Conexão com MongoDB&apos;, async () =&amp;gt; {&lt;br&gt;  const promise = mongoose.connect(MONGODB_DSN)&lt;br&gt;  &lt;br&gt;  await expect(promise).resolves.toBeInstanceOf(mongoose.Mongoose)&lt;br&gt;&lt;br&gt;  await mongoose.connection.close()&lt;br&gt;})&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;4760&quot;&gt;Ao salvar o arquivo com o teste acima, o Jest deverá imediatamente rodar os testes e acusar sucesso (caso os dados da conexão estejam corretos):&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/51/tdd-conexao-mongodb.png&quot; alt=&quot;Terminal indicando que o teste &apos;Conexão com MongoDB&apos; passou&quot; width=&quot;1080&quot; height=&quot;410&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Terminal indicando que o teste &apos;Conexão com MongoDB&apos; passou&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;4909&quot;&gt;Aproveite e mude os valores da constante &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;MONGODB_DSN&lt;/code&gt; para ter certeza de que o teste falha como deveria.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;5015&quot;&gt;Agora vamos brincar com alguns schemas. Tá na hora de inserir uma entidade no nosso MongoDB.&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1ge2jgebl10&quot; class=&quot;p1&quot;&gt;Passo 6 – testar a inserção de entidades no MongoDB com mongoose e jest&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;5182&quot;&gt;É isso, vamos então criar uma coleção chamada &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;artigos&lt;/code&gt; que possui os seguintes campos:&lt;/p&gt;
&lt;ul&gt;
&lt;li data-renderer-start-pos=&quot;5182&quot;&gt;Título&lt;/li&gt;
&lt;li data-renderer-start-pos=&quot;5182&quot;&gt;URL&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-renderer-start-pos=&quot;5288&quot;&gt;De acordo com a &lt;a href=&quot;https://mongoosejs.com/docs/guide.html&quot; title=&quot;https://mongoosejs.com/docs/guide.html&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;documentação oficial do Mongoose&lt;/a&gt; nós precisamos primeiro definir um objeto do tipo &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;Schema&lt;/code&gt;, que mapeia o que acontece dentro do MongoDB para JavaScript. Depois nós precisamos criar um objeto do tipo &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;Model&lt;/code&gt; para poder interagir com aquela coleção que definimos o &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;Schema&lt;/code&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;5573&quot;&gt;Ao inserir um objeto na coleção a gente sabe que tudo funcionou porque o mongoose vai adicionar um campo &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;_id&lt;/code&gt; do tipo &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;mongoose.Types.ObjectId&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;ak-editor-panel css-1ov4ty1&quot; data-panel-type=&quot;custom&quot; data-panel-color=&quot;#FFEBE6&quot; data-panel-icon=&quot;:info:&quot; data-panel-icon-id=&quot;atlassian-info&quot;&gt;
&lt;div&gt;
&lt;p class=&quot;p1 msg msg--highlight &quot;&gt;Note que vamos definir Schema e Model fora do caso de teste, para que possamos reutilizar estas variáveis em outros casos de teste.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ak-editor-panel__content&quot;&gt;
&lt;p data-renderer-start-pos=&quot;5851&quot;&gt;O caso de teste ficou assim:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;5851&quot;&gt;const artigoSchema = new mongoose.Schema({&lt;br&gt;  titulo: String,&lt;br&gt;  url: String,&lt;br&gt;})&lt;br&gt;&lt;br&gt;// &apos;Artigo&apos; vai ser tratado como uma classe de agora em diante&lt;br&gt;const Artigo = mongoose.models.artigos || mongoose.model(&apos;artigos&apos;, artigoSchema)&lt;br&gt;&lt;br&gt;test(&apos;Inserção no MongoDB&apos;, async () =&amp;gt; {&lt;br&gt;  // Nós já vimos que a linha abaixo conecta ao DB&lt;br&gt;  await mongoose.connect(MONGODB_DSN)&lt;br&gt;&lt;br&gt;  // Cria o schema que mapeia mongodb para o JS&lt;br&gt;  const artigoSchema = new mongoose.Schema({&lt;br&gt;    titulo: String,&lt;br&gt;    url: String,&lt;br&gt;  })&lt;br&gt;&lt;br&gt;  // &apos;Artigo&apos; vai ser tratado como uma classe de agora em diante&lt;br&gt;  const Artigo = mongoose.models.artigos || mongoose.model(&apos;artigos&apos;, artigoSchema)&lt;br&gt;&lt;br&gt;  // Criamos uma instância de Artigo&lt;br&gt;  const tutorial_mongodb = new Artigo({&lt;br&gt;    titulo: &apos;Como conectar com mongodb no node.js com TDD&apos;,&lt;br&gt;    url: &apos;https://codamos.com.br/como-conectar-mongodb-nodejs-tdd&apos;,&lt;br&gt;  })&lt;br&gt;&lt;br&gt;  // Salva o registro no MongoDB&lt;br&gt;  await tutorial_mongodb.save()&lt;br&gt;&lt;br&gt;  // &apos;tutorial_mongodb&apos; agora deverá ter um campo &apos;_id&apos;&lt;br&gt;  expect(tutorial_mongodb._id).toBeInstanceOf(mongoose.Types.ObjectId)&lt;br&gt;&lt;br&gt;  await mongoose.connection.close()&lt;br&gt;})&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;6879&quot;&gt;A tela do terminal do Jest ficou assim pra mim:&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/51/tdd-inserir-documento-mongodb.png&quot; alt=&quot;Terminal indicando que o teste &apos;Inserção no MongoDB&apos; passou&quot; width=&quot;1080&quot; height=&quot;411&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Terminal indicando que o teste &apos;Inserção no MongoDB&apos; passou&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;mcetoc_1ge2jgebl11&quot; class=&quot;p1&quot;&gt;Passo 7 – testar a obtenção de documentos no MongoDB com mongoose e jest&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;7005&quot;&gt;Sempre que precisamos buscar um documento em nossa coleção, ou mesmo listar todos documentos, podemos utilizar o método &lt;a href=&quot;https://mongoosejs.com/docs/api/model.html#model_Model-find&quot; title=&quot;https://mongoosejs.com/docs/api/model.html#model_Model-find&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;Model.find()&lt;/em&gt;&lt;/a&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt; &lt;/em&gt;que deverá retornar o tipo &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;Promise&amp;lt;Model[]&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;7184&quot;&gt;Então para o nosso teste podemos só verificar que a lista de documentos tem mais do que &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;0&lt;/code&gt; elementos. Afinal o teste anterior já criou documentos no banco de dados.&lt;/p&gt;
&lt;p class=&quot;msg msg--success&quot; data-renderer-start-pos=&quot;7184&quot;&gt;Um teste de produção não deveria assumir que os testes anteriores passaram, e muito menos depender de estado global. &lt;strong data-renderer-mark=&quot;true&quot;&gt;Neste caso tudo bem trabalhar assim porque estamos utilizando testes para &lt;/strong&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;aprender&lt;/strong&gt;&lt;/em&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;7553&quot;&gt;O caso de testes ficou assim:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;7553&quot;&gt;test(&apos;Listar todos documentos no MongoDB&apos;, async () =&amp;gt; {&lt;br&gt;  await mongoose.connect(MONGODB_DSN)&lt;br&gt;&lt;br&gt;  const artigoSchema = new mongoose.Schema({&lt;br&gt;    titulo: String,&lt;br&gt;    url: String,&lt;br&gt;  })&lt;br&gt;&lt;br&gt;  const artigosEncontrados = await Artigo.find()&lt;br&gt;&lt;br&gt;  expect(artigosEncontrados.length).toBeGreaterThan(0)&lt;br&gt;&lt;br&gt;  await mongoose.connection.close()&lt;br&gt;})&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;7877&quot;&gt;Jest deverá então acusar sucesso: nosso teste passou e temos uma lista de artigos na variável &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;artigosEncontrados&lt;/code&gt;.&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/51/tdd-listar-documentos-mongodb.png&quot; alt=&quot;Terminal indicando que o teste &apos;Listar todos documentos no MongoDB&apos; passou&quot; width=&quot;1080&quot; height=&quot;366&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Terminal indicando que o teste &apos;Listar todos documentos no MongoDB&apos; passou&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;7995&quot;&gt;Você também pode experimentar fazer alguns &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;console.log()&lt;/code&gt; dentro do escopo dos testes pra ver o que está lá dentro. O bacana de usar TDL é que temos um ambiente preparado para brincar e testar o que quisermos a qualquer momento, num ambiente controlado.&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1ge2jgebl12&quot; class=&quot;p1&quot;&gt;Código utilizado no artigo&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;8277&quot;&gt;Você pode verificar o código completo utilizado neste artigo &lt;a href=&quot;https://gist.github.com/nawarian/604c4c5ee5a09aef71ee7bd6989142a1&quot; title=&quot;https://gist.github.com/nawarian/604c4c5ee5a09aef71ee7bd6989142a1&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-tgpl01&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;neste GIST aqui&lt;/a&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;8277&quot;&gt;
&lt;script src=&quot;https://gist.github.com/nawarian/604c4c5ee5a09aef71ee7bd6989142a1.js&quot;&gt;&lt;/script&gt;
&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1ge2jgebl13&quot; class=&quot;p1&quot;&gt;Recomendação de outros testes para rodar&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;8492&quot;&gt;Você provavelmente já entendeu a ideia do negócio: cada funcionalidade que quiser testar, basta criar um novo caso de teste e ver como o framework se comporta.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;8653&quot;&gt;Eu recomendo que você implemente por si os seguintes casos de teste:&lt;/p&gt;
&lt;ul&gt;
&lt;li data-renderer-start-pos=&quot;8653&quot;&gt;Atualizar um documento MongoDB;&lt;/li&gt;
&lt;li data-renderer-start-pos=&quot;8653&quot;&gt;Buscar um documento pelo título;&lt;/li&gt;
&lt;li data-renderer-start-pos=&quot;8653&quot;&gt;Remover um documento por &lt;code class=&quot;code css-1xivnph&quot; style=&quot;font-weight: var(--font-weight-normal);&quot; data-renderer-mark=&quot;true&quot;&gt;_id&lt;/code&gt;&lt;span style=&quot;color: var(--text-primary-color); font-family: var(--editor-font-family); font-size: inherit; font-weight: var(--font-weight-normal);&quot;&gt;;&lt;/span&gt;&lt;/li&gt;
&lt;li data-renderer-start-pos=&quot;8653&quot;&gt;Receber a quantidade (&lt;code class=&quot;code css-1xivnph&quot; style=&quot;font-weight: var(--font-weight-normal);&quot; data-renderer-mark=&quot;true&quot;&gt;count&lt;/code&gt;&lt;span style=&quot;color: var(--text-primary-color); font-family: var(--editor-font-family); font-size: inherit; font-weight: var(--font-weight-normal);&quot;&gt;) de documentos que atendem a um filtro;&lt;/span&gt;&lt;/li&gt;
&lt;li data-renderer-start-pos=&quot;8653&quot;&gt;Listar documentos ordenados por &lt;code class=&quot;code css-1xivnph&quot; style=&quot;font-weight: var(--font-weight-normal);&quot; data-renderer-mark=&quot;true&quot;&gt;url&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-renderer-start-pos=&quot;8939&quot;&gt;Você vai ver que após escrever os testes acima, você já sabe tudo o que precisa pra começar a escrever uma aplicação completa usando Node.js, MongoDB e Mongoose.&lt;/p&gt;
&lt;h2 id=&quot;Conclusão&quot; data-renderer-start-pos=&quot;9102&quot;&gt;Conclusão&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;9113&quot;&gt;Os testes que escrevemos aqui não devem ser utilizados em produção! São apenas testes que utilizamos para aprender a ferramenta. Assim que entender como a ferramenta funciona, recomendo remover estes testes e desenvolver sua aplicação de forma independente, com testes que façam sentido para a sua aplicação.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;9423&quot;&gt;Não se esqueça de que ao interromper seu comando &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;docker&lt;/code&gt; o banco de dados não vai mais funcionar. E ao rodar o mesmo comando novamente, seu banco de dados estará vazio porque usamos a opção &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;--rm&lt;/code&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;9619&quot;&gt;Se você gostou da forma como o artigo foi organizado, não deixa de compartilhar em suas redes sociais!&lt;/p&gt;
&lt;div class=&quot;rich-media-item mediaSingleView-content-wrap image-center css-1mzi1es&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div class=&quot;css-1cdb7pu&quot;&gt;
&lt;div data-context-id=&quot;66420739&quot; data-type=&quot;file&quot; data-node-type=&quot;media&quot; data-width=&quot;1080&quot; data-height=&quot;366&quot; data-id=&quot;8ebf8c75-11f8-4340-a643-a63e78c842e6&quot; data-collection=&quot;contentId-66420739&quot; data-file-name=&quot;Screenshot 2022-09-27 at 23.40.21.png&quot; data-file-size=&quot;63278&quot; data-file-mime-type=&quot;image/png&quot; data-alt=&quot;&quot;&gt;
&lt;div id=&quot;newFileExperienceWrapper&quot; class=&quot;new-file-experience-wrapper css-1aycyi5&quot; data-testid=&quot;media-card-view&quot;&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;rich-media-item mediaSingleView-content-wrap image-center css-1mzi1es&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div class=&quot;css-1fk0raw&quot;&gt;
&lt;div data-context-id=&quot;66420739&quot; data-type=&quot;file&quot; data-node-type=&quot;media&quot; data-width=&quot;1080&quot; data-height=&quot;411&quot; data-id=&quot;3eaa8299-c2ce-440f-a633-38901f35cfc7&quot; data-collection=&quot;contentId-66420739&quot; data-file-name=&quot;Screenshot 2022-09-27 at 23.27.42.png&quot; data-file-size=&quot;44867&quot; data-file-mime-type=&quot;image/png&quot; data-alt=&quot;&quot;&gt;
&lt;div id=&quot;newFileExperienceWrapper&quot; class=&quot;new-file-experience-wrapper css-1pxk23u&quot; data-testid=&quot;media-card-view&quot;&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;rich-media-item mediaSingleView-content-wrap image-center css-1mzi1es&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div class=&quot;css-2h4xrd&quot;&gt;
&lt;div data-context-id=&quot;66420739&quot; data-type=&quot;file&quot; data-node-type=&quot;media&quot; data-width=&quot;1080&quot; data-height=&quot;410&quot; data-id=&quot;f99dd4b6-2bdb-40a0-b8de-b82d6e7eca34&quot; data-collection=&quot;contentId-66420739&quot; data-file-name=&quot;Screenshot 2022-09-27 at 23.15.11.png&quot; data-file-size=&quot;40346&quot; data-file-mime-type=&quot;image/png&quot; data-alt=&quot;&quot;&gt;
&lt;div id=&quot;newFileExperienceWrapper&quot; class=&quot;new-file-experience-wrapper css-ap38jt&quot; data-testid=&quot;media-card-view&quot;&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;rich-media-item mediaSingleView-content-wrap image-center css-1mzi1es&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div class=&quot;css-m8qhrn&quot;&gt;
&lt;div data-context-id=&quot;66420739&quot; data-type=&quot;file&quot; data-node-type=&quot;media&quot; data-width=&quot;1077&quot; data-height=&quot;412&quot; data-id=&quot;e45aa748-fdee-42d6-aeeb-4d862f67fc69&quot; data-collection=&quot;contentId-66420739&quot; data-file-name=&quot;Screenshot 2022-09-27 at 23.00.44.png&quot; data-file-size=&quot;38958&quot; data-file-mime-type=&quot;image/png&quot; data-alt=&quot;&quot;&gt;
&lt;div id=&quot;newFileExperienceWrapper&quot; class=&quot;new-file-experience-wrapper css-17i12rg&quot; data-testid=&quot;media-card-view&quot;&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;rich-media-item mediaSingleView-content-wrap image-center css-1mzi1es&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div class=&quot;css-1siivon&quot;&gt;
&lt;div data-context-id=&quot;66420739&quot; data-type=&quot;file&quot; data-node-type=&quot;media&quot; data-width=&quot;1080&quot; data-height=&quot;414&quot; data-id=&quot;608b2166-de2b-41e8-b32f-4aae4b516097&quot; data-collection=&quot;contentId-66420739&quot; data-file-name=&quot;Screenshot 2022-09-27 at 22.58.56.png&quot; data-file-size=&quot;39370&quot; data-file-mime-type=&quot;image/png&quot; data-alt=&quot;&quot;&gt;
&lt;div id=&quot;newFileExperienceWrapper&quot; class=&quot;new-file-experience-wrapper css-mqn1rl&quot; data-testid=&quot;media-card-view&quot;&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</content:encoded><category>javascript</category><category>mongodb</category><category>node</category></item><item><title>Como encontrar arquivos no VIM (sem plugins)</title><link>https://codamos.com.br/como-encontrar-arquivos-no-vim-sem-plugins/</link><guid isPermaLink="true">https://codamos.com.br/como-encontrar-arquivos-no-vim-sem-plugins/</guid><description>Esta dica eu aprendi recentemente e mudou completamente a forma como eu uso o editor VIM! Eu estou acostumado a utilizar o plugin NERDTree pra navegar nos arquivos do projeto e fazer algumas buscas su</description><pubDate>Mon, 29 Aug 2022 13:52:25 GMT</pubDate><content:encoded>&lt;p data-renderer-start-pos=&quot;1&quot;&gt;Esta dica eu aprendi recentemente e mudou completamente a forma como eu uso o editor VIM!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;92&quot;&gt;Eu estou acostumado a utilizar o plugin &lt;code&gt;NERDTree&lt;/code&gt; pra navegar nos arquivos do projeto e fazer algumas buscas superficiais. Na maioria dos casos funciona bem pra mim, mas esta técnica que eu aprendi tem me economizado MUITO tempo.&lt;/p&gt;
&lt;p class=&quot;msg msg--info&quot; data-renderer-start-pos=&quot;92&quot;&gt;Caso você queira dar seus primeiros passos com VIM, eu escrevi &lt;a href=&quot;/vim-basico/&quot;&gt;um artigo bem simplificado sobre como começar a utilizar o VIM&lt;/a&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;322&quot;&gt;Vem comigo e lê até o final que tem dica de ouro sobre como deixar esse negócio ainda mais eficiente!&lt;/p&gt;
&lt;h2 class=&quot;p1&quot;&gt;A árvore de arquivos que vamos usar como exemplo&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;475&quot;&gt;Os exemplos que eu vou apresentar aqui (e no vídeo de apoio ao final do artigo) são baseados no projeto &lt;a href=&quot;/devlog-emulador-nes-arquitetura/&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;qmario&lt;/em&gt;&lt;/a&gt; – um emulador de NES escrito em C que eu estou desenvolvendo com vocês.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;659&quot;&gt;A estrutura de pastas atualmente é a seguinte:&lt;/p&gt;
&lt;pre class=&quot;code-block  css-iwznuw&quot;&gt;$ tree&lt;br&gt;.&lt;br&gt;├── LICENSE&lt;br&gt;├── Makefile&lt;br&gt;├── build&lt;br&gt;│   ├── bus.o&lt;br&gt;│   ├── cpu.o&lt;br&gt;│   ├── main.o&lt;br&gt;│   └── qmario&lt;br&gt;└── src&lt;br&gt;    ├── bus.c&lt;br&gt;    ├── bus.h&lt;br&gt;    ├── bus.test.c&lt;br&gt;    ├── cpu.c&lt;br&gt;    ├── cpu.h&lt;br&gt;    ├── cpu.test.c&lt;br&gt;    └── main.c&lt;/pre&gt;
&lt;h2 class=&quot;p1&quot;&gt;O comando :find&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;945&quot;&gt;Dentro do editor VIM você pode executar o comando :find pra buscar e abrir arquivos num determinado diretório.&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;945&quot;&gt;:find src/main.c&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;1075&quot;&gt;Ao executar o comando acima, caso VIM encontre um arquivo main.c dentro da pasta src/ ele irá abrir o arquivo imediatamente.&lt;/p&gt;
&lt;p&gt;&lt;img class=&quot;post__image&quot; src=&quot;/media/posts/49/vim-find-main-2.gif&quot; alt=&quot;&quot; width=&quot;2880&quot; height=&quot;1800&quot;&gt;&lt;/p&gt;
&lt;div class=&quot;rich-media-item mediaSingleView-content-wrap image-center css-1mzi1es&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div class=&quot;css-1jgvy8y&quot;&gt;
&lt;div data-context-id=&quot;62816257&quot; data-type=&quot;file&quot; data-node-type=&quot;media&quot; data-width=&quot;2880&quot; data-height=&quot;1800&quot; data-id=&quot;a39114f8-4de8-4746-a28b-093cb0300060&quot; data-collection=&quot;contentId-62816257&quot; data-file-name=&quot;vim-find-main.gif&quot; data-file-size=&quot;7470586&quot; data-file-mime-type=&quot;image/gif&quot; data-alt=&quot;&quot;&gt;
&lt;div class=&quot;new-file-experience-wrapper sc-gqPbQI jpDTvf&quot; data-testid=&quot;media-card-view&quot;&gt;
&lt;p data-renderer-start-pos=&quot;1204&quot;&gt;O comando também tem autocomplete ao pressionar a tecla TAB. Por exemplo, se o arquivo &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;Makefile&lt;/code&gt; existe o seguinte comando vai te ajudar a encontrar:&lt;/p&gt;
&lt;pre class=&quot;code-block  css-iwznuw&quot;&gt;:find ma&amp;lt;TAB&amp;gt;&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;1369&quot;&gt;Só que em vez de escrever &amp;lt;TAB&amp;gt; você deveria apertar a tecla &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;TAB&lt;/code&gt; (aquela que fica em cima do Caps Lock). Note que quando fizer isso, caso VIM encontre o arquivo, vai auto completar pra ti a linha. Note também que pra esta busca não importa muito se o nome está em maiúsculo ou minúsculo.&lt;/p&gt;
&lt;div class=&quot;rich-media-item mediaSingleView-content-wrap image-center css-1mzi1es&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div class=&quot;css-1jgvy8y&quot;&gt;
&lt;div data-context-id=&quot;62816257&quot; data-type=&quot;file&quot; data-node-type=&quot;media&quot; data-width=&quot;2880&quot; data-height=&quot;1800&quot; data-id=&quot;eea5a8d2-d0bd-45cc-8211-b22a64026e45&quot; data-collection=&quot;contentId-62816257&quot; data-file-name=&quot;vim-find-makefile.gif&quot; data-file-size=&quot;8798863&quot; data-file-mime-type=&quot;image/gif&quot; data-alt=&quot;&quot;&gt;
&lt;div class=&quot;new-file-experience-wrapper sc-gqPbQI jpDTvf&quot; data-testid=&quot;media-card-view&quot;&gt;
&lt;p&gt;&lt;img class=&quot;post__image&quot; src=&quot;/media/posts/49/vim-find-makefile-2.gif&quot; alt=&quot;&quot; width=&quot;2880&quot; height=&quot;1800&quot;&gt;&lt;/p&gt;
&lt;h2 class=&quot;p1&quot;&gt;Busca recursiva&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;1678&quot;&gt;O comando &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;find&lt;/code&gt; por si só já é útil, mas convenhamos que se você já sabe a pasta onde o arquivo está não tem muito o que procurar.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1809&quot;&gt;A coisa é que esse comando é muito poderoso! Ele respeita uma variável chamada &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;path&lt;/code&gt; que indica todos os diretórios que VIM deveria utilizar pra buscar seus arquivos.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1976&quot;&gt;Para forçar o VIM a busca recursivamente seus arquivos você pode adicionar o caminho &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;**&lt;/code&gt; à variável &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;path&lt;/code&gt;, assim:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;1976&quot;&gt;:set path+=**&lt;/pre&gt;
&lt;p&gt;Note que &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;+=&lt;/code&gt; aqui significa “adicione ao conteúdo da variável” e &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;**&lt;/code&gt; é valor que estamos adicionando. Agora podemos fazer buscas recursivas:&lt;/p&gt;
&lt;pre&gt;:find cpu.c&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;2256&quot;&gt;O comando acima vai encontrar o arquivo &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;src/cpu.c&lt;/code&gt; sem muita dificuldade!&lt;/p&gt;
&lt;div class=&quot;rich-media-item mediaSingleView-content-wrap image-center css-1mzi1es&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div class=&quot;css-1jgvy8y&quot;&gt;
&lt;div data-context-id=&quot;62816257&quot; data-type=&quot;file&quot; data-node-type=&quot;media&quot; data-width=&quot;2880&quot; data-height=&quot;1800&quot; data-id=&quot;2ae90d55-3573-4427-8c91-7e5951ce86c2&quot; data-collection=&quot;contentId-62816257&quot; data-file-name=&quot;find-cpu-c-recursivo.gif&quot; data-file-size=&quot;15791458&quot; data-file-mime-type=&quot;image/gif&quot; data-alt=&quot;&quot;&gt;
&lt;div class=&quot;new-file-experience-wrapper sc-gqPbQI jpDTvf&quot; data-testid=&quot;media-card-view&quot;&gt;
&lt;p&gt;&lt;img class=&quot;post__image&quot; src=&quot;/media/posts/49/find-cpu-c-recursivo-2.gif&quot; alt=&quot;&quot; width=&quot;2880&quot; height=&quot;1800&quot;&gt;&lt;/p&gt;
&lt;h2 class=&quot;p1&quot;&gt;Visualizar opções&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;2352&quot;&gt;As vezes os arquivos podem ter nomes parecidos e isso gera uma certa ambiguidade que o mecanismo de busca &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;find&lt;/code&gt; não consegue resolver sozinho. Por exemplo, nós temos os arquivos &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;src/cpu.c&lt;/code&gt;, &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;src/cpu.h&lt;/code&gt;, &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;src/cpu.test.c&lt;/code&gt; e &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;build/cpu.o&lt;/code&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2582&quot;&gt;Uma forma muito bacana de resolver essa ambiguidade é habilitar o &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;wildmenu&lt;/code&gt; que vai te mostrar opções sempre que não conseguir encontrar um único resultado para a sua busca.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2756&quot;&gt;Para ativar rode o seguinte comando:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;2756&quot;&gt;:set wildmenu&lt;/pre&gt;
&lt;p&gt;Pronto! Agora se você procurar por &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;cpu&lt;/code&gt; e pressionar TAB um novo menu deverá aparecer pra ti com diferentes opções para o mesmo arquivo como na imagem a seguir:&lt;/p&gt;
&lt;p&gt;&lt;img class=&quot;post__image&quot; src=&quot;/media/posts/49/find-cpu-wildmenu-2.gif&quot; alt=&quot;&quot; width=&quot;2880&quot; height=&quot;1800&quot;&gt;&lt;/p&gt;
&lt;h2 class=&quot;p1&quot;&gt;Conclusão e vídeo de apoio&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;3001&quot;&gt;Tá aí na mão mais uma dica massa pra tu que quer entender melhor como funciona e como aumentar sua produtividade com o VIM.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3126&quot;&gt;Caso tenha dúvidas sobre como isso funciona, eu fiz esse pequeno vídeo de apoio aqui pra te ajudar a entender:&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3126&quot;&gt;&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/HjP8lburwTA&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;allowfullscreen&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3126&quot;&gt;Não esquece de compartilhar este artigo nas suas redes sociais que ajuda muito a gente. Te vejo na próxima!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</content:encoded><category>produtividade</category><category>tecnica</category><category>vim</category></item><item><title>Devlog #02: Emulador NES, emulação da CPU 6502 – parte 1</title><link>https://codamos.com.br/devlog-emulador-nes-emulacao-da-cpu-6502-parte-1/</link><guid isPermaLink="true">https://codamos.com.br/devlog-emulador-nes-emulacao-da-cpu-6502-parte-1/</guid><description>Este artigo é uma continuação da série “Emulador NES” que vai te mostrar e implementar contigo um emulador NES totalmente funcional utilizando a linguagem C e a biblioteca Raylib . Clique aqui para le</description><pubDate>Mon, 22 Aug 2022 09:06:04 GMT</pubDate><content:encoded>&lt;p class=&quot;msg msg--info&quot;&gt;Este artigo é uma continuação da série “Emulador NES” que vai te mostrar e implementar contigo um emulador NES totalmente funcional utilizando a &lt;a href=&quot;/tema/c/&quot; title=&quot;https://codamos.com.br/tema/c/&quot;&gt;linguagem C&lt;/a&gt; e a biblioteca &lt;a href=&quot;http://raylib.com/&quot; title=&quot;http://raylib.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Raylib&lt;/a&gt;. &lt;em data-renderer-mark=&quot;true&quot;&gt;&lt;a href=&quot;/devlog-emulador-nes-github-e-build-simples-com-github-actions/&quot;&gt;Clique aqui&lt;/a&gt;&lt;/em&gt; para ler o artigo anterior, ou &lt;em data-renderer-mark=&quot;true&quot;&gt;&lt;a href=&quot;/devlog-emulador-nes-arquitetura/&quot;&gt;clique aqui&lt;/a&gt;&lt;/em&gt; para ler o primeiro artigo e acompanhar desde o começo!&lt;/p&gt;
&lt;h2 class=&quot;p1&quot;&gt;No artigo anterior&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;646&quot;&gt;Nós já fizemos uma &lt;a href=&quot;/devlog-emulador-nes-arquitetura/&quot;&gt;visão geral dos componentes que o emulador precisa pra operar como um sistema NES&lt;/a&gt;: cpu, barramento, ppu, apu, etc.. E no artigo anterior nós também preparamos o &lt;a href=&quot;/devlog-emulador-nes-github-e-build-simples-com-github-actions/&quot;&gt;ambiente de CI para que rode os testes a cada nova adição&lt;/a&gt; que fizermos ao nosso projeto usando o Github Actions.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;940&quot;&gt;Hoje nós vamos começar uma das partes mais empolgantes do projeto: a emulação da CPU 6502 – o processador do nintendinho. Para isso vamos escrever duas interfaces essenciais do emulador: a CPU e o barramento de memória.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1160&quot;&gt;Para cada uma destas interfaces eu fiz um vídeo separado mostrando a implementação do que tá escrito no arquivo pra todo mundo poder acompanhar. Vem comigo!&lt;/p&gt;
&lt;h2 class=&quot;p1&quot;&gt;Emulação do barramento de memória&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;1353&quot;&gt;Antes de mexer em qualquer coisa relacionada ao processador, nós precisamos preparar uma forma de permitir que o processador – e mais tarde outros componentes também – tenham acesso à memória RAM.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1551&quot;&gt;Esta parte do trabalho é relativamente simples, porque só envolve criar uma interface para ler e escrever num espaço de memória, que nós vamos implementar com um &lt;em data-renderer-mark=&quot;true&quot;&gt;array&lt;/em&gt;.&lt;/p&gt;
&lt;h3 class=&quot;p1&quot;&gt;Propriedades de um barramento de memória&lt;/h3&gt;
&lt;p data-renderer-start-pos=&quot;1763&quot;&gt;O barramento de memória é uma interface bem simples para ler e escrever da memória. Estas são as duas operações que a gente precisa implementar hoje!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1914&quot;&gt;O que é importante notar é que a CPU 6502 tem uma capacidade de endereçamento de apenas 16 bits (2 bytes). Portanto a CPU só consegue ler do barramento os endereços de memória entre &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;0x0000&lt;/code&gt; e &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;0xFFFF&lt;/code&gt;, totalizando 65535 bytes (~64 kilobytes) de memória RAM.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2170&quot;&gt;Em termos práticos significa dizer que não importa se o &lt;em data-renderer-mark=&quot;true&quot;&gt;hardware&lt;/em&gt; tiver mais que 64kb de RAM, a CPU não vai conseguir utilizar este espaço extra de memória.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2327&quot;&gt;Para emular o barramento e a memória RAM portanto, não precisamos de nada mais do que um &lt;em data-renderer-mark=&quot;true&quot;&gt;array&lt;/em&gt; de 64 kb como no exemplo abaixo:&lt;/p&gt;
&lt;div class=&quot;code-block  css-iwznuw&quot;&gt;
&lt;pre class=&quot;p1&quot;&gt;// Declara um array chamado &apos;bus&apos; de 64 KB (65536 bytes, endereços 0x0000–0xFFFF)&lt;br&gt;uint8_t bus[0x10000];&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;2537&quot;&gt;E tudo o que precisamos escrever para emular o barramento de memória são duas funções para que possamos &lt;em data-renderer-mark=&quot;true&quot;&gt;ler&lt;/em&gt; e &lt;em data-renderer-mark=&quot;true&quot;&gt;escrever&lt;/em&gt; da memória. Algo assim:&lt;/p&gt;
&lt;pre class=&quot;p1&quot;&gt;uint8_t bus_read(uint16_t address);&lt;br&gt;void bus_write(uint16_t address, uint8_t value);&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;2767&quot;&gt;A interface acima está relativamente incompleta, mas já deve te dar uma ideia de como o programa deverá ficar.&lt;/p&gt;
&lt;div class=&quot;ak-editor-panel css-d4tzhg&quot; data-panel-type=&quot;info&quot;&gt;
&lt;div class=&quot;ak-editor-panel__content&quot;&gt;
&lt;p class=&quot;msg msg--info&quot; data-renderer-start-pos=&quot;2880&quot;&gt;Dê uma olhada no vídeo de apoio caso queira acompanhar a implementação final, ou implemente os testes abaixo caso queira escrever comigo!&lt;/p&gt;
&lt;h3 data-renderer-start-pos=&quot;2880&quot;&gt;Vídeo de apoio&lt;/h3&gt;
&lt;p&gt;&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/KX-1lDO9WNg&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;allowfullscreen&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;h3 class=&quot;p1&quot;&gt;Testes para o barramento de memória&lt;/h3&gt;
&lt;pre&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;test_bus_read&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;br&gt;&lt;/span&gt;{&lt;br&gt;&lt;span class=&quot;token comment&quot;&gt;    // Given the memory address &apos;0x0600&apos; has the value &apos;0xA9&apos;&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;    // When I call &apos;bus_read()&apos; with the address &apos;0x0600&apos;&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;    // Then I should get the value &apos;0xA9&apos;&lt;/span&gt;&lt;br&gt;}&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;test_bus_write&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;br&gt;&lt;/span&gt;{&lt;br&gt;     &lt;span class=&quot;token comment&quot;&gt;// Given the memory bus contains only zeroes&lt;br&gt;     // When I call &apos;bus_write()&apos; with the address &apos;0x0600&apos; and value &apos;0xA9&apos;&lt;br&gt;     // Then the byte &apos;0x0600&apos; should contain the value &apos;0xA9&apos;&lt;/span&gt;&lt;br&gt;}&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;3472&quot;&gt;Ao fazer o teste acima passar, estamos prontes para a próxima etapa: emular a CPU!&lt;/p&gt;
&lt;div class=&quot;ak-editor-panel css-431guk&quot; data-panel-type=&quot;custom&quot; data-panel-color=&quot;#E3FCEF&quot; data-panel-icon=&quot;:info:&quot; data-panel-icon-id=&quot;atlassian-info&quot;&gt;
&lt;div class=&quot;ak-editor-panel__content&quot;&gt;
&lt;p class=&quot;msg msg--success&quot; data-renderer-start-pos=&quot;3557&quot;&gt;A implementação completa você encontra no vídeo de apoio e também neste &lt;a href=&quot;https://github.com/codamos-com-br/qmario/pull/3&quot; title=&quot;https://github.com/codamos-com-br/qmario/pull/3&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Pull Request aqui&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 class=&quot;p1&quot;&gt;Emulação da CPU 6502&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;3672&quot;&gt;O coração do nosso emulador é a unidade central de processamento, a CPU. Este é o componente que vai nos permitir ler programas presentes no barramento de memória e executar lógica. Na maioria dos casos, os bugs que vamos encontrar no emulador vão morar neste componente também!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3952&quot;&gt;Apesar de ser tão fundamental, o processador tem um funcionamento muito simples: ele fica rodando infinitamente (ou até ser encerrado) e a cada iteração (ciclo) o processador tenta identificar qual a próxima instrução que ele deveria executar a partir do barramento de memória.&lt;/p&gt;
&lt;h3 class=&quot;p1&quot;&gt;Características da CPU 6502&lt;/h3&gt;
&lt;p data-renderer-start-pos=&quot;4260&quot;&gt;O processador 6502 tem 3 registradores chamados de A (acumulador), X e Y – todos eles de apenas 1 byte. Além disso, ele possui um ponteiro de pilha (&lt;em data-renderer-mark=&quot;true&quot;&gt;stack pointer&lt;/em&gt;) que também tem 1 byte, um registrador de &lt;em data-renderer-mark=&quot;true&quot;&gt;status&lt;/em&gt; da CPU de 1 byte e um ponteiro de instrução (&lt;em data-renderer-mark=&quot;true&quot;&gt;instruction pointer&lt;/em&gt; ou &lt;em data-renderer-mark=&quot;true&quot;&gt;program counter&lt;/em&gt;) que possui 2 bytes.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;4578&quot;&gt;A representação disso em uma &lt;em data-renderer-mark=&quot;true&quot;&gt;struct&lt;/em&gt; C é mais ou menos a seguinte:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;4578&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Cpu&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;br&gt; &lt;span class=&quot;token keyword&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;&quot;&gt; a&lt;/span&gt;; &lt;span class=&quot;token comment&quot;&gt;// acumulador&lt;/span&gt;&lt;br&gt; &lt;span class=&quot;token keyword&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;&quot;&gt; x&lt;/span&gt;;&lt;br&gt; &lt;span class=&quot;token keyword&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;&quot;&gt; y&lt;/span&gt;;&lt;br&gt; &lt;span class=&quot;token keyword&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;&quot;&gt; sp&lt;/span&gt;; &lt;span class=&quot;token comment&quot;&gt;// stack pointer&lt;/span&gt;&lt;br&gt; &lt;span class=&quot;token keyword&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;&quot;&gt; st&lt;/span&gt;; &lt;span class=&quot;token comment&quot;&gt;// status register&lt;/span&gt;&lt;br&gt; &lt;span class=&quot;token keyword&quot;&gt;uint16_t&lt;/span&gt;&lt;span class=&quot;&quot;&gt; pc&lt;/span&gt;; &lt;span class=&quot;token comment&quot;&gt;// program counter&lt;/span&gt;&lt;br&gt;};&lt;/span&gt;&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;4813&quot;&gt;Note que o ponteiro de instrução possui 16 bits, ou 2 bytes, que é justamente o tamanho do nosso barramento. Portanto este é o único ponteiro que consegue armazenar o endereço completo de qualquer parte da memória do barramento.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;5043&quot;&gt;Cada instrução do processador é descrita com apenas um byte – elas são armazenadas na memória assim. Por exemplo, a instrução &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;LDA #$00&lt;/code&gt; que significa “&lt;em data-renderer-mark=&quot;true&quot;&gt;carregar o valor &lt;/em&gt;&lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;0x00&lt;/code&gt; &lt;em data-renderer-mark=&quot;true&quot;&gt;no registrador A”&lt;/em&gt; fica descrita assim no barramento de memória: &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;0xA9 0x00&lt;/code&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;5291&quot;&gt;Exatamente esta instrução &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;LDA #$00&lt;/code&gt; pode ser representada no nosso barramento de memória assim:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;5291&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Cpu&lt;/span&gt;&lt;span class=&quot;&quot;&gt; cpu &lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;comment linenumber react-syntax-highlighter-line-number&quot;&gt;&lt;br&gt;&lt;span class=&quot;token comment&quot;&gt;// aponta para o endereço 0x0600 da memória&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;&quot;&gt;cpu&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;&quot;&gt;pc &lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x0600&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;&quot;&gt; bus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0xFFFF&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token function&quot;&gt;bus_write&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0x0600&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0xA9&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// LDA&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token function&quot;&gt;bus_write&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0x0601&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 0x00&lt;/span&gt;&lt;br&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;5560&quot;&gt;De forma que quando a CPU rodar irá encontrar a instrução &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;0xA9&lt;/code&gt; já que seu ponteiro de instrução (pc) aponta para o endereço &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;0x0600&lt;/code&gt;, onde existe o byte &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;0xA9&lt;/code&gt;. Esta instrução exige que o processador busque um segundo parâmetro gravado em sequência, no endereço &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;0x0601&lt;/code&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;5827&quot;&gt;As instruções do processador – também chamadas de &lt;em data-renderer-mark=&quot;true&quot;&gt;OpCode&lt;/em&gt; – podem obrigar diferentes números de parâmetros e diferentes formas de acessar a memória. Para você ter uma ideia, veja o exemplo da instrução LDA:&lt;/p&gt;
&lt;div class=&quot;pm-table-container with-shadow-observer&quot; data-layout=&quot;default&quot;&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 259.031px;&quot; border=&quot;1&quot;&gt;&lt;caption&gt;
&lt;p data-renderer-start-pos=&quot;6378&quot;&gt;Instrução: LDA – carregar para o acumulador (cpu.a)&lt;/p&gt;
&lt;/caption&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Instrução em assembly&lt;/th&gt;
&lt;th&gt;Representação na memória&lt;/th&gt;
&lt;th&gt;Significado&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 50.3594px;&quot;&gt;
&lt;td style=&quot;width: 33.2382%; height: 50.3594px;&quot;&gt;LDA #$00&lt;/td&gt;
&lt;td style=&quot;width: 33.3809%; height: 50.3594px;&quot;&gt;&lt;code&gt;0xA9 0x00&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3809%;&quot; data-colwidth=&quot;226.67&quot;&gt;
&lt;p data-renderer-start-pos=&quot;6132&quot;&gt;Imediato – carregar o próximo byte para o registrador&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 79.1562px;&quot;&gt;
&lt;td style=&quot;width: 33.2382%; height: 79.1562px;&quot;&gt;
&lt;p&gt;LDA $00&lt;/p&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 33.3809%; height: 79.1562px;&quot;&gt;&lt;code&gt;0xA5 0x00&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3809%;&quot; data-colwidth=&quot;226.67&quot;&gt;
&lt;p data-renderer-start-pos=&quot;6215&quot;&gt;Zero Page – carregar 1 byte da memória RAM para o registrador&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 50.3594px;&quot;&gt;
&lt;td style=&quot;width: 33.2382%; height: 50.3594px;&quot;&gt;LDA $ff00&lt;/td&gt;
&lt;td style=&quot;width: 33.3809%; height: 50.3594px;&quot;&gt;&lt;code&gt;0xAD 0x00 0xFF&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3809%;&quot; data-colwidth=&quot;226.67&quot;&gt;
&lt;p data-renderer-start-pos=&quot;6313&quot;&gt;Absoluto – carregar 1 byte da memória RAM para o registrador&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-renderer-start-pos=&quot;6431&quot;&gt;A CPU possui outras formas de endereçamento que eu não citei na tabela acima, mas que nós vamos trabalhar nos próximos artigos.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;6560&quot;&gt;Para facilitar o entendimento de dar alguma praticidade pro texto, eu montei mais um vídeo de apoio implementando o comecinho da nossa CPU.&lt;/p&gt;
&lt;h3 data-renderer-start-pos=&quot;6560&quot;&gt;Vídeo de apoio&lt;/h3&gt;
&lt;p&gt; &lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/ZtSpIonr8TE&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;allowfullscreen&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;h3 class=&quot;p1&quot;&gt;Testes para a instrução LDA da CPU 6502&lt;/h3&gt;
&lt;pre&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;test_cpu_reset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;comment linenumber react-syntax-highlighter-line-number&quot;&gt;&lt;br&gt;&lt;/span&gt;{&lt;br&gt;  // Given a CPU in any state&lt;br&gt;  // When I call &apos;cpu_reset()&apos;&lt;br&gt;  // Then the registers A, X and Y should be &apos;0&apos;&lt;br&gt;  // And the stack pointer should be &apos;0x30&apos;&lt;br&gt;  // And the program counter should point to &apos;0x0600&apos;&lt;br&gt;}&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;test_cpu_tick_lda&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;br&gt;&lt;/span&gt;{&lt;br&gt;  // Given the program &apos;0xA9 0xAA&apos; in the address &apos;0x0600&apos;&lt;br&gt;  // And the program counter (pc) points to the address &apos;0x0600&apos;&lt;br&gt;  // When the cpu executes 1 OpCode&lt;br&gt;  // Then the program counter (pc) should be &apos;0x0602&apos;&lt;br&gt;  // And the A register should be &apos;0xAA&apos;&lt;br&gt;  // And the number of elapsed cycles should be &apos;2&apos;&lt;br&gt;}&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;7385&quot;&gt;Ao fazer os testes acima passar nós alcançamos uma etapa importantíssima do nosso desenvolvimento: estabilidade para trabalhar os próximos &lt;em data-renderer-mark=&quot;true&quot;&gt;opcodes&lt;/em&gt;.&lt;/p&gt;
&lt;div class=&quot;ak-editor-panel css-431guk&quot; data-panel-type=&quot;custom&quot; data-panel-color=&quot;#E3FCEF&quot; data-panel-icon=&quot;:info:&quot; data-panel-icon-id=&quot;atlassian-info&quot;&gt;
&lt;div class=&quot;ak-editor-panel__content&quot;&gt;
&lt;p class=&quot;msg msg--success&quot; data-renderer-start-pos=&quot;7535&quot;&gt;A implementação completa você encontra no vídeo de apoio e também neste &lt;a href=&quot;https://github.com/codamos-com-br/qmario/pull/4&quot; title=&quot;https://github.com/codamos-com-br/qmario/pull/4&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Pull Request aqui&lt;/a&gt;.&lt;/p&gt;
&lt;h2 class=&quot;p1&quot;&gt;Próximos passos&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;7645&quot;&gt;Nós alcançamos um momento importantíssimo do nosso desenvolvimento! Temos um &lt;a href=&quot;https://github.com/codamos-com-br/qmario/pull/4&quot; title=&quot;https://github.com/codamos-com-br/qmario/pull/4&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;pull request&lt;/a&gt; aberto que nos permite enviar alterações continuamente e que irá ativar a nossa &lt;em data-renderer-mark=&quot;true&quot;&gt;CI&lt;/em&gt; caso algo dê errado. Além disso temos uma forma organizada de escrever testes e manter um ritmo de trabalho em que apenas avançamos em vez de criar bugs difíceis de encontrar.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;7995&quot;&gt;No próximo artigo eu pretendo cobrir a instrução &lt;code class=&quot;code css-1xivnph&quot; data-renderer-mark=&quot;true&quot;&gt;STA&lt;/code&gt; (gravar do acumulador para a memória) de forma que com essas duas instruções (LDA e STA) teremos contemplado todos os tipos de endereçamento da memória e poderemos começar a implementar a CPU de forma acelerada utilizando um caso de teste pronto: o &lt;em data-renderer-mark=&quot;true&quot;&gt;nestest&lt;/em&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;8307&quot;&gt;Portanto na próxima nós vamos ver melhor os endereçamentos de memória e vamos carregar para a memória a ROM &lt;em data-renderer-mark=&quot;true&quot;&gt;nestest&lt;/em&gt; que vai nos permitir caminhar muito mais rapidamente na implementação da nossa CPU!&lt;/p&gt;
&lt;div class=&quot;ak-editor-panel css-1ov4ty1&quot; data-panel-type=&quot;custom&quot; data-panel-color=&quot;#FFEBE6&quot; data-panel-icon=&quot;:info:&quot; data-panel-icon-id=&quot;atlassian-info&quot;&gt;
&lt;div class=&quot;ak-editor-panel__icon&quot;&gt; &lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</content:encoded><category>c</category><category>devlog</category><category>emulador-nes</category></item><item><title>Devlog #01: Emulador NES, Github e build simples com Github Actions</title><link>https://codamos.com.br/devlog-emulador-nes-github-e-build-simples-com-github-actions/</link><guid isPermaLink="true">https://codamos.com.br/devlog-emulador-nes-github-e-build-simples-com-github-actions/</guid><description>Este artigo é uma continuação da série “Emulador NES” que vai te mostrar e implementar contigo um emulador NES totalmente funcional utilizando a linguagem C e a biblioteca Raylib . Clique aqui para le</description><pubDate>Tue, 09 Aug 2022 10:51:00 GMT</pubDate><content:encoded>&lt;div class=&quot;ak-editor-panel css-1xdhyk6&quot; data-panel-type=&quot;info&quot;&gt;
&lt;div class=&quot;ak-editor-panel__content&quot;&gt;
&lt;p data-renderer-start-pos=&quot;248&quot;&gt; &lt;/p&gt;
&lt;p class=&quot;msg msg--info&quot; data-renderer-start-pos=&quot;248&quot;&gt;Este artigo é uma continuação da série &lt;a href=&quot;/tema/emulador-nes/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;“Emulador NES”&lt;/a&gt; que vai te mostrar e implementar contigo um emulador NES totalmente funcional utilizando a &lt;a href=&quot;/tema/c/&quot; title=&quot;https://codamos.com.br/tema/c/&quot;&gt;linguagem C&lt;/a&gt; e a biblioteca &lt;a href=&quot;/jogos-em-php/&quot; title=&quot;http://raylib.com&quot;&gt;Raylib&lt;/a&gt;. &lt;a href=&quot;/devlog-emulador-nes-arquitetura/&quot; title=&quot;https://codamos.com.br/devlog-emulador-nes-arquitetura&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Clique aqui&lt;/a&gt; para ler o artigo anterior.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;248&quot;&gt;O resultado do trabalho deste artigo você consegue conferir no primeiro Pull Request do projeto: &lt;a href=&quot;https://github.com/codamos-com-br/qmario/pull/1&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;https://github.com/codamos-com-br/qmario/pull/1&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;No artigo anterior&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;490&quot;&gt;Nós já tivemos uma visão geral da arquitetura do NES e quais componentes vamos precisar emular.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;587&quot;&gt;Agora é hora de botar a mão na massa! Hoje nós vamos criar uma suíte de integração contínua que vai nos permitir compilar e rodar testes, para que possamos detectar com facilidade se algum erro aconteceu e quando.&lt;/p&gt;
&lt;h2 data-renderer-start-pos=&quot;587&quot;&gt;Vídeo de apoio&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;1174&quot;&gt;Tem muita coisa acontecendo ao mesmo tempo neste artigo e, apesar de eu ter tentado deixar ele organizadinho, algumas coisas ainda podem ter ficado confusas.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1333&quot;&gt;Eu gravei um vídeo mostrando a implementação passo a passo de tudo o que vamos falar aqui, talvez assim fique um pouco mais fácil de acompanhar o processo que, como um todo, é bem complicadinho.&lt;/p&gt;
&lt;div class=&quot;ak-editor-panel css-1i4jwoe&quot; data-panel-type=&quot;custom&quot; data-panel-color=&quot;#FFEBE6&quot; data-panel-icon=&quot;:info:&quot; data-panel-icon-id=&quot;atlassian-info&quot;&gt;
&lt;div class=&quot;ak-editor-panel__content&quot;&gt;&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/cqtyu36s9Mg&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;allowfullscreen&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;div&gt;
&lt;h2 class=&quot;p1&quot;&gt;Criar e clonar um novo repositório no Github&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;1579&quot;&gt;O meu primeiro passo aqui é criar um repositório no Github. Isso vai me ajudar a guardar os arquivos e versionar tudo, mas também vai permitir que você dê uma olhada no código e envie algumas correções, faça perguntas pontuais e por aí vai…&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1821&quot;&gt;Na página do seu perfil ou organização, clique em “Repositories” e encontre o botão “New repository”:&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/47/Screenshot-2022-07-05-at-15.23.49.png&quot; alt=&quot;Clique no botão “New repository” para criar um novo repositório no Github.&quot; width=&quot;2038&quot; height=&quot;338&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;rich-media-item mediaSingleView-content-wrap image-center css-1mzi1es&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div class=&quot;css-3vtcul&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;1926&quot;&gt;Clique no botão “New repository” para criar um novo repositório no Github.&lt;/div&gt;
&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Daí basta colocar as informações básicas sobre o projeto. Eu vou chamar este emulador de “qmario” (🤭) e você pode acessar a partir deste link aqui: &lt;a href=&quot;https://github.com/codamos-com-br/qmario&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;https://github.com/codamos-com-br/qmario&lt;/a&gt;.&lt;a href=&quot;https://github.com/codamos-com-br/qmario&quot; role=&quot;button&quot; data-testid=&quot;inline-card-resolved-view&quot; class=&quot;css-1xdzogm eeajecn0&quot; tabindex=&quot;0&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/47/Screenshot-2022-07-05-at-15.24.40.png&quot; alt=&quot;Adicionamos informações básicas: nome, licença e visibilidade do projeto.&quot; width=&quot;1444&quot; height=&quot;1470&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;rich-media-item mediaSingleView-content-wrap image-center css-1mzi1es&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div class=&quot;css-3vtcul&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;2159&quot;&gt;Adicionamos informações básicas: nome, licença e visibilidade do projeto.&lt;/div&gt;
&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;2235&quot;&gt;Agora basta visitar a página principal do repositório, clicar no botão primário “Code” para então escolher a aba “SSH” e copiar a URL que o Github nos oferece na caixa de texto.&lt;/p&gt;
&lt;div class=&quot;rich-media-item mediaSingleView-content-wrap image-center css-1m91hgv&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div class=&quot;css-h8xvby&quot;&gt;
&lt;div data-context-id=&quot;55640065&quot; data-type=&quot;file&quot; data-node-type=&quot;media&quot; data-width=&quot;420&quot; data-height=&quot;349&quot; data-id=&quot;6ef623fb-0e9f-4f8f-b28e-8f87bc305999&quot; data-collection=&quot;contentId-55640065&quot; data-file-name=&quot;Screenshot 2022-07-05 at 15.25.24.png&quot; data-file-size=&quot;96710&quot; data-file-mime-type=&quot;image/png&quot; data-alt=&quot;&quot;&gt;
&lt;div class=&quot;media-card-viewport-anchor&quot;&gt; &lt;/div&gt;
&lt;div class=&quot;new-file-experience-wrapper sc-rBLzX jUmVel&quot; data-testid=&quot;media-card-view&quot;&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/47/Screenshot-2022-07-05-at-15.25.24.png&quot; alt=&quot;Na página do repositório, clique em “Code”, na aba “SSH” e em seguida no ícone de cópia para obter o endereço do seu repositório.&quot; width=&quot;840&quot; height=&quot;698&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;rich-media-item mediaSingleView-content-wrap image-center css-1m91hgv&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div class=&quot;css-3vtcul&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;2416&quot;&gt;Na página do repositório, clique em “Code”, na aba “SSH” e em seguida no ícone de cópia para obter o endereço do seu repositório.&lt;/div&gt;
&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;2548&quot;&gt;Com esta URL eu posso clonar o repositório pro meu computador utilizando o seguinte comando:&lt;/p&gt;
&lt;pre class=&quot;p1&quot;&gt;$ git clone git@github.com:codamos-com-br/qmario.git&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;2696&quot;&gt;Ao entrar na pasta que acabei de clonar, posso listar todos os arquivos. Como é um repositório novo, apenas &lt;code&gt;.git&lt;/code&gt; e &lt;code&gt;LICENSE&lt;/code&gt; deverão existir:&lt;/p&gt;
&lt;div class=&quot;rich-media-item mediaSingleView-content-wrap image-center css-1mzi1es&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div class=&quot;css-1yki34k&quot;&gt;
&lt;div data-context-id=&quot;55640065&quot; data-type=&quot;file&quot; data-node-type=&quot;media&quot; data-width=&quot;693&quot; data-height=&quot;216&quot; data-id=&quot;83712603-6043-4284-8dec-1ef26e130029&quot; data-collection=&quot;contentId-55640065&quot; data-file-name=&quot;Screenshot 2022-07-05 at 15.30.17.png&quot; data-file-size=&quot;87859&quot; data-file-mime-type=&quot;image/png&quot; data-alt=&quot;&quot;&gt;
&lt;div class=&quot;new-file-experience-wrapper sc-rBLzX dzqoyV&quot; data-testid=&quot;media-card-view&quot;&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/47/Screenshot-2022-07-05-at-15.30.17.png&quot; alt=&quot;Após clonar o projeto, entre na pasta e os seguintes arquivos deverão aparecer: .git e LICENSE.&quot; width=&quot;1386&quot; height=&quot;432&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;rich-media-item mediaSingleView-content-wrap image-center css-1mzi1es&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div class=&quot;css-3vtcul&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;2839&quot;&gt;Após clonar o projeto, entre na pasta e os seguintes arquivos deverão aparecer: &lt;em data-renderer-mark=&quot;true&quot;&gt;.git&lt;/em&gt; e &lt;em data-renderer-mark=&quot;true&quot;&gt;LICENSE&lt;/em&gt;.&lt;/div&gt;
&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p class=&quot;p1&quot;&gt;Caso não saiba como mexer com Github ou subir arquivos lá, o João escreveu um post incrível com um passo a passo muito bem feito sobre &lt;a href=&quot;/subindo-arquivos-no-github/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;como subir arquivos para um projeto no Github&lt;/a&gt;.&lt;/p&gt;
&lt;h2 class=&quot;p1&quot;&gt;Integração contínua com Github Actions: qualidade garantida desde o início&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;3052&quot;&gt;O primeiro passo essencial ao criar qualquer projeto, é configurar uma suíte de integração contínua. Desta forma a gente garante desde o dia 1 do projeto que está pronto para se construído e entregue a qualquer computador.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3276&quot;&gt;No &lt;em data-renderer-mark=&quot;true&quot;&gt;Github&lt;/em&gt; podemos utilizar workflows do &lt;em data-renderer-mark=&quot;true&quot;&gt;Github Actions&lt;/em&gt; para integração contínua.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3358&quot;&gt;Antes de tudo, vamos criar um branch novo para receber nossas alterações. Vou chamar este branch de &lt;code&gt;ci_workflow&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;p1&quot;&gt;$ git checkout -b ci_workflow&lt;/pre&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/47/Screenshot-2022-07-05-at-15.35.36.png&quot; alt=&quot;Novo branch&quot; width=&quot;1224&quot; height=&quot;186&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;rich-media-item mediaSingleView-content-wrap image-center css-1c4nuzo&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div class=&quot;css-3vtcul&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;3505&quot;&gt;Novo branch&lt;/div&gt;
&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;3519&quot;&gt;Agora podemos começar a montar a nossa pipeline de integração contínua. Vamos criar um arquivo chamado &lt;code&gt;.github/workflows/ci.yaml&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;p1&quot;&gt;$ mkdir -p .github/workflows&lt;br&gt;$ vim .github/workflows/ci.yaml&lt;/pre&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/47/Screenshot-2022-07-05-at-15.36.08.png&quot; alt=&quot;Criando arquivo ci.yaml&quot; width=&quot;1552&quot; height=&quot;224&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;rich-media-item mediaSingleView-content-wrap image-center css-1mzi1es&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div class=&quot;css-3vtcul&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;3714&quot;&gt;Criando arquivo ci.yaml&lt;/div&gt;
&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p class=&quot;p1&quot;&gt;Para criar e editar o arquivo eu utilizei o editor VIM, mas você pode usar qualquer outro editor de sua preferência. Para saber sobre VIM, dê uma olhada &lt;a href=&quot;/vim-basico/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;neste artigo que escrevi sobre como começar com VIM.&lt;/a&gt;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3950&quot;&gt;Agora vamos dar o seguinte conteúdo ao arquivo &lt;code&gt;ci.yaml&lt;/code&gt;:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;3950&quot;&gt;# .github/workflows/ci.yaml&lt;br&gt;name: CI&lt;br&gt;on:&lt;br&gt;    push:&lt;br&gt;        branches: [ &quot;main&quot; ]&lt;br&gt;    pull_request:&lt;br&gt;        branches: [ &quot;main&quot; ]&lt;br&gt;jobs:&lt;br&gt;    build:&lt;br&gt;        runs-on: ubuntu-latest&lt;br&gt;        steps:&lt;br&gt;            - uses: actions/checkout@v3&lt;br&gt;            - name: Fazer build e rodar&lt;br&gt;              run: echo &apos;Olá github actions&apos;&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;4323&quot;&gt;Note que, de acordo com o conteúdo acima, a pipeline &lt;code&gt;build&lt;/code&gt; vai rodar sempre que fizermos um &lt;code&gt;push&lt;/code&gt; ou abrirmos um &lt;code&gt;pull_request&lt;/code&gt; que afete o branch &lt;em data-renderer-mark=&quot;true&quot;&gt;main&lt;/em&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;4480&quot;&gt;Vamos então fazer um commit e enviar nossas alterações:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;4480&quot;&gt;$ git add .github/.&lt;br&gt;$ git commit -m &quot;ci: adiciona workflow simples&quot;&lt;br&gt;$ git push origin ci_workflow&lt;/pre&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/47/Screenshot-2022-07-05-at-15.37.52.png&quot; alt=&quot;Adiciona .github/workflows/ci.yaml ao branch&quot; width=&quot;1700&quot; height=&quot;1226&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;rich-media-item mediaSingleView-content-wrap image-center css-1mzi1es&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div class=&quot;css-3vtcul&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;4638&quot;&gt;Adiciona &lt;code&gt;.github/workflows/ci.yaml&lt;/code&gt; ao branch&lt;/div&gt;
&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;4685&quot;&gt;Assim que o conteúdo for enviado ao &lt;em data-renderer-mark=&quot;true&quot;&gt;Github&lt;/em&gt;, a página do seu repositório deverá oferecer de criar um &lt;em data-renderer-mark=&quot;true&quot;&gt;Pull Request&lt;/em&gt;. Vamos aceitar a sugestão clicando em “Compare &amp;amp; pull request”:&lt;/p&gt;
&lt;div class=&quot;rich-media-item mediaSingleView-content-wrap image-center css-1mzi1es&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div class=&quot;css-1s46d4v&quot;&gt;
&lt;div data-context-id=&quot;55640065&quot; data-type=&quot;file&quot; data-node-type=&quot;media&quot; data-width=&quot;992&quot; data-height=&quot;438&quot; data-id=&quot;348de05b-78dc-4369-bb8f-4a9e466cfc05&quot; data-collection=&quot;contentId-55640065&quot; data-file-name=&quot;Screenshot 2022-07-05 at 15.37.18.png&quot; data-file-size=&quot;573722&quot; data-file-mime-type=&quot;image/png&quot; data-alt=&quot;&quot;&gt;
&lt;div class=&quot;new-file-experience-wrapper sc-rBLzX cdXNpg&quot; data-testid=&quot;media-card-view&quot;&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/47/Screenshot-2022-07-05-at-15.37.18.png&quot; alt=&quot;Branch criado, podemos criar um Pull Request e ver a pipeline funcionando.&quot; width=&quot;1984&quot; height=&quot;876&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;rich-media-item mediaSingleView-content-wrap image-center css-1mzi1es&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div class=&quot;css-3vtcul&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;4865&quot;&gt;Branch criado, podemos criar um Pull Request e ver a pipeline funcionando.&lt;/div&gt;
&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;4942&quot;&gt;Ao confirmar a criação do &lt;em data-renderer-mark=&quot;true&quot;&gt;Pull Request&lt;/em&gt;, note que o Github Actions imediatamente começa a executar a nossa pipeline:&lt;/p&gt;
&lt;div class=&quot;rich-media-item mediaSingleView-content-wrap image-center css-1wcl8ia&quot; data-layout=&quot;center&quot; data-width=&quot;100&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div class=&quot;css-1u6dl5u&quot;&gt;
&lt;div data-context-id=&quot;55640065&quot; data-type=&quot;file&quot; data-node-type=&quot;media&quot; data-width=&quot;1012&quot; data-height=&quot;625&quot; data-id=&quot;484bbaf6-a570-4e21-9230-57a5cd1f2d85&quot; data-collection=&quot;contentId-55640065&quot; data-file-name=&quot;Screenshot 2022-07-05 at 15.39.08.png&quot; data-file-size=&quot;942819&quot; data-file-mime-type=&quot;image/png&quot; data-alt=&quot;&quot;&gt;
&lt;div class=&quot;media-card-viewport-anchor&quot;&gt; &lt;/div&gt;
&lt;div class=&quot;new-file-experience-wrapper sc-rBLzX ieXUZc&quot; data-testid=&quot;media-card-view&quot;&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/47/Screenshot-2022-07-05-at-15.39.08.png&quot; alt=&quot;Ao criar o Pull Request, o workflow imediatamente começa a rodar.&quot; width=&quot;2024&quot; height=&quot;1250&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;rich-media-item mediaSingleView-content-wrap image-center css-1wcl8ia&quot; data-layout=&quot;center&quot; data-width=&quot;100&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div class=&quot;css-3vtcul&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;5061&quot;&gt;Ao criar o Pull Request, o workflow imediatamente começa a rodar.&lt;/div&gt;
&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;5129&quot;&gt;Caso os comandos desta pipeline tenham um código de saída igual a &lt;code&gt;0&lt;/code&gt; (zero), a pipeline ficará &lt;em data-renderer-mark=&quot;true&quot;&gt;verde&lt;/em&gt; indicando que está tudo em ordem. Caso algum código de saída seja diferente de 0, a pipeline ficará &lt;em data-renderer-mark=&quot;true&quot;&gt;vermelha&lt;/em&gt;, e nos dirá qual comando teve falha.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;5376&quot;&gt;Abaixo eu mostro detalhes de como fica a pipeline verde e expandindo o passo “Fazer build e rodar” para que vejamos a saída do nosso programa &lt;code&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;echo ‘Olá github actions’&lt;/em&gt;&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;rich-media-item mediaSingleView-content-wrap image-center css-1mzi1es&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div class=&quot;css-1cfzy1q&quot;&gt;
&lt;div data-context-id=&quot;55640065&quot; data-type=&quot;file&quot; data-node-type=&quot;media&quot; data-width=&quot;991&quot; data-height=&quot;525&quot; data-id=&quot;fc3b337a-86d9-4dc6-82b5-3c969ba48db6&quot; data-collection=&quot;contentId-55640065&quot; data-file-name=&quot;Screenshot 2022-07-05 at 15.39.22.png&quot; data-file-size=&quot;514895&quot; data-file-mime-type=&quot;image/png&quot; data-alt=&quot;&quot;&gt;
&lt;div class=&quot;new-file-experience-wrapper sc-rBLzX dplXEB&quot; data-testid=&quot;media-card-view&quot;&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/47/Screenshot-2022-07-05-at-15.39.22.png&quot; alt=&quot;O detalhamento daquele workflow mostra quais passos rodaram, e que o nosso passo executou e retornou com sucesso (exit 0).&quot; width=&quot;1982&quot; height=&quot;1050&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;rich-media-item mediaSingleView-content-wrap image-center css-1mzi1es&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div class=&quot;css-3vtcul&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;5550&quot;&gt;O detalhamento daquele workflow mostra quais passos rodaram, e que o nosso passo executou e retornou com sucesso (exit 0).&lt;/div&gt;
&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;5675&quot;&gt;Com este workflow simples em mãos, vamos começar a botar a mão na massa e escrever um pouco de C. Deixe o &lt;em data-renderer-mark=&quot;true&quot;&gt;Pull Request&lt;/em&gt; aberto, a gente ainda vai precisar dele!&lt;/p&gt;
&lt;h2 class=&quot;p1&quot;&gt;Olá mundo: compilando um programa simples em C&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;5884&quot;&gt;Na linguagem C, todo programa precisa ter uma função de entrada. Normalmente esta função se chama &lt;code&gt;main()&lt;/code&gt;. Vamos escrever um arquivo chamado &lt;code&gt;src/main.c&lt;/code&gt; com o seguinte conteúdo:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;5884&quot;&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br&gt;&lt;br&gt;int main(void)&lt;br&gt;{&lt;br&gt;  printf(&quot;Olá mundo&quot;);&lt;br&gt;  return 0;&lt;br&gt;}&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;6136&quot;&gt;O programa acima deverá escrever o texto “Olá mundo” na tela quando executado, e o seu código de saída (exit code) deverá ser &lt;code&gt;0&lt;/code&gt; (zero). Nós podemos verificar o código de saída do último comando executado através da variável &lt;code&gt;$?&lt;/code&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;6365&quot;&gt;Para compilar o programa acima, utilize o seguinte comando:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;6365&quot;&gt;$ clang src/main.c -o build/main.o -std=c99 -Wall&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;6477&quot;&gt;E o conjunto da obra deverá ficar mais ou menos assim:&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/47/Screenshot-2022-07-05-at-15.33.06.png&quot; alt=&quot;Compilação do programa main.c&quot; width=&quot;1678&quot; height=&quot;322&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;rich-media-item mediaSingleView-content-wrap image-center css-1mzi1es&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div class=&quot;css-3vtcul&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;6535&quot;&gt;Compilação do programa main.c&lt;/div&gt;
&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;6567&quot;&gt;O comando acima não apenas compilou o nosso arquivo &lt;em data-renderer-mark=&quot;true&quot;&gt;main.c&lt;/em&gt; mas também executou um processo chamado &lt;em data-renderer-mark=&quot;true&quot;&gt;Linkedição&lt;/em&gt;. Para facilitar a nossa vida no futuro, eu quero quebrar a compilação do nosso programa em duas partes: compilação e linkedição de objetos.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;6818&quot;&gt;Para isto, nós primeiro precisamos compilar os arquivos &lt;em data-renderer-mark=&quot;true&quot;&gt;.c&lt;/em&gt; utilizando a flag &lt;code&gt;-c&lt;/code&gt;. Depois coletamos todos os arquivos &lt;em data-renderer-mark=&quot;true&quot;&gt;.o&lt;/em&gt; e entregamos ao compilador para gerar um único executável, que aqui chamamos de “qmario”. Fica assim:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;6818&quot;&gt;$ clang -c src/main.c -o build/main.o -std=c99 -Wall&lt;br&gt;$ clang build/main.o -o build/qmario&lt;/pre&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/47/Screenshot-2022-07-05-at-15.34.36.png&quot; alt=&quot;Compilação em duas fases: linkedição acontece depois.&quot; width=&quot;1678&quot; height=&quot;714&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;rich-media-item mediaSingleView-content-wrap image-center css-1mzi1es&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div class=&quot;css-3vtcul&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;7133&quot;&gt;Compilação em duas fases: linkedição acontece depois.&lt;/div&gt;
&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 class=&quot;p1&quot;&gt;Criar um Makefile para o projeto&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;7223&quot;&gt;Vamos criar e editar alguns arquivos antes de mais nada. Como eu sei que no próximo post eu vou trabalhar a emulação da CPU, vamos já criar os arquivos da CPU: &lt;code&gt;cpu.h&lt;/code&gt; (cabeçalho, onde ficam as assinaturas de função), &lt;code&gt;cpu.c&lt;/code&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt; &lt;/em&gt;(implementações concretas) e &lt;code&gt;cpu.test.c&lt;/code&gt; (testes automatizados para as funções de CPU).&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;7533&quot;&gt;Dê os seguintes conteúdos para estes arquivos:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;7533&quot;&gt;// no arquivo cpu.h escreva o seguinte&lt;br&gt;&lt;br&gt;#ifndef _cpu_h_&lt;br&gt;#define _cpu_h_&lt;br&gt;&lt;br&gt;void cpu_reset(void);&lt;br&gt;&lt;br&gt;#endif&lt;br&gt;&lt;br&gt;// no arquivo cpu.c escreva o seguinte&lt;br&gt;#include &quot;cpu.h&quot;&lt;br&gt;&lt;br&gt;void cpu_reset(void)&lt;br&gt;{&lt;br&gt;}&lt;br&gt;&lt;br&gt;// no arquivo cpu.test.c escreva o seguinte&lt;br&gt;#include &quot;cpu.h&quot;&lt;br&gt;&lt;br&gt;int main(void)&lt;br&gt;{&lt;br&gt;    cpu_reset();&lt;br&gt;}&lt;br&gt;&lt;br&gt;// no arquivo main.c escreva o seguinte&lt;br&gt;#include &quot;cpu.h&quot;&lt;br&gt;&lt;br&gt;int main(void)&lt;br&gt;{&lt;br&gt;    cpu_reset();&lt;br&gt;&lt;br&gt;    return 0;&lt;br&gt;}&lt;/pre&gt;
&lt;ul class=&quot;ak-ul&quot; data-indent-level=&quot;1&quot;&gt;
&lt;li&gt;
&lt;p data-renderer-start-pos=&quot;8312&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;build/&lt;/em&gt; é a pasta que recebe todos os arquivos compilados e intermediários. Quando o projeto é clonado, esta pasta não deverá existir&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-renderer-start-pos=&quot;8448&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;src/&lt;/em&gt; todo nosso código C ficará nesta pasta, incluindo os testes!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-renderer-start-pos=&quot;8448&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;src/*.test.c&lt;/em&gt; alguns arquivos poderão receber o sufixo &lt;em data-renderer-mark=&quot;true&quot;&gt;.test.c&lt;/em&gt;, que indica que são arquivos de teste. Desta forma conseguimos escrever testes e garantir maior qualidade no projeto&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-renderer-start-pos=&quot;8699&quot;&gt;Portanto vamos criar o arquivo &lt;em data-renderer-mark=&quot;true&quot;&gt;Makefile&lt;/em&gt; com o seguinte conteúdo:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;8699&quot;&gt;CC=clang&lt;br&gt;CFLAGS=-std=c99 -Wall&lt;br&gt;LFLAGS=&lt;br&gt;&lt;br&gt;SRCDIR=src&lt;br&gt;BUILDDIR=build&lt;br&gt;OUT=qmario&lt;br&gt;&lt;br&gt;OBJS=$(BUILDDIR)/cpu.o&lt;br&gt;MAINOBJ=$(BUILDDIR)/main.o&lt;br&gt;TOBJS=$(BUILDDIR)/cpu.test.o&lt;br&gt;&lt;br&gt;run: $(BUILDDIR)/$(OUT)&lt;br&gt;    $(BUILDDIR)/$(OUT)&lt;br&gt;&lt;br&gt;test: $(BUILDDIR) $(OBJS) $(TOBJS)&lt;br&gt;    $(CC) $(OBJS) $(TOBJS) -o $(BUILDDIR)/tests $(LFLAGS)&lt;br&gt;    $(BUILDDIR)/tests&lt;br&gt;&lt;br&gt;# Constrói o executável principal&lt;br&gt;$(BUILDDIR)/$(OUT): $(BUILDDIR) $(OBJS) $(MAINOBJ)&lt;br&gt;    $(CC) $(OBJS) $(MAINOBJ) -o $(BUILDDIR)/$(OUT) $(LFLAGS)&lt;br&gt;&lt;br&gt;$(BUILDDIR):&lt;br&gt;    mkdir -p $(BUILDDIR)&lt;br&gt;&lt;br&gt;$(BUILDDIR)/%.o: $(SRCDIR)/%.c&lt;br&gt;    $(CC) -c $&amp;lt; -o $@ $(CFLAGS)&lt;br&gt;&lt;br&gt;.PHONY: clean&lt;br&gt;clean:&lt;br&gt;    $(RM) -r $(BUILDDIR)&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;9363&quot;&gt;Agora que o arquivo &lt;em data-renderer-mark=&quot;true&quot;&gt;Makefile&lt;/em&gt; existe, podemos executar o comando &lt;code&gt;make clean run&lt;/code&gt; para compilar e executar o programa que definimos em &lt;code&gt;main.c&lt;/code&gt;.&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;9363&quot;&gt;$ make clean run&lt;/pre&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/47/Screenshot-2022-07-05-at-15.41.31.png&quot; alt=&quot;Compilando o programa do zero e executando build/qmario.&quot; width=&quot;1158&quot; height=&quot;412&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;rich-media-item mediaSingleView-content-wrap image-center css-4jwx69&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div class=&quot;css-3vtcul&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;9524&quot;&gt;Compilando o programa do zero e executando build/qmario.&lt;/div&gt;
&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;9583&quot;&gt;E para rodar nossos testes, definidos no arquivo &lt;code&gt;cpu.test.c&lt;/code&gt;, podemos rodar o comando &lt;code&gt;make clean test&lt;/code&gt;. Como a seguir:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;9583&quot;&gt;$ make clean test&lt;/pre&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/47/Screenshot-2022-07-05-at-15.41.44.png&quot; alt=&quot;Compilando o programa do zero e executando build/tests.&quot; width=&quot;1332&quot; height=&quot;410&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;rich-media-item mediaSingleView-content-wrap image-center css-qdbqwu&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div class=&quot;css-3vtcul&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;9722&quot;&gt;Compilando o programa do zero e executando build/tests.&lt;/div&gt;
&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;9780&quot;&gt;A estrutura de pastas deverá ficar mais ou menos assim:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;9780&quot;&gt;├── LICENSE&lt;br&gt;├── Makefile&lt;br&gt;├── build&lt;br&gt;│   ├── cpu.o&lt;br&gt;│   ├── cpu.test.o&lt;br&gt;│   ├── main.o&lt;br&gt;│   ├── qmario&lt;br&gt;│   └── tests&lt;br&gt;└── src&lt;br&gt;    ├── cpu.c&lt;br&gt;    ├── cpu.h&lt;br&gt;    ├── cpu.test.c&lt;br&gt;    └── main.c&lt;/pre&gt;
&lt;h2 class=&quot;p1&quot;&gt;Vamos rodar os testes como parte da integração contínua&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;10077&quot;&gt;Agora que a nosso &lt;em data-renderer-mark=&quot;true&quot;&gt;Makefile&lt;/em&gt; está configurado e funcionando bonitinho, podemos alterar o arquivo &lt;code&gt;.github/workflows/ci.yaml&lt;/code&gt; para fazermos a compilação e rodar os testes sempre que abrirmos um &lt;em data-renderer-mark=&quot;true&quot;&gt;Pull Request&lt;/em&gt; no repositório que criamos.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;10308&quot;&gt;Dê o seguinte conteúdo para o arquivo &lt;code&gt;.github/workflows/ci.yaml&lt;/code&gt;:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;10308&quot;&gt;name: CI&lt;br&gt;on:&lt;br&gt;    push:&lt;br&gt;        branches: [ &quot;main&quot; ]&lt;br&gt;    pull_request:&lt;br&gt;        branches: [ &quot;main&quot; ]&lt;br&gt;jobs:&lt;br&gt;    build:&lt;br&gt;        runs-on: ubuntu-latest&lt;br&gt;        steps:&lt;br&gt;            - uses: actions/checkout@v3&lt;br&gt;            - name: Fazer build e rodar&lt;br&gt;              run: make clean test&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;10652&quot;&gt;Pode enviar o código para o Github e note que o CI agora está verde, indicando que todos os passos foram executados e tudo correu bem:&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/47/Screenshot-2022-07-05-at-16.44.29.png&quot; alt=&quot;Pull Request com a indicação de que todos os testes rodaram e podemos fazer o merge.&quot; width=&quot;1838&quot; height=&quot;612&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;rich-media-item mediaSingleView-content-wrap image-center css-1mzi1es&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div class=&quot;css-3vtcul&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;10790&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;Pull Request&lt;/em&gt; com a indicação de que todos os testes rodaram e podemos fazer o &lt;em data-renderer-mark=&quot;true&quot;&gt;merge&lt;/em&gt;.&lt;/div&gt;
&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 class=&quot;p1&quot;&gt;Próximos passos&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;10894&quot;&gt;Já temos uma integração contínua configurada e pronta para receber nosso código. O próximo passo é começar a escrever o emulador!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;11025&quot;&gt;O primeiro componente a ser escrito é justamente a CPU, que deverá ser escrita em conjunto com o barramento (memory BUS). &lt;strong data-renderer-mark=&quot;true&quot;&gt;No próximo artigo nós vamos começar a entender o chip 6502 utilizado pelo NES, e vamos emular algumas operações.&lt;/strong&gt;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;11261&quot;&gt;Não se esqueça de que o próximo artigo só sai se um número suficiente de pessoas ajudar a divulgar a série! 👇&lt;/p&gt;
&lt;div class=&quot;ak-editor-panel css-1i4jwoe&quot; data-panel-type=&quot;custom&quot; data-panel-color=&quot;#FFEBE6&quot; data-panel-icon=&quot;:info:&quot; data-panel-icon-id=&quot;atlassian-info&quot;&gt;
&lt;div class=&quot;ak-editor-panel__content&quot;&gt;
&lt;p class=&quot;msg msg--highlight &quot; data-renderer-start-pos=&quot;11374&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Atenção!&lt;/strong&gt; Para que este DevLog avance &lt;strong data-renderer-mark=&quot;true&quot;&gt;eu preciso da sua ajuda não financeira&lt;/strong&gt;: Dê &lt;a href=&quot;https://twitter.com/nawarian/status/1556909294167199744&quot; title=&quot;https://twitter.com/nawarian/status/1556909294167199744&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-bspq7p&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;retuíte neste post&lt;/a&gt; e compartilhe com colegas e quem mais se interessar. &lt;strong data-renderer-mark=&quot;true&quot;&gt;Somente após 50 RTs eu vou escrever o próximo post&lt;/strong&gt;. Esta é uma forma fácil e barata de você nos ajudar o projeto &lt;a href=&quot;https://codamos.com.br&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;codamos.com.br&lt;/a&gt; a crescer ao mesmo tempo que ganha um conteúdo exclusivo e de qualidade em português.&lt;/p&gt;
&lt;div&gt;
&lt;div id=&quot;content&quot; class=&quot;highlighter-context page view&quot; data-inline-comments-target=&quot;true&quot; data-test-id=&quot;page-content-only&quot;&gt;
&lt;div class=&quot;css-10izwvm en484vw0&quot;&gt;
&lt;div id=&quot;main-content&quot; class=&quot;wiki-content css-94xrhk e4p5jys0&quot; data-test-appearance=&quot;full-page&quot;&gt;
&lt;div class=&quot;renderer-overrides&quot;&gt;
&lt;div class=&quot;ak-renderer-wrapper css-2c6ch1&quot;&gt;
&lt;div class=&quot;css-fi5zfb&quot;&gt;
&lt;div class=&quot;ak-renderer-document&quot;&gt;
&lt;p data-renderer-start-pos=&quot;11729&quot;&gt;Dá o RT, divulga e lhe vejo na próxima! 👋&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</content:encoded><category>c</category><category>devlog</category><category>emulador-nes</category><category>jogos</category></item><item><title>Consegui meu primeiro emprego dev, e agora?</title><link>https://codamos.com.br/primeiro-emprego-como-desenvolvedor/</link><guid isPermaLink="true">https://codamos.com.br/primeiro-emprego-como-desenvolvedor/</guid><description>Fala galera, tudo belezinha? Novamente pokemaobr aqui para falar com vocês sobre coisas de desenvolvimento. Dessa vez iremos falar um pouco sobre as etapas que você irá passar após conseguir o seu emp</description><pubDate>Sat, 16 Jul 2022 08:14:09 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Fala galera, tudo belezinha? Novamente pokemaobr aqui para falar com vocês sobre coisas de desenvolvimento. Dessa vez iremos falar um pouco sobre as etapas que você irá passar após conseguir o seu emprego como dev.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Realmente é uma parte muito complexa o início dos estudos em desenvolvimento, até a conquista do seu primeiro emprego. Porém, os esforços não acabam por aí. Existem algumas coisas a se fazer assim que entramos na empresa e algumas coisas que devemos saber antes de começar nossa caminhada dentro do desenvolvimento propriamente dito.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;A primeira palavra que acho que devo dizer com um conselho para você que conseguiu um emprego é: CALMA. &lt;strong&gt;Nada do que você pensou vai ser imediato&lt;/strong&gt; e é importante você ter essa idéia antes do seu primeiro dia.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--left&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image&quot; src=&quot;/media/posts/43/todos-olhando-pra-mim-2.jpg&quot; alt=&quot;Todo o time em torno da mesma mesa olhando para o novo membro da equipe.&quot; width=&quot;1500&quot; height=&quot;2250&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Todo o time em torno da mesma mesa olhando para o novo membro da equipe.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Em geral &lt;strong&gt;você não vai ter acesso a nenhum código&lt;/strong&gt; nos primeiros dias, vai passar alguma parte do seu dia &lt;strong&gt;em reuniões que talvez não façam muito sentido para você&lt;/strong&gt;, irá tirar parte do tempo que você pensou que iria só estar codando para &lt;strong&gt;ler documentações&lt;/strong&gt;, conhecerá por alto as áreas de atuação da empresa, &lt;strong&gt;conhecerá a equipe&lt;/strong&gt; que trabalhará com você e provavelmente outras equipes que trabalharão indiretamente com você.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Caso você opte pelo regime de trabalho CLT (no Brasil), a primeira coisa a se fazer antes de começar o trabalho em si é &lt;strong&gt;assinar os contratos&lt;/strong&gt;, a galera pega também a sua carteira de trabalho e te pedem para fazer o exame médico de admissão, nesse exame basicamente uma pessoa médica te perguntará algumas coisas acerca da sua saúde, te pesará e medirá sua altura, e observará você para entender se está com aptidão ao trabalho ao qual te designaram.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Já no regime PJ, você deverá abrir uma empresa e aguardar o período da abertura para poder emitir nota. (É interessante você contratar e conversar com uma pessoa contadora antes para entender o processo geral em que se encaixa a atividade de desenvolvimento de software no simples nacional). &lt;strong&gt;Eu particularmente não indico o regime PJ para quem está no primeiro emprego de desenvolvimento&lt;/strong&gt;, mas, por exemplo, minha primeira experiência após sair da faculdade foi nesse regime, então é bem importante você ler sobre isso antes de entrar.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Após resolvidas essas burocracias, vamos ao que interessa. O que geralmente vai ocorrer com você quando iniciar o trabalho?&lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;Suas Boas Vindas&lt;/h2&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Hoje em dia, até mesmo por influência do LinkedIn, &lt;strong&gt;muitas empresas oferecem o que chamamos de welcome kit (kit de boas vindas)&lt;/strong&gt; para quem está entrando. Esse kit é meio que um modo de mostrar que a empresa se preocupa com você, é muito comum você receber quando entra em uma grande empresa, em uma startup “popzinha” ou agora no regime remoto.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Varia demais de empresa para empresa o que você receberá neste kit, em algumas até notebook e cadeira gamer você recebe, em outras alguns snacks, adesivos, camisetas e adivinhem??? cadernos rs.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Hoje em dia eu acho legal quando você recebe coisas massas no welcome kit, você já começa a sua jornada na empresa de um modo que te anima e em geral espera coisas boas nos dias que sucedem o começo. Porém, &lt;strong&gt;não ter welcome kit ou não ter algo que brilhe seus olhos, não faz da empresa um lugar ruim&lt;/strong&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;O onboarding&lt;/h2&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;&lt;strong&gt;O processo de inicialização (primeiros dias da sua entrada em uma empresa) é chamado de onboarding.&lt;/strong&gt; A ideia desse processo é que você se sinta parte dos processos na empresa, conheça um pouco da sua equipe e das equipes que você trabalhará diretamente, entenda o ciclo de desenvolvimento que será aplicado e, &lt;strong&gt;pouco a pouco, comece a receber suas demandas&lt;/strong&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image&quot; src=&quot;/media/posts/43/primeiro-dia-expectativa-vs-realidade.jpg&quot; alt=&quot;Meme sobre expectativas vs. realidade para o primeiro emprego como pessoa desenvolvedora&quot; width=&quot;1080&quot; height=&quot;1080&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Meme sobre expectativas vs. realidade para o primeiro emprego como pessoa desenvolvedora&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Aqui que muita gente acaba se desesperando quando começa um emprego dev. Na maioria das empresas, &lt;strong&gt;você vai demorar um tempo até mexer no código de verdade&lt;/strong&gt; e a ansiedade da galera que está começando aflora demais nesse período.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;É importante entender que grande parte das empresas trabalha com algum nível de criticidade em seu negócio e também com algum tipo de confidencialidade, e é importante você estar a par do que você vai poder ou não fazer. Além de entender o básico sobre como funciona o processo de desenvolvimento dentro da empresa em si.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;&lt;strong&gt;Então, se você não tem muita experiência na tecnologia, nesse período sua equipe vai te convidar para estudar mais e se aprimorar&lt;/strong&gt;. Além disso, você vai ter suporte da equipe para entender o processo de versionamento de código, entender superficialmente sobre a stack que é utilizada, entender o estilo de código que é desenvolvido, como é organizado o código, as principais regras de negócio que você vai ter que lidar e outras peculiaridades.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Outra coisa importante a se observar e que antes da gente entrar na área de desenvolvimento a gente acaba não entendendo, é que &lt;strong&gt;o onboarding sempre é algo demorado, independente do nível de senioridade.&lt;/strong&gt; Ouso até ao falar que quanto mais sênior, mais demorado o onboarding.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;&lt;strong&gt;Minha dica: perturbe realmente as pessoas que já estão lá a mais tempo!&lt;/strong&gt; É importante no começo da sua carreira como dev (na verdade não só no começo), você absorver o máximo de conhecimento que puder, até para facilitar quando você começar a mexer nas coisas realmente.&lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;O trabalho propriamente dito&lt;/h2&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Após apresentadas todas as premissas para você poder começar a trabalhar realmente, aí sim você vai colocar a mão na massa e começar a desenvolver as coisas. &lt;strong&gt;Cada empresa tem sua maneira de gerenciar as tarefas e o modo que vai ser entregue.&lt;/strong&gt; Mas, um fluxo normal de trabalho que é bem aplicado hoje em dia é o SCRUM (um framework agile), ou algo parecido com isso.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;O que quer dizer que geralmente a cada 2 semanas (depende da empresa/equipe), haverá uma reunião para definir as tarefas de cada pessoa e você terá um prazo estipulado entre essas 2 semanas para realizar o desenvolvimento delas. E haverão outras reuniões (geralmente uma reunião diária e outras complementares) para entender o andamento das tarefas e o que te impede de realizá-las caso tenha algum problema.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Nessa fase também, você irá realmente entender na prática como funciona o sistema de versionamento utilizado na empresa, os padrões de código e arquiteturas, os processos de deploy, entre outras fases do desenvolvimento.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Com o passar do tempo você vai pegar o jeito da empresa trabalhar e ficará bem mais fácil fazer realmente parte do todo.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/programacao-por-coincidencia/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Veja também: como evitar programação por coincidência e sempre ter certeza de que seu código está livre de erros.&lt;/a&gt;&lt;/p&gt;
&lt;div style=&quot;width: 100%; height: 0; padding-bottom: 50%; position: relative;&quot;&gt;&lt;iframe width=&quot;100%&quot; height=&quot;100%&quot; style=&quot;position: absolute;&quot; src=&quot;https://giphy.com/embed/3oKIPnAiaMCws8nOsE&quot; frameborder=&quot;0&quot; class=&quot;giphy-embed&quot; allowfullscreen=&quot;allowfullscreen&quot; data-mce-fragment=&quot;1&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;h2&gt;Seu crescimento e de olho em novas oportunidades&lt;/h2&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;&lt;strong&gt;É sempre importante você continuar atuante também fora da empresa para se manter em atualização&lt;/strong&gt;: seja participando de &lt;a href=&quot;/comunidades-de-desenvolvimento-de-software-brasileiras/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;comunidades de desenvolvimento&lt;/a&gt;, consumindo conteúdo de criadores, fazendo cursos, participando de eventos, alimentando seu &lt;a href=&quot;/subindo-arquivos-no-github/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;github&lt;/a&gt; com projetos pessoais ou auxiliando em projetos open-source, etc.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Uma premissa que é bem verdadeira, ainda mais na área de desenvolvimento. &lt;strong&gt;As pessoas recrutadoras buscam muito mais pessoas que já estão empregadas que as pessoas que não estão.&lt;/strong&gt; E, se atualizando constantemente, você será uma pessoa muito bem vista. &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;&lt;a href=&quot;/guia-definitivo-perfil-profissional-linkedin-passo-a-passo/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Descreva bem suas habilidades no LinkedIn&lt;/a&gt;, se possível tenha um site portfólio. Palestre, se divulgue, tenha um twitter ativo, dentre essas coisas que você lê, escuta e/ou assiste por aí. &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;A área de desenvolvimento está muito aquecida, mas, você não pode parar no tempo. Evolua sempre, se atualize sempre, estude sempre, e se mostre relevante. Quando você fizer isso, não precisará mais correr atrás de vagas. As vagas virão até você.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Desejo que tenha curtido o conteúdo e que ele te ajude a ter uma ideia de como será o seu início na área de desenvolvimento&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Caso tenha alguma dúvida pode entrar em contato comigo no &lt;a href=&quot;mailto:contato@pokemaobr.dev&quot;&gt;contato@pokemaobr.dev&lt;/a&gt; ou na minha live: &lt;/span&gt;&lt;a href=&quot;https://twitch.tv/pokemaobr&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;https://twitch.tv/pokemaobr&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt; ou no twitter: &lt;/span&gt;&lt;a href=&quot;https://twitter.com/pokemaobr&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;https://twitter.com/pokemaobr&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;!&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Obrigado de coração e até a próxima.&lt;/span&gt;&lt;/p&gt;</content:encoded><category>carreira</category><category>junior</category></item><item><title>Instruct The Women: capacitação python para mulheres</title><link>https://codamos.com.br/instruct-the-women-capacitacao-python-para-mulheres/</link><guid isPermaLink="true">https://codamos.com.br/instruct-the-women-capacitacao-python-para-mulheres/</guid><description>Quer aprender sobre Python, APIs, soft skills? Inscreva-se no Instruct The Women e junte-se a WoMakersCode! São 60 vagas para mulheres cis ou trans , com ensino médio completo, maiores de 18 anos e co</description><pubDate>Wed, 06 Jul 2022 04:49:54 GMT</pubDate><content:encoded>&lt;p&gt;Quer aprender sobre Python, APIs, soft skills? Inscreva-se no Instruct The Women e junte-se a WoMakersCode!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;São 60 vagas para mulheres cis ou trans&lt;/strong&gt;, com ensino médio completo, maiores de 18 anos e com conhecimentos básicos de programação.&lt;/p&gt;
&lt;p class=&quot;msg msg--info&quot;&gt;As selecionadas, ao final da capacitação, concorrerão também a uma vaga de trainee com registro CLT e tudo que é de direito!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;As inscrições vão até o dia 10 de Julho de 2022.&lt;/strong&gt; Então corre pra garantir a sua vaga!&lt;/p&gt;
&lt;h2&gt;Pré-requisitos&lt;/h2&gt;
&lt;p&gt;Pode se inscrever mulheres cis ou trans, com ensino médio completo, maiores de 18 anos e com os seguintes conhecimentos:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Familiaridade com algum editor de código&lt;/li&gt;
&lt;li&gt;Git / GitHub&lt;/li&gt;
&lt;li&gt;Conhecimento básico em alguma linguagem de programação (variáveis, condicionais, laços de repetição e função)&lt;/li&gt;
&lt;li&gt;Banco de dados básico (criar uma base, tabela, chave primária e relacionamento entre tabelas)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Faça sua inscrição entre 1 e 10 de Julho, até 18hrs!&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&quot;msg msg--success&quot;&gt;Segue o formulário de inscrição aqui: &lt;a href=&quot;https://bit.ly/instruct-the-women&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;https://bit.ly/instruct-the-women&lt;/a&gt;.&lt;/p&gt;</content:encoded><category>carreira</category><category>python</category><category>vagas</category></item><item><title>PHPeste 2022 em Natal, Rio Grande do Norte</title><link>https://codamos.com.br/phpeste-natal-rio-grande-do-norte-rn-2022/</link><guid isPermaLink="true">https://codamos.com.br/phpeste-natal-rio-grande-do-norte-rn-2022/</guid><description>A maior conferência brasileira de PHP organizada pelas comunidades nordestinas está de volta e vai acontecer entre os dias 7, 8 e 9 de Outubro de 2022! TL;DR – PHPeste 2022 vai acontecer em Natal, RN </description><pubDate>Fri, 17 Jun 2022 13:04:20 GMT</pubDate><content:encoded>&lt;p data-renderer-start-pos=&quot;229&quot;&gt;A maior conferência brasileira de PHP organizada pelas comunidades nordestinas está de volta e vai acontecer entre os dias 7, 8 e 9 de Outubro de 2022!&lt;/p&gt;
&lt;div class=&quot;ak-editor-panel css-1xdhyk6&quot; data-panel-type=&quot;info&quot;&gt;
&lt;div class=&quot;ak-editor-panel__content&quot;&gt;
&lt;div class=&quot;ak-editor-panel css-1xdhyk6&quot; data-panel-type=&quot;info&quot;&gt;
&lt;div class=&quot;ak-editor-panel__content&quot;&gt;
&lt;p class=&quot;msg msg--info&quot; data-renderer-start-pos=&quot;383&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;TL;DR&lt;/strong&gt; – &lt;strong data-renderer-mark=&quot;true&quot;&gt;PHPeste 2022 vai acontecer em Natal, RN nos dias 7, 8 e 9 de Outubro de 2022.&lt;/strong&gt; Mais informações no &lt;a href=&quot;https://www.phpeste.org/&quot; title=&quot;https://www.phpeste.org/&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-bspq7p&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;site oficial&lt;/a&gt;. O evento também tem um código de conduta que precisa ser respeitado, &lt;a href=&quot;https://www.phpeste.org/code-of-conduct/&quot; title=&quot;https://www.phpeste.org/code-of-conduct/&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-bspq7p&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;leia mais aqui&lt;/a&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;590&quot;&gt;Para mais informações em tempo real, visite também o canal &lt;a href=&quot;https://t.me/phpeste&quot; title=&quot;https://t.me/phpeste&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-bspq7p&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;PHPeste no Telegram&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;pm-table-container &quot; data-layout=&quot;default&quot;&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 23.3951%;&quot;&gt;Quando?&lt;/td&gt;
&lt;td style=&quot;width: 76.6049%;&quot; data-colwidth=&quot;340&quot;&gt;7, 8 e 9 de Outubro de 2022&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 23.3951%;&quot;&gt;Onde?&lt;/td&gt;
&lt;td style=&quot;width: 76.6049%;&quot; data-colwidth=&quot;340&quot;&gt;SEBRAE em Natal, Rio Grande do Norte, Brasil&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 23.3951%;&quot;&gt;Quanto?&lt;/td&gt;
&lt;th style=&quot;width: 76.6049%;&quot; data-colwidth=&quot;340&quot;&gt;Divulgação ao fim de Junho 2022 &lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 23.3951%;&quot;&gt;Quem?&lt;/td&gt;
&lt;td style=&quot;width: 76.6049%;&quot;&gt;Comunidades PHP do Nordeste brasileiro: Alagoas, Bahia, Ceará, Maranhão, Paraíba, Pernambuco, Piauí, Rio Grande do Norte e Sergipe.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;O-que-é-PHPeste?&quot; data-renderer-start-pos=&quot;970&quot;&gt;O que é PHPeste?&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;988&quot;&gt;PHPeste é uma conferência de PHP 100% organizada por comunidades do nordeste brasileiro e acontece desde 2015! É uma conferência itinerante e sem fins lucrativos, que a cada ano escolhe uma capital diferente.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1198&quot;&gt;As edições anteriores já visitaram João Pessoa (PB), Salvador (BA), Fortaleza (CE), São Luis (MA) e a última edição aconteceu em Recife (PE).&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1341&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Agora, em 2022, o PHPeste vai acontecer em Natal, lá no Rio Grande do Norte.&lt;/strong&gt; Serão 3 dias de evento com uma galera muito massa, PHP até abrir o bico e um ambiente simplesmente maravilhoso cerca de 15 minutos (de carro) distante da praia!&lt;/p&gt;
&lt;h2 id=&quot;Call-for-papers:-como-palestrar-no-PHPeste&quot; data-renderer-start-pos=&quot;1580&quot;&gt;Call for papers: como palestrar no PHPeste&lt;/h2&gt;
&lt;figure class=&quot;post__image post__image--left&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image&quot; src=&quot;/media/posts/45/phpeste-flyer-submissao.jpeg&quot; alt=&quot;Flyer de divulgação indicando a data 30/06/2022 como limite para submissões de atividades.&quot; width=&quot;1280&quot; height=&quot;1280&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Flyer de divulgação indicando a data 30/06/2022 como limite para submissões de atividades.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;1627&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Até o dia 30 de Junho de 2022 a organização do PHPeste 2022 receberá propostas de quem quiser apresentar alguma palestra ou oficina no evento.&lt;/strong&gt;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1771&quot;&gt;É importante ressaltar que o PHPeste possui seu próprio &lt;a href=&quot;https://www.phpeste.org/code-of-conduct/&quot; title=&quot;https://www.phpeste.org/code-of-conduct/&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-bspq7p&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;código de conduta&lt;/a&gt;. Eu vejo muita gente na comunidade resumir os códigos de conduta alheios com “não seja babaca”, mas isto não é suficiente! Vai lá de lá uma lida no código de conduta. É curto, rápido de ler e vai te ajudar a entender o que esperar deste evento.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2091&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Palestrantes do evento vão receber um auxílio da comunidade com estadia. E tradicionalmente a estadia com a galera do PHPeste é sempre muito massa!&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;ak-editor-panel css-1xdhyk6&quot; data-panel-type=&quot;info&quot;&gt;
&lt;div class=&quot;ak-editor-panel__content&quot;&gt;
&lt;div class=&quot;ak-editor-panel css-1xdhyk6&quot; data-panel-type=&quot;info&quot;&gt;
&lt;div class=&quot;ak-editor-panel__content&quot;&gt;
&lt;p class=&quot;msg msg--info&quot; data-renderer-start-pos=&quot;2241&quot;&gt;Para submeter sua proposta de palestra ou workshop, envie suas informações &lt;a href=&quot;https://bit.ly/phpeste2022&quot; title=&quot;https://bit.ly/phpeste2022&quot; data-renderer-mark=&quot;true&quot; class=&quot;css-bspq7p&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;neste formulário aqui&lt;/a&gt; até as 23:59 do dia 30 de Junho de 2022.&lt;/p&gt;
&lt;h2 class=&quot;p1&quot;&gt;Quero patrocinar o evento!&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;2409&quot;&gt;Caso você ou sua empresa queiram patrocinar o evento, aqui vão algumas direções pra ti!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2498&quot;&gt;O PHPeste está recebendo o apoio do &lt;em data-renderer-mark=&quot;true&quot;&gt;SEBRAE-RN&lt;/em&gt; e &lt;em data-renderer-mark=&quot;true&quot;&gt;sebraelab&lt;/em&gt;, que vão oferecer o espaço e infraestrutura. E para fazer o evento acontecer, outros suportes também são necessários para oferecer brindes e camisetas, comes e bebes e suporte a quem vai se apresentar e por aí vai.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2498&quot;&gt;Patrocinar o evento, além de ajudar a comunidade, é uma ótima oportunidade de &lt;em&gt;branding&lt;/em&gt; para a sua marca! Este ano o PHPeste preparou quatro modalidades de patrocínio: Bronze, Prata, Ouro e Diamante. Os benefícios de cada nível você confere na imagem a seguir:&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image&quot; src=&quot;/media/posts/45/phpeste-modalidades-patrocinio.png&quot; alt=&quot;Ilustração que mostra os benefícios de cada modalidade de patrocínio.&quot; width=&quot;1600&quot; height=&quot;867&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Ilustração que mostra os benefícios de cada modalidade de patrocínio.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Para acessar o plano de patrocínio completo, dá uma olhada &lt;a href=&quot;https://drive.google.com/file/d/16D3LQNxrbHRVSB79vQ0p60ardzf1vQR6/view&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;neste PDF aqui&lt;/a&gt; com todas as informações necessárias.&lt;/p&gt;
&lt;p class=&quot;msg msg--info&quot;&gt;Para mais informações sobre como patrocinar o evento, entre em contato diretamente com a organização no email &lt;a href=&quot;mailto:phpeste.evento@gmail.com&quot; rel=&quot;nofollow&quot;&gt;phpeste.evento@gmail.com&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;Linha do tempo&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;3193&quot;&gt;&lt;code&gt;&lt;span class=&quot;date-lozenger-container&quot;&gt;&lt;span class=&quot;date-node&quot; data-node-type=&quot;date&quot; data-timestamp=&quot;1653782400000&quot;&gt;29 Maio 2022&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; &lt;span style=&quot;text-decoration: line-through;&quot;&gt;Data da conferência divulgada: 7, 8 e 9 de Outubro de 2022 🥳&lt;/span&gt;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3258&quot;&gt;&lt;code&gt;&lt;span class=&quot;date-lozenger-container&quot;&gt;&lt;span class=&quot;date-node&quot; data-node-type=&quot;date&quot; data-timestamp=&quot;1654128000000&quot;&gt;2 Junho 2022&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; &lt;span style=&quot;text-decoration: line-through;&quot;&gt;Aberta a chamada para submissões de palestras e oficinas 🗣&lt;/span&gt;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3321&quot;&gt;&lt;code&gt;&lt;span class=&quot;date-lozenger-container&quot;&gt;&lt;span class=&quot;date-node&quot; data-node-type=&quot;date&quot; data-timestamp=&quot;1655337600000&quot;&gt;16 Junho 2022&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; &lt;span style=&quot;text-decoration: line-through;&quot;&gt;Prorrogada a chamada para submissões: serão aceitas até o dia 30/06/2022 🚨&lt;/span&gt;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3400&quot;&gt;&lt;code&gt;&lt;span class=&quot;date-lozenger-container&quot;&gt;&lt;span class=&quot;date-node&quot; data-node-type=&quot;date&quot; data-timestamp=&quot;1656547200000&quot;&gt;30 Junho 2022&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; &lt;span style=&quot;text-decoration: line-through;&quot;&gt;Primeiro lote de ingressos 🎫&lt;/span&gt;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3433&quot;&gt;&lt;code&gt;&lt;span class=&quot;date-lozenger-container&quot;&gt;&lt;span class=&quot;date-node&quot; data-node-type=&quot;date&quot; data-timestamp=&quot;1657497600000&quot;&gt;11 Julho 2022&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; &lt;span style=&quot;text-decoration: line-through;&quot;&gt;Divulgação da grade de palestrantes 📣&lt;/span&gt;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3475&quot;&gt;&lt;code&gt;&lt;span class=&quot;date-lozenger-container&quot;&gt;&lt;span class=&quot;date-node&quot; data-node-type=&quot;date&quot; data-timestamp=&quot;1665100800000&quot;&gt;7 Outubro 2022&lt;/span&gt;&lt;/span&gt;&lt;/code&gt; Muito PHP, cana, conhecimento e gente boa! 🐘&lt;/p&gt;
&lt;h2 id=&quot;Compartilhe!&quot; data-renderer-start-pos=&quot;3524&quot;&gt;Compartilhe!&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;3538&quot;&gt;O evento é da comunidade para a comunidade e precisa da sua ajuda para acontecer. Mesmo que não apoie ao PHPeste financeiramente, o simples ato de compartilhar este artigo e dar visibilidade já é uma enorme ajuda!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3753&quot;&gt;Então não deixe de compartilhar em suas redes sociais que o maior evento cabra da peste de PHP está pra acontecer. Aqui vão alguns links para as redes sociais da organização:&lt;/p&gt;
&lt;ul&gt;
&lt;li data-renderer-start-pos=&quot;3753&quot;&gt;Site oficial: &lt;a href=&quot;https://phpeste.org&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;phpeste.org&lt;/a&gt;&lt;/li&gt;
&lt;li data-renderer-start-pos=&quot;3753&quot;&gt;Facebook: &lt;a href=&quot;https://www.facebook.com/PeAgaPeste/&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;fb.com/PeAgaPeste&lt;/a&gt;&lt;/li&gt;
&lt;li data-renderer-start-pos=&quot;3753&quot;&gt;Instagram: &lt;a href=&quot;https://www.instagram.com/phpeste/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;@phpeste&lt;/a&gt;&lt;/li&gt;
&lt;li data-renderer-start-pos=&quot;3753&quot;&gt;Twitter: &lt;a href=&quot;https://twitter.com/phpestene&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;@phpestene&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</content:encoded><category>evento</category><category>php</category><category>phpeste</category></item><item><title>O princípio do Samurai 🤺</title><link>https://codamos.com.br/o-principio-do-samurai/</link><guid isPermaLink="true">https://codamos.com.br/o-principio-do-samurai/</guid><description>Em programação é recorrente encontrar pessoas discutindo sobre qual a melhor forma de escrever esta ou aquela função, que tipo de código é mais elegante e etc.. Mas muitas dessas discussões são basead</description><pubDate>Sat, 28 May 2022 11:04:27 GMT</pubDate><content:encoded>&lt;p data-renderer-start-pos=&quot;441&quot;&gt;Em programação é recorrente encontrar pessoas discutindo sobre qual a melhor forma de escrever esta ou aquela função, que tipo de código é mais elegante e etc.. Mas muitas dessas discussões são baseadas em opiniões e gostos pessoais, que usam argumentos circulares e travam o debate.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;726&quot;&gt;Por isso diferentes princípios de programação e de &lt;em data-renderer-mark=&quot;true&quot;&gt;design&lt;/em&gt; foram estabelecidos, de forma a encurtar discussões sobre gostos e boas práticas. &lt;strong data-renderer-mark=&quot;true&quot;&gt;Dentre os princípios mais famosos estão o &lt;/strong&gt;&lt;a class=&quot;sc-jKJlTe dPfAtb&quot; href=&quot;https://pt.wikipedia.org/wiki/SOLID&quot; title=&quot;https://pt.wikipedia.org/wiki/SOLID&quot; data-renderer-mark=&quot;true&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;SOLID&lt;/strong&gt;&lt;/a&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;, &lt;/strong&gt;&lt;a class=&quot;sc-jKJlTe dPfAtb&quot; href=&quot;https://pt.wikipedia.org/wiki/Don%27t_repeat_yourself&quot; title=&quot;https://pt.wikipedia.org/wiki/Don%27t_repeat_yourself&quot; data-renderer-mark=&quot;true&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;DRY&lt;/strong&gt;&lt;/a&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;, &lt;/strong&gt;&lt;a class=&quot;sc-jKJlTe dPfAtb&quot; href=&quot;https://pt.wikipedia.org/wiki/Princ%C3%ADpio_KISS&quot; title=&quot;https://pt.wikipedia.org/wiki/Princ%C3%ADpio_KISS&quot; data-renderer-mark=&quot;true&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;KISS&lt;/strong&gt;&lt;/a&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt; e &lt;/strong&gt;&lt;a class=&quot;sc-jKJlTe dPfAtb&quot; href=&quot;https://pt.wikipedia.org/wiki/YAGNI&quot; title=&quot;https://pt.wikipedia.org/wiki/YAGNI&quot; data-renderer-mark=&quot;true&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;YAGNI&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;935&quot;&gt;Já &lt;strong data-renderer-mark=&quot;true&quot;&gt;o princípio do Samurai não é tão conhecido&lt;/strong&gt;, especialmente para quem se acostumou a programar em linguagens mais modernas. Mas é uma sabedoria anciã que vem lá da época do C, que eu acho que toda pessoa desenvolvedora deveria carregar consigo.&lt;/p&gt;
&lt;h2&gt;O que é o princípio do Samurai?&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;1215&quot;&gt;Nós, aqui do ocidente, gostamos de inventar misticismo sobre as coisas que não entendemos do oriente e, com certeza, o Samurai é uma delas. Mas em programação, o princípio do Samurai não tem nada a ver com o Bushidô!&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1433&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;O princípio do Samurai é um princípio de &lt;/strong&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;design&lt;/strong&gt;&lt;/em&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt; de software que diz “retorne com sucesso, senão nem mesmo retorne”&lt;/strong&gt;, baseado naquela mística da honra ilibada dos Samurais. Que é um jeito bonitinho de dizer que devemos manter um único tipo de retorno para nossas rotinas, funções e métodos.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;1668&quot;&gt;Eu aprendi sobre este princípio lendo o &lt;a class=&quot;sc-jKJlTe dPfAtb&quot; href=&quot;https://bit.ly/fluent-c&quot; title=&quot;https://bit.ly/fluent-c&quot; data-renderer-mark=&quot;true&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;livro Fluent C, que traz diversos padrões e boas práticas para programas escritos na linguagem C com exemplos&lt;/a&gt;. Eu definitivamente recomendo a leitura!&lt;/p&gt;
&lt;h2 id=&quot;“Sempre-retorne-com-sucesso,-senão-nem-mesmo-retorne”-🤺&quot; data-renderer-start-pos=&quot;1860&quot;&gt;“Sempre retorne com sucesso, senão nem mesmo retorne” 🤺&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;1918&quot;&gt;Este princípio ressoa bastante com a ideia de &lt;em data-renderer-mark=&quot;true&quot;&gt;early return&lt;/em&gt;, mas a principal diferença é que não queremos apenas retornar o quanto antes: queremos interromper a execução do programa caso algo esteja errado.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2125&quot;&gt;E apesar de ser muito útil em linguagens como C, este princípio se aplica e deveria estar fortemente presente em linguagens mais modernas como o PHP, Rust e Golang.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2291&quot;&gt;Mas como diachos a gente chegou num princípio desse e como se aplica a software? Vem comigo que eu tenho muita explicação e exemplo de código pra você!&lt;/p&gt;
&lt;h2 id=&quot;Contexto:-linguagem-C&quot; data-renderer-start-pos=&quot;2444&quot;&gt;Contexto e história: linguagem C&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;2467&quot;&gt;Na linguagem C é fundamental saber lidar com ponteiros e fazer alocações dinâmicas. Acontece que &lt;strong data-renderer-mark=&quot;true&quot;&gt;algumas operações com ponteiros e memória podem falhar&lt;/strong&gt; por circunstâncias do sistema operacional: alocar memória para ler um arquivo pode causar um estouro de pilha, receber um dado por rede por falhar por perda de conexão e etc..&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2796&quot;&gt;No caso de linguagens como C, estas situações podem criar o famoso &lt;a class=&quot;sc-jKJlTe dPfAtb&quot; href=&quot;https://pt.wikipedia.org/wiki/Ponteiro_(programa%C3%A7%C3%A3o)#Ponteiro_nulo&quot; title=&quot;https://pt.wikipedia.org/wiki/Ponteiro_(programa%C3%A7%C3%A3o)#Ponteiro_nulo&quot; data-renderer-mark=&quot;true&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;NULL Pointer&lt;/em&gt; ou ponteiros nulos&lt;/a&gt;. Variáveis que deveriam possuir um conteúdo mas não possuem por algum motivo.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;2974&quot;&gt;No exemplo a seguir, nós vamos extrair palavras-chave de um texto. Preste atenção no que fazemos com a variável &lt;code class=&quot;code css-9z42f9&quot; data-renderer-mark=&quot;true&quot;&gt;handle&lt;/code&gt; que é um ponteiro que representa o arquivo de texto que estamos lendo.&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image post__image--center&quot; src=&quot;/media/posts/44/ponteiro-nulo-01.png&quot; alt=&quot;Utilização e tratamento de um ponteiro potencialmente nulo (condição IF linha 7)&quot; width=&quot;1192&quot; height=&quot;1146&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Utilização e tratamento de um ponteiro potencialmente nulo (condição IF linha 7)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;3168&quot;&gt;A transcrição da imagem acima está aqui:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;3168&quot;&gt;string_t *fetch_keywords(string_t filename)&lt;br&gt;{&lt;br&gt;  FILE *handle;&lt;br&gt;  string_t *keywords;&lt;br&gt;  handle = fopen(filename, &quot;r&quot;);&lt;br&gt;&lt;br&gt;  if (handle != NULL) {&lt;br&gt;    keywords = _fetch_keywords_from_file(handle);&lt;br&gt;    fclose(handle);&lt;br&gt;    return keywords;&lt;br&gt;  }&lt;br&gt;&lt;br&gt;  return NULL;&lt;br&gt;}&lt;/pre&gt;
&lt;p&gt;Você não precisa ser especialista em C pra entender o que tá acontecendo. Vem que eu te explico:&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3573&quot;&gt;A função &lt;code class=&quot;code css-9z42f9&quot; data-renderer-mark=&quot;true&quot;&gt;fetch_keywords()&lt;/code&gt; têm como retorno o tipo &lt;code class=&quot;code css-9z42f9&quot; data-renderer-mark=&quot;true&quot;&gt;string_t*&lt;/code&gt;: o ponteiro para um vetor de strings. E recebe como parâmetro uma única string chamada &lt;code class=&quot;code css-9z42f9&quot; data-renderer-mark=&quot;true&quot;&gt;filename&lt;/code&gt;, que indica qual arquivo deverá ser aberto para leitura.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;3787&quot;&gt;Para abrir o arquivo nós usamos a função &lt;a class=&quot;sc-jKJlTe dPfAtb&quot; href=&quot;https://man7.org/linux/man-pages/man3/fopen.3.html&quot; title=&quot;https://man7.org/linux/man-pages/man3/fopen.3.html&quot; data-renderer-mark=&quot;true&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;fopen()&lt;/em&gt;&lt;/a&gt; que retorna um ponteiro do tipo &lt;code class=&quot;code css-9z42f9&quot; data-renderer-mark=&quot;true&quot;&gt;FILE*&lt;/code&gt;. Caso &lt;code class=&quot;code css-9z42f9&quot; data-renderer-mark=&quot;true&quot;&gt;fopen()&lt;/code&gt; encontre e consiga abrir o arquivo para leitura, o ponteiro &lt;code class=&quot;code css-9z42f9&quot; data-renderer-mark=&quot;true&quot;&gt;FILE *handle&lt;/code&gt; passa a ter um valor lá dentro. Senão, caso um erro tenha ocorrido ao abrir o arquivo, &lt;code class=&quot;code css-9z42f9&quot; data-renderer-mark=&quot;true&quot;&gt;FILE *handle&lt;/code&gt; passa a ter o valor &lt;code class=&quot;code css-9z42f9&quot; data-renderer-mark=&quot;true&quot;&gt;NULL&lt;/code&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;4088&quot;&gt;É importante então sempre testar se os ponteiros de arquivo são nulos ou não, porque acessar um ponteiro nulo cria um erro fatal em sua aplicação. Aqui um exemplo de como acessar um ponteiro nulo pode causar um &lt;em data-renderer-mark=&quot;true&quot;&gt;segmentation fault&lt;/em&gt;:&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image post__image--center&quot; src=&quot;/media/posts/44/segmentation-fault.png&quot; alt=&quot;O ponteiro FILE * é nulo e ao chamar fread() com este ponteiro nulo, a aplicação gera um Segmentation fault.&quot; width=&quot;658&quot; height=&quot;468&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;O ponteiro FILE * é nulo e ao chamar fread() com este ponteiro nulo, a aplicação gera um Segmentation fault.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;4433&quot;&gt;Agora, repare que o retorno da nossa função &lt;code class=&quot;code css-9z42f9&quot; data-renderer-mark=&quot;true&quot;&gt;fetch_keywords()&lt;/code&gt; é um ponteiro para um vetor de strings (&lt;code class=&quot;code css-9z42f9&quot; data-renderer-mark=&quot;true&quot;&gt;string_t *&lt;/code&gt;). Este ponteiro também pode ser &lt;em data-renderer-mark=&quot;true&quot;&gt;NULL&lt;/em&gt;, para indicar que não encontramos nenhuma palavra-chave no arquivo.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;4651&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;O problema disso é que esta função obriga as funções que a chamam a também verificarem se o retorno é nulo ou não&lt;/strong&gt;. Com isso, dois problemas aparecem:&lt;/p&gt;
&lt;ol class=&quot;ak-ol&quot; data-indent-level=&quot;1&quot;&gt;
&lt;li&gt;
&lt;p data-renderer-start-pos=&quot;4804&quot;&gt;A gente NUNCA consegue garantir que seus usuários estão utilizando seu código da forma esperada;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-renderer-start-pos=&quot;4904&quot;&gt;O montante de código duplicado é grande a deixa o código totalmente bagunçado.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-renderer-start-pos=&quot;4986&quot;&gt;Portanto o ideal, e o que &lt;strong data-renderer-mark=&quot;true&quot;&gt;o princípio do Samurai diz, é que você sempre deve retornar apenas em caso de sucesso. Caso não obtenha sucesso, você não pode sequer retornar.&lt;/strong&gt; Você deve interromper a execução do programa imediatamente.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;4986&quot;&gt;Assim:&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image post__image--center&quot; src=&quot;/media/posts/44/ponteiro-nulo-com-assert.png&quot; alt=&quot;Ao utilizar assert() não é mais necessário escrever vários IF statements.&quot; width=&quot;1384&quot; height=&quot;1098&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Ao utilizar assert() não é mais necessário escrever vários IF statements.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;5302&quot;&gt;A transcrição do código na imagem acima é a seguinte:&lt;/p&gt;
&lt;pre data-renderer-start-pos=&quot;5302&quot;&gt;string_t *fetch_keywords(string_t filename)&lt;br&gt;{&lt;br&gt;  FILE *handle;&lt;br&gt;  string_t *keywords;&lt;br&gt;  handle = fopen(filename, &quot;r&quot;);&lt;br&gt;  &lt;br&gt;  // Se handle for NULL, o programa pára por aqui&lt;br&gt;  assert(handle != NULL &amp;amp;&amp;amp; &quot;Could not open keywords file&quot;);&lt;br&gt;&lt;br&gt;  keywords = _fetch_keywords_from_file(handle);&lt;br&gt;  fclose(handle);&lt;br&gt;  return keywords;&lt;br&gt;}&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;5676&quot;&gt;Aquele &lt;a class=&quot;sc-jKJlTe dPfAtb&quot; href=&quot;https://man7.org/linux/man-pages/man3/assert.3.html&quot; title=&quot;https://man7.org/linux/man-pages/man3/assert.3.html&quot; data-renderer-mark=&quot;true&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;assert()&lt;/em&gt;&lt;/a&gt; no meio da função vai interromper o programa completamente caso a expressão ali não retorne &lt;code class=&quot;code css-9z42f9&quot; data-renderer-mark=&quot;true&quot;&gt;TRUE&lt;/code&gt;. Desta forma você diminui o número de IFs aqui e em todos lugares que chamam esta função.&lt;/p&gt;
&lt;h2 id=&quot;Como-aplicar-o-princípio-do-Samurai-em-linguagens-modernas?&quot; data-renderer-start-pos=&quot;5880&quot;&gt;Como aplicar o princípio do Samurai em linguagens modernas?&lt;/h2&gt;
&lt;p data-renderer-start-pos=&quot;5941&quot;&gt;Linguagens mais modernas do que o C como o C++, Java e PHP possuem &lt;strong data-renderer-mark=&quot;true&quot;&gt;um mecanismo de gerenciamento e propagação de erros chamado &lt;/strong&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Exceções&lt;/strong&gt;&lt;/em&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt; ou &lt;/strong&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Exceptions&lt;/strong&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;6093&quot;&gt;A ideia é que um pedaço de código pode &lt;em data-renderer-mark=&quot;true&quot;&gt;lançar&lt;/em&gt; uma exceção utilizando a palavra-chave &lt;code class=&quot;code css-9z42f9&quot; data-renderer-mark=&quot;true&quot;&gt;throw&lt;/code&gt; e a execução do &lt;em data-renderer-mark=&quot;true&quot;&gt;stack frame&lt;/em&gt; atual é interrompida imediatamente, retornando o &lt;em data-renderer-mark=&quot;true&quot;&gt;stack frame&lt;/em&gt; superior. E caso não exista nenhum mecanismo para tratar a exceção, ela continua se propagando até encontrar algum &lt;em data-renderer-mark=&quot;true&quot;&gt;stack frame&lt;/em&gt; que a capture ou até a aplicação ser interrompida.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;6452&quot;&gt;Aqui um exemplo de &lt;a class=&quot;sc-jKJlTe dPfAtb&quot; href=&quot;https://www.php.net/manual/pt_BR/language.exceptions.php&quot; title=&quot;https://www.php.net/manual/pt_BR/language.exceptions.php&quot; data-renderer-mark=&quot;true&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;exceção&lt;/em&gt; utilizando PHP&lt;/a&gt;:&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image post__image--center&quot; src=&quot;/media/posts/44/exemplo-principio-do-samurai-com-php.png&quot; alt=&quot;Em PHP podemos lançar e capturar exceções específicas, para controlar o fluxo do programa.&quot; width=&quot;1510&quot; height=&quot;1474&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;div class=&quot;rich-media-item mediaSingleView-content-wrap image-center sc-krvtoX gAHdtv sc-lkqHmb dRxJBH&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;div class=&quot;sc-jTzLTM diNXoT&quot; data-media-caption=&quot;true&quot; data-testid=&quot;media-caption&quot; data-renderer-start-pos=&quot;6498&quot;&gt;Em PHP podemos lançar e capturar exceções específicas, para controlar o fluxo do programa.&lt;/div&gt;
&lt;/div&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;6591&quot;&gt;A transcrição do código da imagem acima é a seguinte:&lt;/p&gt;
&lt;pre class=&quot;code-block sc-hORach hrZwGg&quot;&gt;function a(bool $x): void&lt;br&gt;{&lt;br&gt;  try {&lt;br&gt;    b($x);&lt;br&gt;  } catch (EntityNotFoundException $e) {&lt;br&gt;    echo $e-&amp;gt;getMessage();&lt;br&gt;  }&lt;br&gt;}&lt;br&gt;&lt;br&gt;function b(bool $x): void&lt;br&gt;{&lt;br&gt;  if ($x === true) {&lt;br&gt;    throw new InvalidArgumentException(&quot;Outro tipo de exceção&quot;);&lt;br&gt;  }&lt;br&gt;  &lt;br&gt;  throw new EntityNotFoundException(&quot;Mensagem da minha exception&quot;);&lt;br&gt;}&lt;br&gt;&lt;br&gt;a(false);&lt;br&gt;a(true);&lt;br&gt;echo &apos;Nunca alcancaremos esta linha!&apos;;&lt;/pre&gt;
&lt;p data-renderer-start-pos=&quot;7019&quot;&gt;No exemplo acima, a chamada &lt;code class=&quot;code css-9z42f9&quot; data-renderer-mark=&quot;true&quot;&gt;a(false)&lt;/code&gt; causa a função &lt;code class=&quot;code css-9z42f9&quot; data-renderer-mark=&quot;true&quot;&gt;b()&lt;/code&gt; lançar uma exceção do tipo &lt;code class=&quot;code css-9z42f9&quot; data-renderer-mark=&quot;true&quot;&gt;EntityNotFoundException&lt;/code&gt;, que é explicitamente capturada no escopo da função &lt;code class=&quot;code css-9z42f9&quot; data-renderer-mark=&quot;true&quot;&gt;a()&lt;/code&gt;. Portanto toda vez que uma exceção deste tipo é lançada, &lt;code class=&quot;code css-9z42f9&quot; data-renderer-mark=&quot;true&quot;&gt;a()&lt;/code&gt; apenas faz um &lt;a class=&quot;sc-jKJlTe dPfAtb&quot; href=&quot;https://www.php.net/manual/pt_BR/function.echo.php&quot; title=&quot;https://www.php.net/manual/pt_BR/function.echo.php&quot; data-renderer-mark=&quot;true&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;echo&lt;/em&gt;&lt;/a&gt; para jogar a mensagem da exceção na tela e seguir seu rumo normalmente.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;7335&quot;&gt;Quando chamamos &lt;code class=&quot;code css-9z42f9&quot; data-renderer-mark=&quot;true&quot;&gt;a(true)&lt;/code&gt; nós forçamos que &lt;code class=&quot;code css-9z42f9&quot; data-renderer-mark=&quot;true&quot;&gt;b()&lt;/code&gt; lance uma exceção de outro tipo, que não é capturada no &lt;em data-renderer-mark=&quot;true&quot;&gt;stack frame&lt;/em&gt; da função &lt;code class=&quot;code css-9z42f9&quot; data-renderer-mark=&quot;true&quot;&gt;a()&lt;/code&gt;. De fato, ninguém na aplicação tenta capturar aquela exceção, que acaba por interromper o código completamente.&lt;/p&gt;
&lt;p class=&quot;msg msg--info&quot; data-renderer-start-pos=&quot;7575&quot;&gt;🏮 Em linguagens modernas, a forma mais fácil de adotar o princípio do Samurai é lançando exceções👌&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;7673&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Algumas linguagens modernas não possuem exceções, como é o caso do Rust e Golang&lt;/strong&gt;. Apesar de o próprio ecossistema da linguagem te forçar a lidar com casos de erro, &lt;strong data-renderer-mark=&quot;true&quot;&gt;a saída para quando não se consegue lidar com determinado fluxo de exceção é interromper a execução do programa&lt;/strong&gt;.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;7951&quot;&gt;Portanto caso a sua linguagem não possua o mecanismo de exceção (exceptions) você pode sempre aplicar o drástico &lt;em data-renderer-mark=&quot;true&quot;&gt;exit&lt;/em&gt; em sua aplicação, que força o interrompimento do programa como um todo.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;8142&quot;&gt;No caso do Golang você pode utilizar o &lt;a class=&quot;sc-jKJlTe dPfAtb&quot; href=&quot;https://gobyexample.com/exit&quot; title=&quot;https://gobyexample.com/exit&quot; data-renderer-mark=&quot;true&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;os.Exit&lt;/em&gt;&lt;/a&gt;, enquanto o Rust possui vários mecanismos diferentes: o &lt;a class=&quot;sc-jKJlTe dPfAtb&quot; href=&quot;https://doc.rust-lang.org/stable/std/process/fn.exit.html&quot; title=&quot;https://doc.rust-lang.org/stable/std/process/fn.exit.html&quot; data-renderer-mark=&quot;true&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;std::process::exit&lt;/em&gt;&lt;/a&gt; que faz a mesma coisa que o Golang faz, mas também possui diferentes macros e métodos que podem encerrar a execução do programa completamente como é o caso das macros &lt;a class=&quot;sc-jKJlTe dPfAtb&quot; href=&quot;https://doc.rust-lang.org/std/macro.assert.html&quot; title=&quot;https://doc.rust-lang.org/std/macro.assert.html&quot; data-renderer-mark=&quot;true&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;assert&lt;/em&gt; e &lt;em data-renderer-mark=&quot;true&quot;&gt;panic&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image post__image--center&quot; src=&quot;/media/posts/44/exemplo-panic-com-rust.png&quot; alt=&quot;Exemplo de interrupção do programa utilizando a macro panic! do Rust.&quot; width=&quot;876&quot; height=&quot;291&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Exemplo de interrupção do programa utilizando a macro panic! do Rust.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-renderer-start-pos=&quot;8522&quot;&gt;A transcrição do programa acima é a seguinte:&lt;/p&gt;
&lt;pre class=&quot;code-block sc-hORach hrZwGg&quot;&gt;fn main() {&lt;br&gt;  panic!(&quot;Oh noez!&quot;);&lt;br&gt;}&lt;/pre&gt;
&lt;h2 id=&quot;Até-a-próxima&quot; data-renderer-start-pos=&quot;8606&quot;&gt;Até a próxima&lt;/h2&gt;
&lt;div&gt;
&lt;div id=&quot;content&quot; class=&quot;highlighter-context page view&quot; data-inline-comments-target=&quot;true&quot; data-test-id=&quot;page-content-only&quot;&gt;
&lt;div class=&quot;css-10izwvm en484vw0&quot;&gt;
&lt;div id=&quot;main-content&quot; class=&quot;wiki-content css-yjz6t5 e4p5jys0&quot; data-test-appearance=&quot;full-page&quot;&gt;
&lt;div class=&quot;ak-renderer-wrapper sc-bdVaJa jGgciL&quot;&gt;
&lt;div class=&quot;sc-jzJRlG jjuufi&quot;&gt;
&lt;div class=&quot;ak-renderer-document&quot;&gt;
&lt;p data-renderer-start-pos=&quot;8621&quot;&gt;Espero que este pequeno artigo-resposta tenha sido útil pra ti e, no mínimo, aguçado sua curiosidade sobre o tema. Todos os princípios de software têm um motivo para existir e, mais importante do que entender o princípio em si, é entender como se aplica e em quais contextos.&lt;/p&gt;
&lt;p data-renderer-start-pos=&quot;8898&quot;&gt;Não se esqueça de compartilhar este artigo em suas redes sociais e com seus colegas de trabalho. E também pega pra ouvir &lt;em&gt;Samurai&lt;/em&gt; do Djavan, que esta musica e artigo vão ficar na sua cabeça pelo menos por 2 dias 🤣&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;width: 100%; height: 0; padding-bottom: 64%; position: relative;&quot;&gt;&lt;iframe width=&quot;100%&quot; height=&quot;100%&quot; style=&quot;position: absolute;&quot; src=&quot;https://giphy.com/embed/3oKIPfFs4hPHemcU6I&quot; frameborder=&quot;0&quot; class=&quot;giphy-embed&quot; allowfullscreen=&quot;allowfullscreen&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;https://giphy.com/gifs/alanwalker-alan-walker-3oKIPfFs4hPHemcU6I&quot;&gt;via GIPHY&lt;/a&gt;&lt;/p&gt;</content:encoded><category>c</category><category>livro</category><category>principios</category><category>tecnica</category></item><item><title>Feature flags: como proteger seu software de catástrofes</title><link>https://codamos.com.br/feature-flags/</link><guid isPermaLink="true">https://codamos.com.br/feature-flags/</guid><description>Recentemente o Codamos recebeu um artigo do Rouan Wilsenach sobre o conceito de Ship / Show / Ask , que basicamente diz que não faz muito sentido esperar seu time aprovar um Pull Request pra integrar </description><pubDate>Tue, 10 May 2022 13:46:34 GMT</pubDate><content:encoded>&lt;p&gt;Recentemente o Codamos recebeu &lt;a href=&quot;/entregar-mostrar-perguntar-branch-git/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;um artigo do Rouan Wilsenach sobre o conceito de Ship / Show / Ask&lt;/a&gt;, que basicamente diz que não faz muito sentido esperar seu time aprovar um &lt;em&gt;Pull Request&lt;/em&gt; pra integrar o seu código na maior parte das vezes.&lt;/p&gt;
&lt;p&gt;A intenção é boa, mas muitas de nós ainda fica com um pé atrás: como garantir a qualidade do software se o &lt;em&gt;Code Review&lt;/em&gt; acontece &lt;em&gt;depois&lt;/em&gt; de lançar pra produção?&lt;/p&gt;
&lt;p&gt;Neste artigo eu vou te apresentar uma técnica mágica que vai mudar para sempre a forma como você lida com código nas suas empresas: as feature flags!&lt;/p&gt;
&lt;div class=&quot;post__toc&quot;&gt;
&lt;h3&gt;Conteúdos do post&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1g2n1nodm70l&quot;&gt;O que é feature flag ou feature toggle?&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1g2n1nodm70m&quot;&gt;Exemplo de código&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1g2n1nodm70n&quot;&gt;Que problemas feature flags resolvem?&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1g2n1nodm70o&quot;&gt;Proteger lançamentos de produtos&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1g2n1nodm70p&quot;&gt;Realizar experimentos e testes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1g2n1nodm70q&quot;&gt;Proteger-se de catástrofes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1g2n1nodm70r&quot;&gt;Gerenciamento de permissões&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1g2n1nodm70s&quot;&gt;Que problemas feature flags criam?&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1g2n1nodm70t&quot;&gt;A complexidade dos testes é maior&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1g2n1nodm70u&quot;&gt;Depurar e reproduzir situações descritas em logs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1g2n1nodm70v&quot;&gt;Gerenciamento e governança de software&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1g2n1nodm710&quot;&gt;Como eu integro feature flags no meu software?&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1g2n1nodm711&quot;&gt;Pacotes pagos&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1g2n1nodm712&quot;&gt;Pacotes open source&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1g2n1nodm713&quot;&gt;Implementação própria&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1g2n1nodm714&quot;&gt;Conclusão&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id=&quot;mcetoc_1g2n1nodm70l&quot;&gt;O que é &lt;em&gt;feature flag&lt;/em&gt; ou &lt;em&gt;feature toggle&lt;/em&gt;?&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Feature flag&lt;/em&gt;, também conhecida por &lt;em&gt;feature toggle,&lt;/em&gt; é uma técnica que lhe permite proteger parte do seu código de forma dinâmica. É como se você pudesse colocar um interruptor no seu código, e só quando você virar a chave o novo código passa a valer.&lt;/p&gt;
&lt;p&gt;Na prática a feature flag te permite adicionar alguns &lt;em&gt;IFs&lt;/em&gt; no seu código, que vão executar uma ou outra lógica dependendo do estado desta &lt;em&gt;feature flag&lt;/em&gt;. Dá uma olhada no exemplo abaixo 👇!&lt;a href=&quot;https://www.youtube.com/watch?v=AD8LSdy7b2s&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1g2n1nodm70m&quot;&gt;Exemplo de código&lt;/h3&gt;
&lt;p&gt;Digamos que o método &lt;code&gt;Users.list()&lt;/code&gt; atualmente chama uma API rest no endpoint &lt;code&gt;/v1/users&lt;/code&gt; e o mantenedor desta API disse que a versão 2 está disponível através do endpoint &lt;code&gt;/v2/users&lt;/code&gt; e precisa ser adotada, ao final do mês a versão 1 será descontinuada.&lt;/p&gt;
&lt;p&gt;A migração parece bem simples e direta. Mas é sempre bom manter-se longe de problemas. Uma forma simples e livre de muitas preocupações para implementar esta mudança é através de uma &lt;em&gt;feature flag&lt;/em&gt;. Olha o exemplo abaixo:&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image post__image--center&quot; src=&quot;/media/posts/42/feature-flags.png&quot; alt=&quot;Código exemplificando a utilização de feature flags. Transcrição a seguir.&quot; width=&quot;1268&quot; height=&quot;1242&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Código exemplificando a utilização de feature flags. Transcrição a seguir.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;pre&gt;class Users:&lt;br&gt;  def list(self):&lt;br&gt;    if (isFeatureActive(&apos;enableUserListV2API&apos;):&lt;br&gt;      return self.listV2()&lt;br&gt;    else:&lt;br&gt;      return self.listV1()&lt;br&gt;&lt;br&gt;  def listV1():&lt;br&gt;    &quot;&quot;&quot;&lt;br&gt;    Call /v1/users&lt;br&gt;    &quot;&quot;&quot;&lt;br&gt;&lt;br&gt;  def listV2():&lt;br&gt;    &quot;&quot;&quot;&lt;br&gt;    Call /v2/users&lt;br&gt;    &quot;&quot;&quot;&lt;/pre&gt;
&lt;p&gt;A função &lt;code&gt;isFeatureActive()&lt;/code&gt; retorna TRUE or FALSE, e o ideal é que possamos configurar o retorno desta função. Talvez escrevendo num banco de dados, talvez escrevendo num arquivo...&lt;/p&gt;
&lt;p&gt;Acho que deu pra entender bem a ideia de &lt;em&gt;feature flag&lt;/em&gt; já. Vou deixar um vídeo (em inglês) abaixo que explica com palavras e imagens como &lt;em&gt;feature flags&lt;/em&gt; funcionam caso esteja interessade em se aprofundar no assunto.&lt;/p&gt;
&lt;p&gt;O interessante sobre este vídeo é exatamente a ideia de fazer deploy de forma intencional. A filosofia por trás disso é basicamente a mesma que eu mostrei no &lt;a href=&quot;/programacao-por-coincidencia/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;meu artigo sobre programação por coincidência X por intenção&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/AD8LSdy7b2s&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;allowfullscreen&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1g2n1nodm70n&quot;&gt;Que problemas feature flags resolvem?&lt;/h2&gt;
&lt;p&gt;De acordo com Pete Hodgson, num &lt;a href=&quot;https://martinfowler.com/articles/feature-toggles.html&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;artigo que publicou no blog do Martin Fowler&lt;/a&gt;, as feature flags resolvem diferentes categorias de problemas:&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1g2n1nodm70o&quot;&gt;Proteger lançamentos de produtos&lt;/h3&gt;
&lt;p&gt;As vezes a pessoa que faz a gerência de produto gostaria de testar o produto em produção algumas semanas ou dias antes de realizar o lançamento oficial. E o ideal seria poder lançar o produto sem que uma pessoa desenvolvedora esteja envolvida.&lt;/p&gt;
&lt;p&gt;De forma que uma &lt;em&gt;feature flag&lt;/em&gt; é a opção perfeita para resolver o caso acima. A pessoa desenvolvedora pode criar uma flag chamada &lt;code&gt;habilitarNovoCheckout&lt;/code&gt;, por exemplo, e utilizá-la em todo o código novo. A pessoa que gerencia o produto pode a qualquer momento ativar ou desativar o novo &lt;em&gt;checkout&lt;/em&gt; apenas apertando um botão liga/desliga numa interface.&lt;/p&gt;
&lt;p&gt;Algo assim:&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image post__image--center&quot; src=&quot;/media/posts/42/feature-flag-release-produto.png&quot; alt=&quot;Código exemplificando a utilização de feature flags para o lançamento de produtos. Transcrição a seguir.&quot; width=&quot;1254&quot; height=&quot;832&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Código exemplificando a utilização de feature flags para o lançamento de produtos. Transcrição a seguir.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;pre&gt;&amp;lt;CheckoutFlow&amp;gt;&lt;br&gt;  {&lt;br&gt;    isFeatureActive(&apos;habilitarNovoCheckout&apos;) ? (&lt;br&gt;      &amp;lt;NovoCheckoutFlow {...props} /&amp;gt;&lt;br&gt;    ) : (&lt;br&gt;      &amp;lt;AntigoCheckoutFlow {...props} /&amp;gt;&lt;br&gt;    )&lt;br&gt;  }&lt;br&gt;&amp;lt;/CheckoutFlow&amp;gt;&lt;/pre&gt;
&lt;h3 id=&quot;mcetoc_1g2n1nodm70p&quot;&gt;Realizar experimentos e testes&lt;/h3&gt;
&lt;p&gt;O bacana de &lt;em&gt;feature flags&lt;/em&gt; é que elas não precisam levar em consideração apenas o estado &lt;em&gt;ligado/desligado&lt;/em&gt;. A decisão sobre uma &lt;em&gt;feature flag&lt;/em&gt; estar ativa ou não pode ser bem mais complexa e levar em consideração elementos como:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Distribuição de tráfego&lt;/li&gt;
&lt;li&gt;ID / Sessão do usuário&lt;/li&gt;
&lt;li&gt;Localidade do usuário&lt;/li&gt;
&lt;li&gt;Data / Horário&lt;/li&gt;
&lt;li&gt;etc..&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;De forma que você pode configurar uma flag para estar ativa somente para usuários da cidade de São Paulo acessando o site aos finais de semana entre 10am e 3pm. Tudo depende da ferramenta que você utilizar para feature flags, mas acho que dá pra entender o potencial.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1g2n1nodm70q&quot;&gt;Proteger-se de catástrofes&lt;/h3&gt;
&lt;p&gt;Por mais que nós escrevamos código utilizando TDD, que façamos revisão de código com nossos pares, e adotemos um processo rígido de qualidade de software, nada garante que o nosso código não vá causar algum tipo de anomalia.&lt;/p&gt;
&lt;p&gt;Uma funcionalidade talvez acabe sendo tão popular que muito mais pessoas do que o esperado a querem utilizar, aumento a carga no servidor. Ou talvez você tenha reparado que um algoritmo não está fazendo &lt;em&gt;exatamente&lt;/em&gt; o que deveria.&lt;/p&gt;
&lt;p&gt;Ao notar um problema desta dimensão, você pode facilmente desligar uma &lt;em&gt;feature flag&lt;/em&gt; e investigar a solução de forma controlada. Sem precisar reverter algum &lt;em&gt;deployment&lt;/em&gt; ou, pior ainda, um &lt;em&gt;commit&lt;/em&gt;.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1g2n1nodm70r&quot;&gt;Gerenciamento de permissões&lt;/h3&gt;
&lt;p&gt;Algumas funcionalidades precisam ficar protegidas. E os sistemas de ACL nem sempre são suficientes.&lt;/p&gt;
&lt;p&gt;Por exemplo, digamos que a área de gerenciamento da sua plataforma precise ser acessada &lt;em&gt;somente&lt;/em&gt; por computadores dentro da VPN da empresa. Uma &lt;em&gt;feature flag&lt;/em&gt; que verifica a origem do IP pode facilmente resolver esta verificação sem nenhuma adição ao seu &lt;em&gt;framework&lt;/em&gt; de ACL.&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1g2n1nodm70s&quot;&gt;Que problemas feature flags criam?&lt;/h2&gt;
&lt;p&gt;Como você já deve ter imaginado, feature flags adicionam complexidade ao seu código. Ainda mais considerando que você pretende testar seus códigos, certo?&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1g2n1nodm70t&quot;&gt;A complexidade dos testes é maior&lt;/h3&gt;
&lt;p&gt;Vejamos o snippet abaixo:&lt;/p&gt;
&lt;pre&gt;function sumPositive(int|float a, int|float b): int|float&lt;br&gt;{&lt;br&gt;  if (typeof(a) !== typeof(b):&lt;br&gt;    raise &quot;Cannot add an integer to a float&quot;&lt;br&gt;  return a + b&lt;br&gt;}&lt;/pre&gt;
&lt;p&gt;Eu esperaria ver ao menos três testes para esta função, de forma a cobrir os seguintes casos:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Soma de dois inteiros&lt;/li&gt;
&lt;li&gt;Soma de dois floats&lt;/li&gt;
&lt;li&gt;Lançamento de exceção&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Se nós adicionar uma &lt;em&gt;feature flag&lt;/em&gt; que nos impede de somar números negativos, o código rapidamente se transformaria em algo assim:&lt;/p&gt;
&lt;pre&gt;function sumPositive(int|float a, int|float b): int|float&lt;br&gt;{&lt;br&gt;  if (typeof(a) !== typeof(b):&lt;br&gt;    raise &quot;Cannot add an integer to a float&quot;&lt;br&gt;&lt;br&gt;  # New code&lt;br&gt;  if (isFeatureActive(&apos;disableNegativesSum&apos;) &amp;amp;&amp;amp; (a &amp;lt; 0 || b &amp;lt; 0)):&lt;br&gt;    raise &quot;Summing negative numbers is not allowed&quot;&lt;br&gt;&lt;br&gt;  return a + b&lt;br&gt;}&lt;/pre&gt;
&lt;p&gt;Ao adicionar uma feature flag nós precisamos agora adicionar dois outros testes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;O comportamento quando a feature flag está inativa&lt;/li&gt;
&lt;li&gt;O comportamento quando a feature flag está ativa&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;mcetoc_1g2n1nodm70u&quot;&gt;Depurar e reproduzir situações descritas em &lt;em&gt;logs&lt;/em&gt;&lt;/h3&gt;
&lt;p&gt;A complexidade se reflete não somente nos testes, mas também ao depurar uma determinada chamada de método ou página.&lt;/p&gt;
&lt;p&gt;Além disso, olhando apenas para os &lt;em&gt;logs&lt;/em&gt; de acesso não é tão simples identificar se uma determinada flag estava ativa no momento ou não.&lt;/p&gt;
&lt;p&gt;Com o tempo, é ideal remover as &lt;em&gt;feature flags&lt;/em&gt; que já não têm mais nenhuma utilidade. A cada vez que você cria uma &lt;em&gt;feature flag&lt;/em&gt; nova, você está também criando um novo caminho em seu software que precisará ser limpo depois.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1g2n1nodm70v&quot;&gt;Gerenciamento e governança de software&lt;/h3&gt;
&lt;p&gt;O mau gerenciamento de feature flags pode explodir seu software em complexidade e dificultar a manutenção deste ao longo do tempo se a sua equipe não limpar estas flags frequentemente.&lt;/p&gt;
&lt;p&gt;Portanto ao criar uma &lt;em&gt;feature flag&lt;/em&gt; nova é ideal sempre ter em mente quando e como você pretende se livrar desta flag.&lt;/p&gt;
&lt;p&gt;Aqui onde eu trabalho, uma das técnicas que a gente adota pra limpar &lt;em&gt;feature flags&lt;/em&gt; é gerar um &lt;em&gt;dashboard&lt;/em&gt; que mostra todas as flags ativas por data e com a possibilidade de marcar cada flag como &quot;pronta para ser removida&quot;. Com base neste dashboard a gente consegue escrever tarefas para fazer esta limpeza.&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1g2n1nodm710&quot;&gt;Como eu integro feature flags no meu software?&lt;/h2&gt;
&lt;p&gt;Algumas empresas – onde eu trabalho, por exemplo – preferem criar o próprio software de gerenciamento de feature flags. Outras adotam soluções de mercado já prontas, e outras ainda preferem utilizar plataformas de código aberto.&lt;/p&gt;
&lt;p&gt;As três formas de implementação são validas e você precisa entender bem qual o caso de uso que você precisa cobrir.&lt;/p&gt;
&lt;p&gt;Migrar de uma solução para outra é relativamente simples, dado que o código normalmente vai chamar uma função ou método chamado &lt;code&gt;isFeatureActive()&lt;/code&gt; ou alguma coisa assim.&lt;/p&gt;
&lt;p&gt;O único desafio numa migração é justamente mover os dados de uma solução para outra e manter os SDKs compatíveis.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1g2n1nodm711&quot;&gt;Pacotes pagos&lt;/h3&gt;
&lt;p&gt;O bacana de usar uma solução paga é que normalmente tudo já funciona sem precisar configurar muita coisa, e normalmente as empresas oferecem suporte.&lt;/p&gt;
&lt;p&gt;O que eu acho particularmente zoado é que no evento de um ataque à plataforma paga, o seu software pode ficar parcialmente disponível ou, pior ainda, ter o comportamento aleatoriamente bagunçado.&lt;/p&gt;
&lt;p&gt;Plataformas conhecidas de gerenciamento de feature flags incluem &lt;a href=&quot;https://launchdarkly.com/features/feature-flags&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;LaunchDarkly™&lt;/a&gt; e &lt;a href=&quot;https://www.optimizely.com/products/intelligence/full-stack-experimentation/&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;Optimizely&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1g2n1nodm712&quot;&gt;Pacotes open source&lt;/h3&gt;
&lt;p&gt;Pacotes de código aberto são uma ótima opção porque normalmente exigem pouca configuração/preparo. Mas adiciona complexidade à sua infraestrutura que precisa de constante manutenção.&lt;/p&gt;
&lt;p&gt;Dentre os pacotes mais conhecidos estão o &lt;a href=&quot;https://www.getunleash.io/feature-management&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;Unleash&lt;/a&gt; e &lt;a href=&quot;https://www.flippercloud.io/docs&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;Flipper&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1g2n1nodm713&quot;&gt;Implementação própria&lt;/h3&gt;
&lt;p&gt;A implementação própria normalmente parece a melhor opção durante os primeiros meses/anos. O motivo é que no começo você provavelmente vai identificar vários casos de uso complexos que são muito específicos do domínio da aplicação.&lt;/p&gt;
&lt;p&gt;Com o tempo, o número de alterações no software de gerenciamento de flags vai diminuir até o ponto em que este pedaço de software entra em modo de manutenção.&lt;/p&gt;
&lt;p&gt;Neste momento eu acho que faz muito mais sentido procurar uma solução paga ou de código aberto, para substituir a implementação própria.&lt;/p&gt;
&lt;p&gt;O problema de uma implementação própria é que a partir do momento que ela não dá mais problemas, dificilmente a empresa irá revisitar a implementação, corrigir bugs ou identificar problemas de segurança.&lt;/p&gt;
&lt;p&gt;Um serviço pago ou de código aberto te fornece atualizações constantes e melhorias no software.&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1g2n1nodm714&quot;&gt;Conclusão&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Feature flag &lt;/em&gt;é uma técnica incrível para proteger seu código de diferentes formas: lançamento de produtos independente do envolvimento de pessoas desenvolvedoras, proteger e recuperar de catástrofes e remover completamente a necessidade de &lt;em&gt;Pull Requests &lt;/em&gt;antes de lançar o código para produção usando o processo &lt;a href=&quot;/entregar-mostrar-perguntar-branch-git/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Ship / Show / Ask&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Utilizar feature flags aumenta a sua flexibilidade, mas vem com um custo alto de manutenção.&lt;/p&gt;
&lt;p&gt;Por fim, este é um dos passos essenciais para a tão sonhada Integração e Entrega Contínua (CI/CD). Sem um bom monitoramento e ferramentas para forçar curto-circuitos (como &lt;em&gt;feature flags&lt;/em&gt; lhe permitem), CI/CD pode ser extremamente perigoso.&lt;/p&gt;</content:encoded><category>produtividade</category><category>tecnica</category></item><item><title>Pokémãobr ensina: como atrair tech recruiters</title><link>https://codamos.com.br/como-atrair-tech-recruiters/</link><guid isPermaLink="true">https://codamos.com.br/como-atrair-tech-recruiters/</guid><description>E ai, tudo beleza contigo? Pokemaobr aqui novamente com mais um tópico para você que está em busca do seu primeiro emprego como dev, ou até mesmo para você que quer novidades e mudar de ares na sua ca</description><pubDate>Sun, 24 Apr 2022 17:16:09 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;E ai, tudo beleza contigo? Pokemaobr aqui novamente com mais um tópico para você que está em busca do seu primeiro emprego como dev, ou até mesmo para você que quer novidades e mudar de ares na sua carreira.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;No início da carreira é normal a pessoa desenvolvedora ir atrás das vagas, entrar em processos seletivos demorados, com muitas etapas e no desespero de realmente conseguir a bendita vaga e poder iniciar sua trajetória como dev.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Mas, caso você analise algumas pessoas devs, principalmente do twitter do linkedIn, encontra muita gente reclamando, inclusive, da quantidade de recrutadores que entram em contato (muitos deles com vagas que não fazem nenhum sentido para com stack de desenvolvimento para quem oferecem).&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;No artigo de hoje irei falar um pouco sobre o que você pode fazer para estar mais próximo desses recrutadores e consequentemente conseguir vagas sem precisar tanto correr atrás.&lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;Participe de uma comunidade de desenvolvimento&lt;/h2&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;A primeira coisa que indico para pessoas que querem entrar e/ou migrar para a área de desenvolvimento é que participem de uma comunidade. No Brasil em geral, cada estado possui uma comunidade local das linguagens mais utilizadas.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Caso você use PHP, temos: PHPSP, ou PHPRio, ou PHP com rapadura, PHPWomen, etc. Se você é de python temos os Grupys, o pyladies. Se você é de Ruby os Gurus, RailsGirls, etc. Então, indico e muito você procurar essas comunidades para entender como funciona o ecossistema das linguagens que você quer começar desenvolver.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;O Nawarian recentemente escreveu &lt;a href=&quot;/comunidades-de-desenvolvimento-de-software-brasileiras/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;um artigo que lista comunidades de desenvolvimento brasileiras&lt;/a&gt;, presenciais e online.&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Esse tipo de networking é muito legal quando está se conhecendo o ambiente que permeia. As pessoas que participam em geral tem uma experiência legal e podem te adiantar algumas características que você vai perceber um pouco mais para a frente sobre como funciona até mesmo a parte de contratação para a stack daquela linguagem, bem como as ferramentas mais utilizadas, frameworks, etc.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Com a pandemia muitos dos encontros passaram a ser online, o que facilita você participar de algum desses grupos mesmo não estando no mesmo estado ou cidade do grupo. Sempre que há encontros existem pessoas que vão para tentar recrutar ou oferecer vagas nas empresas que trabalham.&lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;Apareça nas redes sociais&lt;/h2&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Um passo importante para que recrutadores encontrem você, é exatamente poderem te encontrar. E para isso, você deve ser uma pessoa fácil de encontrar. Estar nas redes sociais, faz com que você esteja em uma posição mais acessível e com isso, facilita a comunicação e diminui a distância de uma possível vaga, ou até mesmo de algum contato para um desenvolvimento pontual.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Para devs, eu indico muito o twitter como uma das principais redes sociais. Engajar bons conteúdos lá fazem com que você possa atingir um número interessante de pessoas e que você possa até mesmo ser relevante na #bolhadev (o modo que chamamos um grupo aleatório de desenvolvedores que criam conteúdo e/ou interagem com outras pessoas devs no twitter).&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Para o twitter em específico, eu indico que você não consuma todo tipo de conteúdo de lá. Existe o que chamamos de tretas dev, que são literalmente cagações de regra (alguém que puxa um tema polêmico afirmando alguma coisa que muitas das vezes não faz o menor sentido) que só servem para criar um ambiente tóxico e unir pessoas tóxicas em torno de temas que se repetem de tempos em tempos.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Porém, você pode silenciar ou bloquear as pessoas que incitam esse tipo de conteúdo e utilizar a rede social de uma maneira fluida. Eu por exemplo tenho mais de 9000 seguidores e consigo muitas coisas legais usando o twitter. Inclusive fiz um vídeo&lt;/span&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt; para ajudar as pessoas a crescerem utilizando essa rede social. Também desenvolvi uma &lt;/span&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;&lt;a href=&quot;https://dev.to/acaverna/utilizando-a-bolha-dev-ao-seu-favor-na-busca-do-seu-primeiro-emprego-15cf&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;estratégia para você conseguir o seu primeiro emprego dev&lt;/a&gt; utilizando a força da #bolhadev.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/zZIM3lTwEkY&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;allowfullscreen&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Outra rede social que eu indico para fins profissionais é o linkedIn. Embora particularmente não tenho dado tanta atenção para essa rede (devido a quantidade infinita de posts caça interação e a incrível corja de pseudo coaches que fazem qualquer ação cotidiana virar um post de auto-ajuda).&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Mesmo assim, uma grande quantidade de recrutadores utilizam essa rede social. Então, ter uma conta lá com a descrição de seus últimos trabalhos, estudos e coisas do tipo é interessante para você receber contato dessas pessoas.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Para ajudar a você a melhorar a qualidade do seu linkedIn, o Nawarian escreveu &lt;/span&gt;&lt;a href=&quot;/guia-definitivo-perfil-profissional-linkedin-passo-a-passo/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;esse &lt;/span&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;artigo aqui&lt;/span&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;, onde em 12 passos você pode melhorar o seu perfil.&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Outra coisa que sempre falo para a galera dev verificar é o que aparece quando você pesquisa o seu nome ou nick no Google, dependendo do que tiver como resultado, isso pode ajudar a entender como as pessoas recrutadoras podem encontrar você.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Sobre instagram, sinceramente… deixa pra lá…&lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;Tenha projetos no seu github&lt;/h2&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Uma maneira das pessoas devs mostrarem um pouco do que são capazes de fazer para o mundo é através de projetos de código e, uma ferramenta muito importante para o compartilhamento de código entre devs é o github.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Aí você me pergunta… Pokemãooo, mas é obrigatório toda pessoa dev ter um github e projetos relevantes lá? NÃO. Porém, ter códigos lá facilita e muito para pessoas recrutadoras entenderem com que tipo de stack você desenvolve, o que você compartilha de código com as pessoas e até mesmo ter uma ideia do seu nível de desenvolvimento.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;No meu github coloco projetos que desenvolvo nas lives, tenho fork de projetos open-source que utilizo, ajudo em repositórios de conteúdo, entre outras coisas. Caso você não saiba que tipo de projetos desenvolver para deixar no seu github, escrevi esse &lt;/span&gt;&lt;a href=&quot;https://dev.to/acaverna/sou-iniciante-em-desenvolvimento-que-projetos-devo-fazer-no-meu-github-4611&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;artigo aqui&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Já conheci pessoas que conseguiram empregos em projetos open-source simplesmente porque eram as pessoas que mais contribuíam naqueles projetos sem receber.&lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;Faça um site pessoal e/ou mantenha um blog ou produza algo em algum site de conteúdo&lt;/h2&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Outra coisa que pode te ajudar e muito para recrutadores te encontrarem é a produção de conteúdo. Algumas vezes já fui contactado por pessoas que precisavam de alguma skill específica em uma biblioteca, por exemplo, simplesmente por ter feito um artigo sobre aquele tema.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Um site pessoal, por exemplo, pode ter o compilado de todos os links que remetem a seus perfis, o que facilita a comunicação de recrutadores para você. Além de você poder usá-lo como portfólio.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Blogs pessoais fazem com que você aprenda mais e tenha um repositório de fácil acesso sobre o conteúdo que você produz. Além de poder ter algum controle sobre as pessoas que consomem o mesmo.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Caso você tenha interesse, convido você que está lendo esse artigo à escrever e publicar aqui no Codamos&lt;/span&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt; também. É legal você ganhar uma visibilidade com seus artigos dentro da comunidade brasileira, além de receber suporte na revisão de textos, temas e etc. Se quiser saber como publicar: &lt;/span&gt;&lt;a href=&quot;https://github.com/codamos-com-br/&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;https://github.com/codamos-com-br/&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;De qualquer jeito, produzir conteúdo faz com que mais pessoas saibam da sua existência e tenham alguma idéia sobre sua experiência com desenvolvimento, o que facilita em caso de procurarem pessoas com as suas skills.&lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;Participe de eventos&lt;/h2&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Para finalizar, só tenho que falar para você participar de eventos. Organizo eventos de TI desde 2012 e a cada ano que passa mais empresas querem patrocinar os eventos apenas para atingir um número maior de devs e oferecer vagas de emprego.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Esteja lá, seja palestrando e compartilhando conhecimento, ou consumindo conteúdo e visitando os stands das empresas que patrocinam. Quem sabe você não sai do próximo evento já com um emprego?&lt;/span&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Desejo que tenha curtido esse artigo. Caso tenha alguma dúvida pode entrar em contato comigo no contato@pokemaobr.dev ou na minha live: &lt;/span&gt;&lt;a href=&quot;https://twitch.tv/pokemaobr&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;https://twitch.tv/pokemaobr&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt; ou no twitter:&lt;/span&gt;&lt;a href=&quot;https://twitter.com/pokemaobr&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt; https://twitter.com/pokemaobr&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt; ! Deixa aqui o seu comentário sobre o que foi escrito. Obrigado de coração e até a próxima.&lt;/span&gt;&lt;/p&gt;</content:encoded><category>carreira</category><category>junior</category><category>pokemaobr</category><category>vagas</category></item><item><title>Comunidades de desenvolvimento de software brasileiras</title><link>https://codamos.com.br/comunidades-de-desenvolvimento-de-software-brasileiras/</link><guid isPermaLink="true">https://codamos.com.br/comunidades-de-desenvolvimento-de-software-brasileiras/</guid><description>Eu recentemente perguntei nas minhas redes quais as comunidades de desenvolvimento de software brasileiras que a galera conhece e participa. Galeru, quais comunidades de desenvolvimento vocês conhecem</description><pubDate>Tue, 12 Apr 2022 12:03:39 GMT</pubDate><content:encoded>&lt;p&gt;Eu recentemente perguntei nas minhas redes quais as comunidades de desenvolvimento de software brasileiras que a galera conhece e participa.&lt;/p&gt;
&lt;blockquote class=&quot;twitter-tweet&quot;&gt;
&lt;p dir=&quot;ltr&quot; lang=&quot;pt&quot;&gt;Galeru, quais comunidades de desenvolvimento vocês conhecem e/ou participam? Marca aqui plz? É pro meu TCC 👀&lt;br&gt;&lt;br&gt;Eu começo: &lt;a href=&quot;https://twitter.com/phpsp?ref_src=twsrc%5Etfw&quot;&gt;@phpsp&lt;/a&gt; &amp;lt;3&lt;br&gt;&lt;br&gt;cc/ &lt;a href=&quot;https://twitter.com/sseraphini?ref_src=twsrc%5Etfw&quot;&gt;@sseraphini&lt;/a&gt;&lt;/p&gt;
— Níckolas Da Silva (nawarian) (@nawarian) &lt;a href=&quot;https://twitter.com/nawarian/status/1509289706823028736?ref_src=twsrc%5Etfw&quot;&gt;March 30, 2022&lt;/a&gt;&lt;/blockquote&gt;
&lt;p&gt;
&lt;script async=&quot;&quot; src=&quot;https://platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;
&lt;/p&gt;
&lt;p&gt;Esta lista aqui é um compilado das comunidades que foram listadas naquele tweet. Caso a sua comunidade não esteja representada neste artigo, vai lá e comenta no tweet que eu atualizo esta página 😉.&lt;/p&gt;
&lt;h2&gt;O que é uma comunidade desenvolvimento de software?&lt;/h2&gt;
&lt;p&gt;No Brasil, comunidades têm um significado muito especial. São grupos de pessoas que se ajudam, se encontram, se envolvem e em que todo mundo cresce!&lt;/p&gt;
&lt;p&gt;Eu digo que no Brasil isso tem um significado muito especial porque em outros países é comum que comunidades de desenvolvimento sejam apenas grupos pra falar do mesmo tópico e talvez fazer algum networking.&lt;/p&gt;
&lt;p&gt;Já em comunidades brasileiras eu noto muito a criação de grupos de apoio, iniciativas inclusivas, mentoria, troca de experiência, mutirões e etc.. Comunidades brasileiras, na minha opinião, são mais... comunitárias.&lt;/p&gt;
&lt;h2&gt;Como uma comunidade de desenvolvimento de software pode te ajudar?&lt;/h2&gt;
&lt;p&gt;Profissionais de software de todos os níveis têm muito a ganhar ao participar de comunidades: iniciantes ganham exposição a ideias e discussões de alto nível, enquanto pessoas mais experientes trocam entre si e ganham experiência como mentoras.&lt;/p&gt;
&lt;p&gt;Além disso, participar de comunidades te permite expandir a sua rede de contatos, ganhar notoriedade e contratar ou ser contratada.&lt;/p&gt;
&lt;p&gt;Ao frequentar espaços de comunidade, a pessoa desenvolvedora &lt;strong&gt;ganha experiência, sabedoria, descobre tecnologias novas, resolve problemas, faz boas amizades e expande sua rede de contatos e oportunidades.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;As comunidades de programação do Brasil&lt;/h2&gt;
&lt;p&gt;Como eu mencionei acima, aqui eu vou deixar uma lista das comunidades brasileiras que foram citadas no Tweet.&lt;/p&gt;
&lt;p class=&quot;msg msg--success&quot;&gt;Caso queira adicionar alguma comunidade a esta lista, &lt;a href=&quot;https://twitter.com/nawarian/status/1509289706823028736&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;responda este tweet&lt;/a&gt; com o link para o site e eu vou adicionar aqui assim que possível 📝&lt;/p&gt;
&lt;h3&gt;Feministech - representatividade em tech&lt;/h3&gt;
&lt;p&gt;&lt;img class=&quot;post__image post__image--left&quot; src=&quot;/media/posts/38/feministech-logo.webp&quot; alt=&quot;&quot; width=&quot;300&quot; height=&quot;300&quot;&gt;&lt;/p&gt;
&lt;p&gt;A comunidade Feministech foi criada em 2020 e é um grupo de pessoas que se identificam no feminino e não-bináries e que produzem, consomem e compartilham conteúdo sobre tech num ambiente diverso e inclusivo.&lt;/p&gt;
&lt;p&gt;O maior objetivo desta comunidade é aumentar a representatividade de pessoas femininas e não-binárias, oferecendo auxílio, incentivo e espaço para &lt;em&gt;live codings&lt;/em&gt;, vídeos, artigos, palestras, &lt;em&gt;podcasts&lt;/em&gt; e eventos de tecnologia. Os principais links para se envolver com esta comunidade você encontra na tabela abaixo.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; display: inline-table;&quot; border=&quot;1&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Comunidade&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Feministech&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Local&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Online&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Foco&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Diversidade, inclusão e representatividade em tech&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Código de conduta&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;&lt;a href=&quot;https://github.com/feministech/codigo-de-conduta&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;Link para o COC&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Site oficial&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;&lt;a href=&quot;https://feministech.github.io/&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;feministech.github.io&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Blog&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;&lt;a href=&quot;https://dev.to/feministech&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;dev.to/feministech&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Github&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;&lt;a href=&quot;https://github.com/feministech&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;@feministech&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Twitch&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;&lt;a href=&quot;https://www.twitch.tv/team/livecodergirls&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;team/livecodergirls&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Podcast&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;&lt;a href=&quot;https://anchor.fm/feministech&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;@feministech&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Redes&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Twitter: &lt;a href=&quot;https://twitter.com/feminis_tech&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;@feminis_tech&lt;/a&gt;&lt;br&gt;LinkedIn: &lt;a href=&quot;https://www.linkedin.com/company/feministech/&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;company/feministech/&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;PHPSP - Grupo de usuários PHP do Estado de São Paulo&lt;/h3&gt;
&lt;p&gt;&lt;img class=&quot;post__image post__image--left&quot; src=&quot;/media/posts/38/phpsp-logo-2.png&quot; alt=&quot;&quot; width=&quot;300&quot; height=&quot;102&quot;&gt;&lt;/p&gt;
&lt;p&gt;A comunidade PHPSP existe desde 2009 e é &lt;strong&gt;um dos grupos de usuários da linguagem PHP mais expressivos no Brasil.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A comunidade nasceu na capital &lt;em&gt;sampa&lt;/em&gt; e se espalha por todo o estado de São Paulo.&lt;/p&gt;
&lt;p&gt;Esta comunidade oferece alguns &lt;strong&gt;canais online para discussão e organiza eventos.&lt;/strong&gt; Desde que a pandemia começou os eventos passaram a ser online, mas o PHPSP já organizou diversos eventos e conferências presenciais.&lt;/p&gt;
&lt;p&gt;O principal evento do PHPSP, chamado &lt;strong&gt;PHPSP + Pub, ocorre toda segunda quinta-feira do mês&lt;/strong&gt; com a intenção de unir pessoas desenvolvedoras de software numa roda de conversa descontraída com comes e bebes, e muita piada nerd.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; display: inline-table;&quot; border=&quot;1&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 34.0942%;&quot;&gt;Comunidade&lt;/td&gt;
&lt;td style=&quot;width: 65.9058%;&quot;&gt;PHPSP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 34.0942%;&quot;&gt;Local&lt;/td&gt;
&lt;td style=&quot;width: 65.9058%;&quot;&gt;São Paulo, SP e online&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 34.0942%;&quot;&gt;Foco&lt;/td&gt;
&lt;td style=&quot;width: 65.9058%;&quot;&gt;Linguagem PHP, &lt;em&gt;networking&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 34.0942%;&quot;&gt;Código de conduta&lt;/td&gt;
&lt;td style=&quot;width: 65.9058%;&quot;&gt;&lt;a href=&quot;https://phpsp.org.br/codigo-de-conduta/&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;Link para o COC&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 34.0942%;&quot;&gt;Site oficial&lt;/td&gt;
&lt;td style=&quot;width: 65.9058%;&quot;&gt;&lt;a href=&quot;https://phpsp.org.br&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;phpsp.org.br&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 34.0942%;&quot;&gt;Canal do Slack&lt;/td&gt;
&lt;td style=&quot;width: 65.9058%;&quot;&gt;&lt;a href=&quot;https://bit.ly/vem-pro-slack-phpsp&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;Link para o convite&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 34.0942%;&quot;&gt;Canal no Telegram&lt;/td&gt;
&lt;td style=&quot;width: 65.9058%;&quot;&gt;&lt;a href=&quot;https://t.me/phpsp&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;@phpsp&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 34.0942%;&quot;&gt;Github&lt;/td&gt;
&lt;td style=&quot;width: 65.9058%;&quot;&gt;&lt;a href=&quot;https://github.com/phpsp&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;@phpsp&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 34.0942%;&quot;&gt;Youtube&lt;/td&gt;
&lt;td style=&quot;width: 65.9058%;&quot;&gt;&lt;a href=&quot;https://www.youtube.com/c/PHPSP&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;@PHPSP&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 34.0942%;&quot;&gt;Meetup&lt;/td&gt;
&lt;td style=&quot;width: 65.9058%;&quot;&gt;&lt;a href=&quot;https://www.meetup.com/php-sp/&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;@php-sp&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 34.0942%;&quot;&gt;Redes&lt;/td&gt;
&lt;td style=&quot;width: 65.9058%;&quot;&gt;Twitter: &lt;a href=&quot;https://twitter.com/phpsp&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;@phpsp&lt;/a&gt;&lt;br&gt;LinkedIn: &lt;a href=&quot;https://www.linkedin.com/company/phpsp---php-user-group-in-s-o-paulo/&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;company/phpsp&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;PerifaCode - a comunidade de programação da periferia&lt;/h3&gt;
&lt;p&gt;&lt;img class=&quot;post__image post__image--left&quot; src=&quot;/media/posts/38/perifacode-logo.jpeg&quot; alt=&quot;&quot; width=&quot;300&quot; height=&quot;300&quot;&gt;&lt;/p&gt;
&lt;p&gt;O perifaCode é uma comunidade voltada para criar uma rede de apoio a pessoas que moram nas periferias, favelas e guetos do Brasil inteiro.&lt;/p&gt;
&lt;p&gt;A missão dessa comunidade é inserir pessoas de origem periférica na área de tecnologia.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; display: inline-table;&quot; border=&quot;1&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Comunidade&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;perifaCode&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Local&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Online&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Foco&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Desenvolvimento de software, apoio às pessoas periféricas do Brasil&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Manifesto&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;&lt;a href=&quot;https://perifacode.com/manifesto/&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;Link para o manifesto&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Código de conduta&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;&lt;a href=&quot;https://perifacode.com/COC/&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;Link para o COC&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Site oficial&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;&lt;a href=&quot;https://perifacode.com/&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;perifacode.com&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Servidor Discord&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;&lt;a href=&quot;https://docs.google.com/forms/d/e/1FAIpQLSd9ptSntk4FklmD-Lb0B0C6KL2xgijym2jx1G-FQVw8IIvxYQ/viewform&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;Link para o convite&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Github&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;&lt;a href=&quot;https://github.com/perifacode&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;@perifacode&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Redes&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Twitter: &lt;a href=&quot;https://twitter.com/perifacode&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;@perifacode&lt;/a&gt;&lt;br&gt;Instagram: &lt;a href=&quot;https://www.instagram.com/perifacode/&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;@perifacode&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;PHP Rio - Grupo de usuários PHP do Estado do Rio de Janeiro&lt;/h3&gt;
&lt;p&gt;&lt;img class=&quot;post__image post__image--left&quot; src=&quot;/media/posts/38/phprio-logo.png&quot; alt=&quot;&quot; width=&quot;300&quot; height=&quot;243&quot;&gt;&lt;/p&gt;
&lt;p&gt;O PHP Rio existe desde 2016 e foca em todo o estado do Rio de Janeiro.&lt;/p&gt;
&lt;p&gt;A comunidade PHP Rio tem presença nas redes sociais, eventos da comunidade brasileira de PHP e oferece &lt;em&gt;meetups&lt;/em&gt; mensais com cerveja, tecnologia e gente massa!&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; display: inline-table;&quot; border=&quot;1&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Comunidade&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;PHP Rio&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Local&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Rio de Janeiro, RJ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Foco&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Linguagem PHP, &lt;em&gt;networking&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Código de conduta&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;&lt;a href=&quot;http://php.rio/codigo-de-conduta/&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;Link para o código de conduta&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Site oficial&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;&lt;a href=&quot;https://php.rio/&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;php.rio&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Canal no Telegram&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;&lt;a href=&quot;https://telegram.me/phprio&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;@phprio&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Github&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;&lt;a href=&quot;https://github.com/PHPRio&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;@PHPRio&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Meetup&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;&lt;a href=&quot;https://meetup.com/PHP-Rio&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;@PHP-Rio&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Redes&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Twitter: &lt;a href=&quot;https://twitter.com/phprio&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;@phprio&lt;/a&gt;&lt;br&gt;LinkedIn: &lt;a href=&quot;https://www.linkedin.com/groups/1202577&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;link para o grupo&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;He4rt developers&lt;/h3&gt;
&lt;p&gt;&lt;img class=&quot;post__image post__image--left&quot; src=&quot;/media/posts/38/logo-he4rt2.png&quot; alt=&quot;&quot; width=&quot;300&quot; height=&quot;97&quot;&gt;He4rt developers é uma comunidade 100% online que tem como filosofia o ensino, tecnologia e pessoas.&lt;/p&gt;
&lt;p&gt;A comunidade procura oferecer apoio, inclusão e evolução de quem participa de forma colaborativa.&lt;/p&gt;
&lt;p&gt;A comunidade se concentra num servidor do Discord e marca presença em diversas redes sociais.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; display: inline-table;&quot; border=&quot;1&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Comunidade&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;He4rt devs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Local&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Online&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Foco&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Desenvolvimento de software&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Site oficial&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;&lt;a href=&quot;https://heartdevs.com/&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;heartdevs.com&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Servidor Discord&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;&lt;a href=&quot;https://discord.com/invite/5kwDQuv&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;Link para o convite&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Github&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;&lt;a href=&quot;https://github.com/he4rt&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;@he4rt&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Redes&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Twitter: &lt;a href=&quot;https://twitter.com/He4rtDevs&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;@He4rtDevs&lt;/a&gt;&lt;br&gt;Instagram: &lt;a href=&quot;https://www.instagram.com/heartdevs/&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;@heartdevs&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;BeeStrong Code 💛&lt;/h3&gt;
&lt;p&gt;&lt;img class=&quot;post__image post__image--left&quot; src=&quot;/media/posts/38/logo-beestrong-code.png&quot; alt=&quot;&quot; width=&quot;300&quot; height=&quot;300&quot;&gt;&lt;/p&gt;
&lt;p&gt;A comunidade BeeStrong Code nasceu organicamente em 2022, como um passo natural para suportar uma grande quantidade de profissionais mulheres e não bináries concentradas em grupos de whatsapp.&lt;/p&gt;
&lt;p&gt;O objetivo da comunidade BeeStrong é oferecer uma rede de apoio para mulheres e pessoas sem gênero que trabalham ou queiram trabalhar com tecnologia, considerando todas as suas necessidades.&lt;/p&gt;
&lt;p&gt;Hoje a comunidade conta com mais de 600 pessoas num servidor de Discord, e já está planejando os primeiros minicursos sobre LinkedIn, Github e Currículo.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; display: inline-table;&quot; border=&quot;1&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Comunidade&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;BeeStrong Code 💛&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Local&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Online&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Foco&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Rede de apoio para mulheres e pessoas sem gênero&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Site oficial&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;&lt;a href=&quot;https://linktr.ee/BeeStrongcode&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;Linktree&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Github&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;&lt;a href=&quot;https://github.com/BeeStrong-code&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;@BeeStrong-code&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Servidor Discord&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;&lt;a href=&quot;https://discord.com/invite/v5kQp7rh7x&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;Link para o convite&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Redes&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Twitter: &lt;a href=&quot;https://twitter.com/BeeStrongcode&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;@BeeStrongcode&lt;/a&gt;&lt;br&gt;Instagram: &lt;a href=&quot;https://www.instagram.com/beestrongcode/&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;@beestrongcode&lt;/a&gt;&lt;br&gt;LinkedIn: &lt;a href=&quot;https://www.linkedin.com/company/beestrongcode/&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;company/beestrongcode&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;TOTVs Developers&lt;/h3&gt;
&lt;p&gt;&lt;img class=&quot;post__image post__image--left&quot; src=&quot;/media/posts/38/totvsdev-logo.jpeg&quot; alt=&quot;&quot; width=&quot;300&quot; height=&quot;300&quot;&gt;&lt;/p&gt;
&lt;p&gt;A comunidade TOTVS Developers foca em disseminar conhecimento e boas práticas em programação.&lt;/p&gt;
&lt;p&gt;Eles apoiam outras comunidades disponibilizando local para eventos, comida, brindes, auxílio na curadoria de eventos presenciais e ferramentas para execução de eventos online.&lt;/p&gt;
&lt;p&gt;TOTVS Developers também realiza &lt;em&gt;meetups&lt;/em&gt; em São Paulo. Abaixo a tabela com detalhes para se envolver com a comunidade.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; display: inline-table;&quot; border=&quot;1&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Comunidade&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Totvs developers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Local&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;São Paulo, SP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Foco&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Disseminar conhecimento e boas práticas em programação&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Site oficial&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;&lt;a href=&quot;https://developers.totvs.com/&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;developers.totvs.com&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Github&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;&lt;a href=&quot;https://github.com/totvs&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;@totvs&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Canal no Slack&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;&lt;a href=&quot;https://totvsdev.herokuapp.com/&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;Link para o convite&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;YouTube&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;&lt;a href=&quot;https://www.youtube.com/totvsdevelopers&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;@totvsdevelopers&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Meetup&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;&lt;a href=&quot;https://www.meetup.com/pt-BR/totvsdevelopers/&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;@totvsdevelopers&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Redes&lt;/td&gt;
&lt;td style=&quot;width: 49.9288%;&quot;&gt;Twitter: &lt;a href=&quot;https://twitter.com/TOTVSDevelopers&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;@TOTVSDevelopers&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;Faltou alguma comunidade aqui?&lt;/h2&gt;
&lt;p&gt;Eu tenho certeza de que esta lista não é extensiva e se você acha que eu deixei de falar sobre alguma comunidade brasileira de desenvolvimento e deveria adicionar neste artigo, tem um jeito de tu me falar.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/nawarian/status/1509289706823028736&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;Responde este tweet aqui&lt;/a&gt; com o arroba da comunidade, ou o site pra eu dar uma olhada e eu vou adicionar neste artigo aqui.&lt;/p&gt;
&lt;p&gt;Até a próxima! 👋&lt;/p&gt;</content:encoded></item><item><title>3 dicas essenciais para identificar vagas arrombadas</title><link>https://codamos.com.br/vagas-arrombadas/</link><guid isPermaLink="true">https://codamos.com.br/vagas-arrombadas/</guid><description>Fala galera, tudo bom? Pokemaobr aqui e vamos falar hoje sobre uma tema que eu particularmente acho muito importante você tentar entender antes de sair mandando currículo para alguns lugares por aí. A</description><pubDate>Wed, 30 Mar 2022 18:52:53 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Fala galera, tudo bom? Pokemaobr aqui e vamos falar hoje sobre uma tema que eu particularmente acho muito importante você tentar entender antes de sair mandando currículo para alguns lugares por aí. As &quot;benditas&quot; &lt;strong&gt;vagas arrombadas&lt;/strong&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Acho que todo mundo já passou por um momento de ler a descrição de uma ou mais vagas e não entender nada do que está acontecendo ali, muitos requisitos, &lt;strong&gt;10 linguagens, 20 frameworks, 10 anos de experiência em um framework que só tem 3 anos e, entre outras coisas totalmente sem sentido&lt;/strong&gt;. Embora às vezes fique na cara que a vaga em questão se trata de algo que devemos evitar, outras muitas, poderíamos ter evitado de se aplicar e perdido nosso tempo à toa.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Muito se fala sobre o excesso de demanda para devs, e isso se mostra real com a quantidade de vagas abertas. Porém, quantas dessas vagas realmente fazem sentido para você que busca uma boa alocação no mercado de trabalho de TI? Vamos pontuar algumas características que fazem uma vaga ser arrombada ou não.&lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;Excesso de tecnologias como requisitos técnicos&lt;/h2&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Esse é o primeiro ponto para você descartar completamente a aplicação em uma vaga. Vagas com tecnologias obsoletas, ou que não se conversam entre si. &lt;strong&gt;Mistura de 3 frameworks front-end com, 5 linguagens back-end e ferramentas devops numa vaga de nível júnior&lt;/strong&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Uma característica desse tipo de vaga é as linguagens citadas nem conversarem entre si. Onde por exemplo para uma vaga para web exigem C, JavaScript, Delphi.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Geralmente quando você verificar que uma vaga tem esse tanto de requisitos técnicos, provavelmente foi escrita pelo pessoal do RH e em geral alguma parte da entrevista vai ser com esse pessoal. Então, &lt;strong&gt;é bom evitar esse tipo de vaga para não se arrepender depois.&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image post__image--center&quot; src=&quot;/media/posts/37/vaga-arrombada-1.png&quot; alt=&quot;Anúncio de vaga com dezenas de linguagens de programação, e formações superiores aleatórias. Destaque para o requisito &amp;quot;Engenharia civil&amp;quot;.&quot; width=&quot;629&quot; height=&quot;772&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Anúncio de vaga com dezenas de linguagens de programação, e formações superiores aleatórias. Destaque para o requisito &quot;Engenharia civil&quot;.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2&gt;Excesso de requisitos para vaga de nível junior&lt;/h2&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;&lt;strong&gt;Numa vaga dev de nível junior é esperado poucos requisitos técnicos&lt;/strong&gt;. Geralmente uma ou duas linguagens, alguns conceitos básicos, talvez um framework. Existem &lt;strong&gt;vagas pra júnior que exigem  4 anos de experiência&lt;/strong&gt;, outras pedem muitas linguagens, ou muitos frameworks. Esse tipo de vaga não é boa e geralmente você não vai atuar como junior e sim como &lt;strong&gt;pleno e receber como junior&lt;/strong&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Uma boa vaga para junior vai focar um pouco mais nos requisitos não-técnicos (&lt;em&gt;softskills&lt;/em&gt;) e abraçará a pessoa para que ela possa aprender mais dentro da empresa. Então não exigirá requisitos técnicos avançados.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Devs junior estão começando a desenvolver, então não deveria ser cobrado coisas que a princípio dependem da regra de negócio da empresa, como: propor melhorias e evoluir coisas. Estão em tempo de aprender então o ideal.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image post__image--center&quot; src=&quot;/media/posts/37/vaga-arrombada-2-2.png&quot; alt=&quot;Anúncio de vaga que pede melhoria de produtos e processos, agilidade e 6 linguagens de programação diferentes.&quot; width=&quot;929&quot; height=&quot;736&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Anúncio de vaga que pede melhoria de produtos e processos, agilidade e 6 linguagens de programação diferentes.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image post__image--center&quot; src=&quot;/media/posts/37/vaga-arrombada-3-2.png&quot; alt=&quot;Anúncio de vaga que pede avaliação de riscos e tomada de decisão e diversas tecnologias.&quot; width=&quot;909&quot; height=&quot;701&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Anúncio de vaga que pede avaliação de riscos e tomada de decisão e diversas tecnologias.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2&gt;Testes não condizentes&lt;/h2&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;É normal algumas empresas cobrarem das pessoas que aplicam um teste básico para &lt;/span&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;&quot;medir&quot; a qualidade técnica da pessoa. Porém, em alguns casos esses testes fogem um pouco do padrão e &lt;strong&gt;exigem que a pessoa basicamente desenvolva uma funcionalidade que é parte de um produto&lt;/strong&gt;. O que exige muito tempo de esforço e &lt;strong&gt;às vezes acaba sendo um trabalho de graça que você faz para essas empresas&lt;/strong&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Tudo bem ter alguns testes como a resolução de algum exercício de lógica, ou algumas perguntas sobre as tecnologias que são necessárias para os requisitos da vaga, ou até o consumo de uma API simples ou o desenvolvimento de uma. Mas quando começam a pedir para você desenvolver &lt;strong&gt;funcionalidades muito complexas, ou partes de um produto&lt;/strong&gt; isso foge bastante do que é esperado para uma vaga. Tornando assim essa vaga, uma vaga arrombada.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image post__image--center&quot; src=&quot;/media/posts/37/vaga-arrombada-4.png&quot; alt=&quot;Descrição de um teste que pede CRUD de clientes, produtos, pedidos de compra, filtros e busca.&quot; width=&quot;893&quot; height=&quot;787&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Descrição de um teste que pede CRUD de clientes, produtos, pedidos de compra, filtros e busca.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2&gt;Excesso de &quot;mimos&quot;&lt;/h2&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Sabemos que é importante e parte do bem estar da pessoa desenvolvedora algumas regalias na descrição de uma vaga, coisas como: vale refeição, vale transporte, vale alimentação, plano de saúde, &lt;em&gt;gympass&lt;/em&gt; (embora quase nenhuma pessoa dev utilize :)), vale cultura, etc., são complementos muito legais ao salário e ajudam bastante na melhoria da qualidade de vida.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Porém, em algumas vagas vemos excessos de &quot;mimos&quot; como: &lt;strong&gt;escorregador, vídeogame, sinuca, ping pong, piscina de bolinha&lt;/strong&gt;, etc. e às vezes você nunca vai conseguir usufruir dessas coisas.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;É legal ter um ambiente de trabalho mais &quot;divertido&quot;? Com certeza. Mas temos que ponderar até que ponto esses &quot;mimos&quot; realmente vão ser importantes para nós e melhorar a nossa qualidade de vida. &lt;strong&gt;Excesso de mimos geralmente significa um salário abaixo do mercado e/ou jornadas de trabalho mais longas&lt;/strong&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Bem, acho que deu para perceber um pouco como fugir das famigeradas vagas arrombadas. Mas então, como identificar boas vagas?&lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;Identificando boas vagas&lt;/h2&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Ainda sobre a questão dos requisitos técnicos. Uma boa vaga sempre vai trazer a escolha de &lt;strong&gt;uma linguagem&lt;/strong&gt; como, por exemplo: java ou C# ou PHP ou Python; a escolha de &lt;strong&gt;um framework&lt;/strong&gt;, como react, angular ou vue; ao invés de cobrar os 3 frameworks ou as 4 linguagens.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;&lt;strong&gt;Boas vagas tem descrições mais diretas nos requisitos e pouca enrolação na listagem dos benefícios&lt;/strong&gt;. São sucintas e de fácil entendimento. Pedem coisas que realmente a empresa utiliza e você usará no dia a dia de trabalho.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Uma última dica: &lt;strong&gt;fuja de vagas que utilizam&lt;/strong&gt; muito de palavras-chave como &lt;strong&gt;resiliência, espírito de dono, foco em resultado, visão do futuro, excelência, etc&lt;/strong&gt;. Essas palavras são conhecidas como red flags. A empresa que precisa de alguém &quot;resiliente&quot;, &quot;focado&quot;, &quot;com sede&quot;, etc. geralmente &lt;strong&gt;vai comer a saúde mental da pessoa e oferecer um salário bem abaixo do que a pessoa executa&lt;/strong&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mas pokemão e como eu consigo mudar o jogo e ao invés de procurar vagas, pessoas recrutadoras me encontrarem?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Para que as pessoas recrutadoras encontrem você, a primeira coisa é ser uma pessoa de fácil procura. &lt;strong&gt;Seja estando mais ativa na comunidade dev&lt;/strong&gt;, tendo um bom portfólio de projetos no github, e &lt;strong&gt;ter bons perfis em redes sociais, principalmente no linkedIn.&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt; Falando nisso, temos um artigo sensacional escrito pelo Nawarian com &lt;a href=&quot;/guia-definitivo-perfil-profissional-linkedin-passo-a-passo/&quot;&gt;12 passos para ter um perfil extremamente atraente no linkedIn&lt;/a&gt;!&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Caso tenha alguma dúvida pode entrar em contato comigo no &lt;a href=&quot;mailto:contato@pokemaobr.dev&quot; rel=&quot;nofollow&quot;&gt;contato@pokemaobr.dev&lt;/a&gt; ou na minha live: &lt;/span&gt;&lt;a href=&quot;https://twitch.tv/pokemaobr&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;https://twitch.tv/pokemaobr&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt; ou no twitter: &lt;a href=&quot;https://twitter.com/pokemaobr&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;https://twitter.com/pokemaobr&lt;/a&gt;!&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-weight: 400;&quot;&gt;Obrigado de coração e até a próxima.&lt;/span&gt;&lt;/p&gt;</content:encoded><category>junior</category><category>vagas</category><category>pokemaobr</category></item><item><title>PHP 8.1 e suas novidades para 2022</title><link>https://codamos.com.br/novidades-php-81/</link><guid isPermaLink="true">https://codamos.com.br/novidades-php-81/</guid><description>A equipe que gerencia o PHP lançou a versão 8.1 em Novembro de 2021 , e na mesma data deixou de dar suporte à versão 7.3. Portanto se você ainda está na versão 7.3 ou abaixo, é importantíssimo que voc</description><pubDate>Fri, 25 Mar 2022 08:39:04 GMT</pubDate><content:encoded>&lt;p&gt;A equipe que gerencia o PHP lançou a &lt;a href=&quot;https://www.php.net/releases/8.1/pt_BR.php&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;versão 8.1 em Novembro de 2021&lt;/a&gt;, e na mesma data deixou de dar suporte à versão 7.3.&lt;/p&gt;
&lt;p&gt;Portanto se você ainda está na versão 7.3 ou abaixo, é importantíssimo que você atualize! Bugs e falhas de segurança não serão mais corrigidas para estas versões!&lt;/p&gt;
&lt;p class=&quot;msg msg--highlight &quot;&gt;&lt;strong&gt;😉 Veja também o PHP 8.2!&lt;/strong&gt;&lt;br&gt;&lt;br&gt;Em Novembro de 2022 é lançada a versão 8.2 do PHP. Eu escrevi &lt;a href=&quot;/novidades-php-82/&quot;&gt;uma publicação detalhada sobre as mudanças da linguagem para esta versão também&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;post__toc&quot;&gt;
&lt;h3&gt;Conteúdos deste artigo&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fuk16lmbeq&quot;&gt;Melhorias de performance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#new-features&quot;&gt;Novas funcionalidades da linguagem&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fuk16lmbes&quot;&gt;Enumerações (enums)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1g458mqeqbo&quot;&gt;Desempacotamento de arrays com chaves do tipo string&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1g458mqeqbp&quot;&gt;Fibers ou Fibras&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fuk16lmbet&quot;&gt;Propriedades imutáveis (somente leitura)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fuk16lmbeu&quot;&gt;Nova sintaxe de Callables&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fuk16lmbev&quot;&gt;Utilizar new como valor padrão e em atributos&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fuk16lmbf0&quot;&gt;Interseção de tipos&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fuk16lmbf3&quot;&gt;O tipo de retorno never&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1g458mqeqbq&quot;&gt;Constantes de classe finais&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fuk16lmbf4&quot;&gt;Nova sintaxe para números octais&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fuk1blntfa&quot;&gt;Conclusão&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id=&quot;mcetoc_1fuk16lmbeq&quot;&gt;Melhorias de performance&lt;/h2&gt;
&lt;p&gt;O PHP 8.1 vem com algumas otimizações de performance, mas nada absurdo como o que aconteceu entre as versões 5.6 e 7.0.&lt;/p&gt;
&lt;p&gt;A realidade é que a máquina virtual do PHP já é bem otimizada e a partir da versão 8.0 vai ser difícil ver outro salto de performance como o que vimos no passado.&lt;/p&gt;
&lt;p&gt;Alguns números oficiais que tirei da página oficial de lançamento do PHP:&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--wide&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/36/php81_performance.svg&quot; alt=&quot;Tempo de requisição necessário para carregar a aplicação Demo do framework Symfomy. Portanto quanto menor o tempo, melhor. Fonte: https://www.php.net/releases/8.1/pt_BR.php&quot; width=&quot;672.63&quot; height=&quot;198.38&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;
&lt;p&gt;Tempo de requisição necessário para carregar a aplicação &lt;em&gt;Demo&lt;/em&gt; do framework &lt;em&gt;Symfomy. &lt;/em&gt;Quanto menos, melhor.&lt;br&gt;Fonte: https://www.php.net/releases/8.1/pt_BR.php&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Note que entre o PHP 7.4 há uma redução média de 392ms. Em comparação à versão 8.0, o PHP teve performance 23% mais rápida com a aplicação &lt;em&gt;Demo&lt;/em&gt; do &lt;em&gt;Symfony&lt;/em&gt;, e 3,5% mais rápida no &lt;em&gt;WordPress&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Para quem olha estes números crus parece pouco, mas num ambiente onde se precisa trafegar milhares ou dezenas de milhares de requisições por segundo, isto faz uma diferença enorme!&lt;/p&gt;
&lt;h2 id=&quot;new-features&quot;&gt;Novas funcionalidades da linguagem&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;/php-8-features/&quot; target=&quot;null&quot;&gt;Quando o PHP 8.0 saiu&lt;/a&gt;, nós tivemos uma recepção muito bacana pela comunidade e várias funcionalidades promissoras como o &lt;a href=&quot;/php-8-jit/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Compilador &lt;em&gt;Just in Time&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;O PHP 8.1 não deixou a desejar e trouxe ainda mais coisas que a comunidade vem pedindo há bastante tempo. Enums, imutabilidade, avanços no motor de verificações de tipos, desempacotamento de arrays...&lt;/p&gt;
&lt;p&gt;Vamos à lista:&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fuk16lmbes&quot;&gt;Enumerações (&lt;em&gt;enums&lt;/em&gt;)&lt;/h3&gt;
&lt;p&gt;A proposta para lançar &lt;em&gt;enums&lt;/em&gt; foi escrita no final de 2020 e conduzida por &lt;a href=&quot;https://twitter.com/Crell&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;Larry Garfield (@Crell)&lt;/a&gt; e &lt;a href=&quot;https://twitter.com/IlijaTovilo&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Ilija Tovilo (@IlijaTovilo)&lt;/a&gt;. Você pode visitar a RFC através &lt;a href=&quot;https://wiki.php.net/rfc/enumerations&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;deste link&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;O principal efeito de ter &lt;em&gt;enums&lt;/em&gt; integrados à linguagem, é que nós vamos poder parar de usar constantes de classe para indicar quais os valores possíveis para uma função/método.&lt;/p&gt;
&lt;p&gt;&lt;img class=&quot;post__image post__image--center&quot; src=&quot;/media/posts/36/sintaxe-enum-php-8.1-3.png&quot; alt=&quot;&quot; width=&quot;2268&quot; height=&quot;2068&quot;&gt;&lt;/p&gt;
&lt;p&gt;Para quem não vê, ou para quem quer copiar e colar, abaixo a transcrição do código presente na imagem acima:&lt;/p&gt;
&lt;pre&gt;enum Status {&lt;br&gt;  case Draft;&lt;br&gt;  case Published;&lt;br&gt;  case Archived;&lt;br&gt;}&lt;br&gt;&lt;br&gt;function setStatus(Status $status)&lt;br&gt;{&lt;br&gt;  // ...&lt;br&gt;}&lt;br&gt;&lt;br&gt;setStatus(Status::Draft); // OK&lt;br&gt;setStatus(Status::Archived); // OK&lt;br&gt;setStatus(&apos;codamos.com.br&apos;); // TypeError X_X&apos;&lt;/pre&gt;
&lt;p&gt;No código acima a função &lt;em&gt;&lt;code&gt;setStatus()&lt;/code&gt;&lt;/em&gt; recebe um argumento do tipo &lt;code&gt;&lt;em&gt;enum Status&lt;/em&gt;&lt;/code&gt;, que só pode ter três valores: &lt;code&gt;Status::Draft&lt;/code&gt;, &lt;code&gt;Status::Published&lt;/code&gt; ou &lt;code&gt;Status::Archived&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Qualquer valor diferente que for passado para aquela função vai gerar uma exceção do tipo &lt;em&gt;TypeError&lt;/em&gt;.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1g458mqeqbo&quot; data-pm-slice=&quot;1 1 []&quot;&gt;Desempacotamento de arrays com chaves do tipo string&lt;/h3&gt;
&lt;p data-pm-slice=&quot;1 1 []&quot;&gt;Desde o PHP 7.4 já era possível desempacotar arrays, mas as chaves do tipo string seriam ignoradas.&lt;/p&gt;
&lt;p&gt;Agora no PHP 8.1 é possível desempacotar arrays com chaves do tipo string, e a precedência segue a &lt;a href=&quot;https://www.php.net/manual/pt_BR/function.array-merge.php&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;mesma regra do array_merge()&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;$array1 = [&apos;a&apos; =&amp;gt; 1];&lt;br&gt;$array2 = [&apos;b&apos; =&amp;gt; 2];&lt;br&gt;$final = [&apos;a&apos; =&amp;gt; 0, ...$array1, ...$array2];&lt;br&gt;&lt;br&gt;var_dump($final); // [&apos;a&apos; =&amp;gt; 1, &apos;b&apos; =&amp;gt; 2]&lt;/pre&gt;
&lt;h3 id=&quot;mcetoc_1g458mqeqbp&quot; data-pm-slice=&quot;1 1 []&quot;&gt;&lt;em&gt;Fibers&lt;/em&gt; ou Fibras&lt;/h3&gt;
&lt;p data-pm-slice=&quot;1 1 []&quot;&gt;A &lt;a href=&quot;https://wiki.php.net/rfc/fibers&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;RFC de &lt;em&gt;fibers&lt;/em&gt;&lt;/a&gt; causou um alvoroço enorme na comunidade, especialmente no time que desenvolve o &lt;em&gt;Swoole&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Fibras são um mecanismo de paralelismo também conhecido como &lt;em&gt;green threads&lt;/em&gt;. A ideia deste mecanismo é que você possa gerenciar interrupções no fluxo de execução do seu código.&lt;/p&gt;
&lt;p&gt;Provavelmente você não vai utilizar este mecanismo no seu dia a dia, mas frameworks assíncronos nativos como o &lt;a href=&quot;https://reactphp.org/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;React PHP&lt;/a&gt; e &lt;a href=&quot;https://amphp.org/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;Amphp&lt;/a&gt; vão tirar muito proveito desta funcionalidade.&lt;/p&gt;
&lt;p&gt;A RFC traz um exemplo simples de como as fibras funcionam. O segredo aqui é pensar que o código está constantemente interrompendo a execução um do outro:&lt;/p&gt;
&lt;pre&gt;$fiber = new Fiber(function (): void {&lt;br&gt;  $value = Fiber::suspend(&apos;fiber&apos;);&lt;br&gt;  echo &quot;Valor utilizado ao retomar a execução da fibra: {$value}\n&quot;;&lt;br&gt;});&lt;br&gt;&lt;br&gt;$value = $fiber-&amp;gt;start();&lt;br&gt;echo &quot;Valor da suspensão da fibra: {$value}\n&quot;;&lt;br&gt;$fiber-&amp;gt;resume(&apos;test&apos;);&lt;/pre&gt;
&lt;p data-pm-slice=&quot;1 3 []&quot;&gt;O código acima executa na seguinte ordem:&lt;/p&gt;
&lt;ol class=&quot;ak-ol&quot;&gt;
&lt;li&gt;
&lt;p&gt;Instancia um objeto &lt;code&gt;&lt;span class=&quot;code&quot; spellcheck=&quot;false&quot;&gt;$fiber&lt;/span&gt;&lt;/code&gt; com uma função &lt;em&gt;callback&lt;/em&gt; que será executada assim que o método &lt;code&gt;&lt;span class=&quot;code&quot; spellcheck=&quot;false&quot;&gt;start()&lt;/span&gt;&lt;/code&gt; for chamado;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Chama o método &lt;code&gt;&lt;span class=&quot;code&quot; spellcheck=&quot;false&quot;&gt;start()&lt;/span&gt;&lt;/code&gt;, que efetivamente executa o callback definido no objeto &lt;span class=&quot;code&quot; spellcheck=&quot;false&quot;&gt;$fiber e armazena seu retorno;&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;O &lt;em&gt;callback&lt;/em&gt; executa e, em sua primeira linha, suspende a fibra utilizando o método &lt;code&gt;&lt;span class=&quot;code&quot; spellcheck=&quot;false&quot;&gt;Fiber::suspend()&lt;/span&gt;&lt;/code&gt; e passando &lt;span class=&quot;code&quot; spellcheck=&quot;false&quot;&gt;&lt;code&gt;string(fiber)&lt;/code&gt; &lt;/span&gt;como parâmetro. Isto retorna a execução para a linha anterior e joga o valor “fiber” para a variável &lt;span class=&quot;code&quot; spellcheck=&quot;false&quot;&gt;$value&lt;/span&gt;;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Um echo executa, utilizando a variável &lt;span class=&quot;code&quot; spellcheck=&quot;false&quot;&gt;$value&lt;/span&gt;, que neste momento possui o valor &lt;code&gt;&lt;span class=&quot;code&quot; spellcheck=&quot;false&quot;&gt;string(fiber)&lt;/span&gt;&lt;/code&gt;;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Retomamos a execução do &lt;em&gt;callback&lt;/em&gt; ao chamar o método &lt;code&gt;&lt;span class=&quot;code&quot; spellcheck=&quot;false&quot;&gt;resume()&lt;/span&gt;&lt;/code&gt;. Passamos o valor &lt;code&gt;&lt;span class=&quot;code&quot; spellcheck=&quot;false&quot;&gt;string(test)&lt;/span&gt;&lt;/code&gt; como parâmetro, que será transmitido àquela variável &lt;span class=&quot;code&quot; spellcheck=&quot;false&quot;&gt;$value&lt;/span&gt; dentro do &lt;em&gt;callback&lt;/em&gt;;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;O echo de dentro do &lt;em&gt;callback&lt;/em&gt; executa, utilizando a variável &lt;span class=&quot;code&quot; spellcheck=&quot;false&quot;&gt;$value&lt;/span&gt;, que neste momento possui o valor &lt;code&gt;&lt;span class=&quot;code&quot; spellcheck=&quot;false&quot;&gt;string(test)&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;mcetoc_1fuk16lmbet&quot;&gt;Propriedades imutáveis (somente leitura)&lt;/h3&gt;
&lt;p&gt;Lembra daquela época quando a gente escrevia classes como essa abaixo?&lt;/p&gt;
&lt;p&gt;&lt;img class=&quot;post__image post__image--center&quot; src=&quot;/media/posts/36/classes-imutaveis-php-antigo-3.png&quot; alt=&quot;&quot; width=&quot;2488&quot; height=&quot;2420&quot;&gt;&lt;/p&gt;
&lt;pre&gt;class Person&lt;br&gt;{&lt;br&gt;  public string $name;&lt;br&gt;&lt;br&gt;  public static function create(string $name): self&lt;br&gt;  {&lt;br&gt;    $instance = new self();&lt;br&gt;    $instance-&amp;gt;name = $name;&lt;br&gt;&lt;br&gt;    return $instance;&lt;br&gt;  }&lt;br&gt;&lt;br&gt;  public function setName(string $name): Self&lt;br&gt;  {&lt;br&gt;    return self::create($name);&lt;br&gt;  }&lt;br&gt;}&lt;/pre&gt;
&lt;p&gt;De acordo com a imagem acima, sempre que quiséssemos modificar uma propriedade da classe, criaríamos uma nova instância para defender a imutabilidade do objeto atual.&lt;/p&gt;
&lt;p&gt;A partir do PHP 8.1 isto já não é mais necessário, porque podemos definir propriedades como imutáveis desde a sua criação. Segue o snippet abaixo:&lt;/p&gt;
&lt;p&gt;&lt;img class=&quot;post__image post__image--center&quot; src=&quot;/media/posts/36/sintaxe-propriedade-somente-leitura-php-8.1-2.png&quot; alt=&quot;&quot; width=&quot;2828&quot; height=&quot;1004&quot;&gt;&lt;/p&gt;
&lt;pre&gt;class Person&lt;br&gt;{&lt;br&gt;  public function __construct(public &lt;strong&gt;readonly&lt;/strong&gt; string $name)&lt;br&gt;  {}&lt;br&gt;}&lt;/pre&gt;
&lt;p&gt;Aqui eu utilizei o &lt;a href=&quot;/php-8-features/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;constructor promotion, que foi introduzido no PHP 8.0&lt;/a&gt;. Mas adicionei uma palavra-chave ali: &lt;code&gt;&lt;em&gt;readonly&lt;/em&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Com a palavra-chave &lt;em&gt;readonly&lt;/em&gt; nós podemos indicar que propriedades das classes só podem ser escritas uma vez, dentro do método &lt;code&gt;&lt;em&gt;__construct()&lt;/em&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Portanto tanto faz se você deixa aquela propriedade com visibilidade pública ou não, porque nada vai poder alterar aquela propriedade. &lt;strong&gt;Adeus &lt;em&gt;getters&lt;/em&gt; e &lt;em&gt;setters&lt;/em&gt;!&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fuk16lmbeu&quot;&gt;Nova sintaxe de &lt;em&gt;Callables&lt;/em&gt;&lt;/h3&gt;
&lt;p&gt;O PHP já tem uma sintaxe para referenciar classes, que funciona mais ou menos assim: &lt;code&gt;$name = MinhaClasse::class;&lt;/code&gt;, onde &lt;code&gt;$name&lt;/code&gt; armazena a string &lt;code&gt;&quot;\MinhaClasse&quot;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Isso é extremamente útil pra fazer referência ao código de forma dinâmica para quem escreve. Por exemplo, o &lt;em&gt;framework&lt;/em&gt; Slim nos permite definir rotas da seguinte forma:&lt;/p&gt;
&lt;p&gt;&lt;img class=&quot;post__image post__image--center&quot; src=&quot;/media/posts/36/sintaxe-constante-de-classe-3.png&quot; alt=&quot;&quot; width=&quot;1788&quot; height=&quot;532&quot;&gt;&lt;/p&gt;
&lt;pre&gt;$app-&amp;gt;get(&apos;/&apos;, MinhaClasse&lt;strong&gt;::class&lt;/strong&gt;);&lt;/pre&gt;
&lt;p&gt;O problema com a forma acima é que para aquela rota funcionar, a classe &lt;code&gt;\MinhaClasse&lt;/code&gt; precisa implementar o método público &lt;code&gt;&lt;em&gt;__invoke()&lt;/em&gt;&lt;/code&gt;. Existe uma forma de contornar a situação, como em &lt;code&gt;[MinhaClasse::class, &apos;meuMetodo&apos;]&lt;/code&gt; - mas esta sintaxe se confunde com a de arrays.&lt;/p&gt;
&lt;p&gt;Com o PHP 8.1 é possível indicar a classe e método de forma nativa e distinta na linguagem. A sintaxe é a seguinte:&lt;/p&gt;
&lt;p&gt;&lt;img class=&quot;post__image post__image--center&quot; src=&quot;/media/posts/36/sintaxe-nativa-callables-8.1.png&quot; alt=&quot;&quot; width=&quot;2488&quot; height=&quot;1832&quot;&gt;&lt;/p&gt;
&lt;pre&gt;$len = strlen&lt;strong&gt;(...)&lt;/strong&gt;; // função&lt;br&gt;$invoke = $obj&lt;strong&gt;(...)&lt;/strong&gt;; // objeto com método __invoke()&lt;br&gt;$metodo = $obj-&amp;gt;metodo&lt;strong&gt;(...)&lt;/strong&gt;; // método de um objeto&lt;br&gt;// método estático de uma classe&lt;br&gt;$metodoEstatico = MinhaClasse::metodoEstatico&lt;strong&gt;(...)&lt;/strong&gt;;&lt;/pre&gt;
&lt;p&gt;Desta forma, é possível imaginar que num release futuro do &lt;em&gt;framework&lt;/em&gt; Slim a gente consiga ver algo assim:&lt;/p&gt;
&lt;p&gt;&lt;img class=&quot;post__image post__image--center&quot; src=&quot;/media/posts/36/sintaxe-nativa-callables-php-8.1-exemplo-router.png&quot; alt=&quot;&quot; width=&quot;2176&quot; height=&quot;768&quot;&gt;&lt;/p&gt;
&lt;pre&gt;$app-&amp;gt;get(&apos;/person&apos;, &lt;strong&gt;$person-&amp;gt;list(...)&lt;/strong&gt;);&lt;br&gt;$app-&amp;gt;post(&apos;/person&apos;, &lt;strong&gt;$person-&amp;gt;create(...)&lt;/strong&gt;);&lt;/pre&gt;
&lt;p&gt;Eu esperaria ver esta sintaxe criar impacto direto em &lt;em&gt;frameworks&lt;/em&gt; e bibliotecas que lidam com:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Rotas (Slim, Mezzio...)&lt;/li&gt;
&lt;li&gt;Injeção de dependências (PHP DI)&lt;/li&gt;
&lt;li&gt;Event Loop (ReactPHP, Swoole, AMP...)&lt;/li&gt;
&lt;li&gt;Logging (Monolog)&lt;/li&gt;
&lt;li&gt;Testes (PHPUnit, Pest...)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;mcetoc_1fuk16lmbev&quot;&gt;Utilizar new como valor padrão e em atributos&lt;/h3&gt;
&lt;p&gt;Você já deve ter visto que para argumentos opcionais é possível dar um valor padrão na assinatura da função ou método. Algo assim:&lt;/p&gt;
&lt;p&gt;&lt;img class=&quot;post__image post__image--center&quot; src=&quot;/media/posts/36/sintaxe-php-valor-padrao-argumento.png&quot; alt=&quot;&quot; width=&quot;1788&quot; height=&quot;1124&quot;&gt;&lt;/p&gt;
&lt;pre&gt;function minhaFuncao(int $a &lt;strong&gt;= 10&lt;/strong&gt;) {&lt;br&gt;  var_dump($a);&lt;br&gt;}&lt;br&gt;&lt;br&gt;minhaFuncao(); // int(10)&lt;/pre&gt;
&lt;p&gt;Repare que ao chamar &lt;code&gt;minhaFuncao()&lt;/code&gt; sem parâmetro algum, a máquina virtual do PHP assume que deveria utilizar o valor padrão &lt;code&gt;10&lt;/code&gt;. Mas esta sintaxe só funciona com valores primitivos.&lt;/p&gt;
&lt;p class=&quot;msg msg--info&quot;&gt;🧙🏻‍♂️ Se você ainda não se familiarizou com os termos sobre tipos em PHP, dá uma olhada &lt;a href=&quot;/tipos-em-php/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;neste artigo que eu escrevi sobre tipos no PHP&lt;/a&gt; 😉&lt;/p&gt;
&lt;p&gt;Desde o PHP 8.1 também é possível utilizar objetos como valor padrão. Um caso de uso que eu acho particularmente útil é o de utilização de datas. Veja um exemplo de como isso muda no PHP 8.1:&lt;/p&gt;
&lt;p&gt;&lt;img class=&quot;post__image post__image--center&quot; src=&quot;/media/posts/36/sintaxe-php-8.1-valor-padrao-argumento-objeto-2.png&quot; alt=&quot;&quot; width=&quot;3312&quot; height=&quot;1832&quot;&gt;&lt;/p&gt;
&lt;pre&gt;class MinhaClasse&lt;br&gt;{&lt;br&gt;  public function __construct(&lt;br&gt;    public DateTimeInterface $createdAt &lt;strong&gt;= new DateTimeImmutable(&apos;now&apos;)&lt;/strong&gt;&lt;br&gt;  ) {}&lt;br&gt;}&lt;br&gt;&lt;br&gt;$obj1 = new MinhaClasse(new DateTimeImmutable(&apos;tomorrow&apos;));&lt;br&gt;$obj2 = new MinhaClasse&lt;strong&gt;()&lt;/strong&gt;; // $obj2-&amp;gt;createdAt é um DateTimeImmutable(&apos;now&apos;)&lt;/pre&gt;
&lt;p&gt;Com o construtor acima nós definimos a propriedade &lt;code&gt;DateTimeInterface $createdAt&lt;/code&gt;, e caso ela seja omitida ao instanciar o objeto nós adotamos como valor padrão uma nova instância de &lt;code&gt;DateTimeImmutable&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fuk16lmbf0&quot;&gt;Interseção de tipos&lt;/h3&gt;
&lt;p&gt;Desde o PHP 8.0 nós recebemos suporte à &lt;a href=&quot;https://www.php.net/manual/pt_BR/language.types.declarations.php#language.types.declarations.composite.union&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;União de Tipos (&lt;em&gt;union types&lt;/em&gt;)&lt;/a&gt;. Que nos permite dizer que determinada variável é do tipo A &lt;em&gt;ou&lt;/em&gt; B, como abaixo:&lt;/p&gt;
&lt;p&gt;&lt;img class=&quot;post__image post__image--center&quot; src=&quot;/media/posts/36/sintaxe-php-8.0-uniao-de-tipos.png&quot; alt=&quot;&quot; width=&quot;2088&quot; height=&quot;652&quot;&gt;&lt;/p&gt;
&lt;pre&gt;function minhaFuncao(&lt;strong&gt;int|float&lt;/strong&gt; $numero) {}&lt;/pre&gt;
&lt;p&gt;No escopo da função acima, a variável &lt;code&gt;$numero&lt;/code&gt; pode ser do tipo &lt;code&gt;int&lt;/code&gt; ou &lt;code&gt;float&lt;/code&gt;, mas &lt;strong&gt;nunca os dois ao mesmo tempo&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;A versão 8.1 do PHP trouxe a &lt;a href=&quot;https://www.php.net/manual/pt_BR/language.types.declarations.php#language.types.declarations.composite.intersection&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;Interseção de tipos (&lt;em&gt;intersection types&lt;/em&gt;)&lt;/a&gt;, que nos permite indicar que uma variável é de tipo A &lt;em&gt;e&lt;/em&gt; B &lt;strong&gt;ao mesmo tempo&lt;/strong&gt;. Um claro exemplo que interseção de tipos que me vem à mente são &lt;em&gt;mocks em testes&lt;/em&gt;, veja o exemplo abaixo:&lt;/p&gt;
&lt;p&gt;&lt;img class=&quot;post__image post__image--center&quot; src=&quot;/media/posts/36/sintaxe-php-8.1-interseccao-de-tipos.png&quot; alt=&quot;&quot; width=&quot;3312&quot; height=&quot;1832&quot;&gt;&lt;/p&gt;
&lt;pre&gt;class MyTest extends TestCase&lt;br&gt;{&lt;br&gt;    private &lt;strong&gt;MinhaClasse&amp;amp;MockObject&lt;/strong&gt; $mock;&lt;br&gt;&lt;br&gt;    ...&lt;br&gt;    public function testAlgumaCoisa()&lt;br&gt;    {&lt;br&gt;        $this-&amp;gt;mock = $this-&amp;gt;prophesize(MinhaClasse::class)-&amp;gt;reveal();&lt;br&gt;        ...&lt;br&gt;    }&lt;br&gt;}&lt;/pre&gt;
&lt;p&gt;No exemplo acima a propriedade $mock é do tipo &lt;code&gt;MinhaClasse&lt;/code&gt; e &lt;code&gt;MockObject&lt;/code&gt; ao mesmo tempo.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fuk16lmbf3&quot;&gt;O tipo de retorno never&lt;/h3&gt;
&lt;p&gt;Já se viu numa situação em que você chama uma função, escreve mais algumas operações em seguida mas o código nunca executa estas operações? Eu já caí em algo assim:&lt;/p&gt;
&lt;p&gt;&lt;img class=&quot;post__image post__image--center&quot; src=&quot;/media/posts/36/exemplo-redirect-confuso-com-exit.png&quot; alt=&quot;&quot; width=&quot;2044&quot; height=&quot;768&quot;&gt;&lt;/p&gt;
&lt;pre&gt;// ...&lt;br&gt;&lt;br&gt;$redirect = redirect(&apos;/&apos;);&lt;br&gt;$this-&amp;gt;logger-&amp;gt;log(&apos;Redirecting to &quot;/&quot;&apos;);&lt;/pre&gt;
&lt;p&gt;E a linha &lt;code&gt;$this-&amp;gt;logger-&amp;gt;log()&lt;/code&gt; não executava NUNCA. O motivo? A função &lt;code&gt;redirect()&lt;/code&gt; enviava os cabeçalhos HTTP e depois dava um &lt;code&gt;exit(0)&lt;/code&gt;, simples assim.&lt;/p&gt;
&lt;p&gt;Como adivinhar uma coisa dessas? Lendo código alheio, usando o depurador... e testar isso é um inferno na terra!&lt;/p&gt;
&lt;p&gt;O tipo de retorno &lt;em&gt;&lt;code&gt;never&lt;/code&gt;&lt;/em&gt; vem justamente pra deixar este comportamento mais explícito. Se usa assim:&lt;/p&gt;
&lt;p&gt;&lt;img class=&quot;post__image post__image--center&quot; src=&quot;/media/posts/36/sintaxe-php-8.1-tipo-retorno-never.png&quot; alt=&quot;&quot; width=&quot;1916&quot; height=&quot;1124&quot;&gt;&lt;/p&gt;
&lt;pre&gt;function redirect(string $path): &lt;strong&gt;never&lt;/strong&gt;&lt;br&gt;{&lt;br&gt;  header(&quot;Location: {$path}&quot;);&lt;br&gt;  exit(0);&lt;br&gt;}&lt;/pre&gt;
&lt;p&gt;Ao utilizar o tipo de retorno &lt;em&gt;never&lt;/em&gt; você diz à máquina virtual do PHP, e à próxima pessoa que ler a assinatura da sua função/método, que aquela função necessariamente vai finalizar o processo PHP.&lt;/p&gt;
&lt;p class=&quot;msg msg--info&quot;&gt;🧙🏻‍♂️ Eu já comentei no meu &lt;a href=&quot;/programacao-por-coincidencia/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;artigo sobre como programar por intenção&lt;/a&gt; o quão poderoso uma coisa dessas é. Com esta sintaxe você consegue comunicar intenção e comportamento para quem lê o código.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1g458mqeqbq&quot; data-pm-slice=&quot;1 1 []&quot;&gt;Constantes de classe finais&lt;/h3&gt;
&lt;p data-pm-slice=&quot;1 1 []&quot;&gt;Até o PHP 8.0 era possível sobrescrever constantes de classes, e agora com a versão 8.1 da linguagem é possível adicionar o modificador &lt;span class=&quot;code&quot; spellcheck=&quot;false&quot;&gt;final&lt;/span&gt; para as constantes de classe de forma que nunca sejam sobrescritas.&lt;/p&gt;
&lt;p&gt;A utilização fica assim:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;/code&gt;class Primeira&lt;br&gt;{&lt;br&gt;  final public const MINHA_CONST = &apos;foo&apos;;&lt;br&gt;}&lt;br&gt;&lt;br&gt;class Segunda&lt;br&gt;{&lt;br&gt;  public const MINHA_CONST = &apos;bar&apos;; // Erro fatal&lt;br&gt;}&lt;/pre&gt;
&lt;h3 id=&quot;mcetoc_1fuk16lmbf4&quot;&gt;Nova sintaxe para números octais&lt;/h3&gt;
&lt;p&gt;A linguagem PHP permite escrever números em diferentes bases numéricas, seguindo as sintaxes a seguir:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Base binária, usando o prefixo &lt;code&gt;0b&lt;/code&gt; como em &lt;code&gt;0b10010&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;Base octal, usando o prefixo &lt;code&gt;0&lt;/code&gt; como em &lt;code&gt;016&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;Base decimal, sem prefixo algum como em &lt;code&gt;16&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;Base hexadecimal, usando o prefixo &lt;code&gt;0x&lt;/code&gt; como em &lt;code&gt;0x16&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;msg msg--info&quot;&gt;🧙🏻‍♂️ Se você não entende bem o que essas bases todas significam, dá uma olhada no meu &lt;a href=&quot;/php-bitwise/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;artigo sobre operações binárias (bitwise) em PHP&lt;/a&gt; 😉.&lt;/p&gt;
&lt;p&gt;O atual prefixo para números octais faz parecer com que o primeiro 0 é parte do número em si, e pode gerar resultados confusos como abaixo:&lt;/p&gt;
&lt;p&gt;&lt;img class=&quot;post__image post__image--center&quot; src=&quot;/media/posts/36/sintaxe-php-numeros-octais.png&quot; alt=&quot;&quot; width=&quot;2392&quot; height=&quot;652&quot;&gt;&lt;/p&gt;
&lt;pre&gt;016 === 16 // false -&amp;gt; 016 (octal) é 14 (decimal)&lt;/pre&gt;
&lt;p&gt;Para resolver isto, um novo prefixo foi adicionado à linguagem para representar números octais: &lt;code&gt;0o&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Desta forma o código acima fica menos confuso, porque fica claro que o lado esquerdo usa a notação octal:&lt;/p&gt;
&lt;p&gt;&lt;img class=&quot;post__image post__image--center&quot; src=&quot;/media/posts/36/sintaxe-php-8.1-numeros-octais.png&quot; alt=&quot;&quot; width=&quot;1788&quot; height=&quot;768&quot;&gt;&lt;/p&gt;
&lt;pre&gt;&lt;strong&gt;0o&lt;/strong&gt;16 === 16 // false&lt;br&gt;&lt;strong&gt;0o&lt;/strong&gt;16 === 14 // true&lt;/pre&gt;
&lt;h2 id=&quot;mcetoc_1fuk1blntfa&quot;&gt;Conclusão&lt;/h2&gt;
&lt;p&gt;O PHP 8.1 está uma delícia, com diversas adições na linguagem e ferramentas para tornar o nosso fluxo de trabalho bem mais agradável, seguro e performático!&lt;/p&gt;
&lt;p&gt;Num futuro eu pretendo escrever sobre &lt;em&gt;Fibers &lt;/em&gt;com maior atenção, porque este conteúdo simplesmente não cabe neste artigo. &lt;a href=&quot;https://twitter.com/nawarian&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;Me segue no Twitter&lt;/a&gt; pra ficar sabendo quando o artigo sair 😉.&lt;/p&gt;
&lt;p&gt;Até a próxima 👋&lt;/p&gt;</content:encoded><category>php</category></item><item><title>Guia: LinkedIn para pessoas desenvolvedoras - 12 passos para um perfil chamativo!</title><link>https://codamos.com.br/guia-definitivo-perfil-profissional-linkedin-passo-a-passo/</link><guid isPermaLink="true">https://codamos.com.br/guia-definitivo-perfil-profissional-linkedin-passo-a-passo/</guid><description>Não importa se você é iniciante ou se já está na área faz tempo, a apresentação pessoal normalmente não é o forte de quem trabalha com desenvolvimento de software... Eu vim aqui te ajudar justamente c</description><pubDate>Mon, 14 Mar 2022 17:36:44 GMT</pubDate><content:encoded>&lt;p&gt;Não importa se você é iniciante ou se já está na área faz tempo, a apresentação pessoal normalmente não é o forte de quem trabalha com desenvolvimento de software... Eu vim aqui te ajudar justamente com isso!&lt;/p&gt;
&lt;p&gt;Eu trabalho com desenvolvimento de software há 10 anos, e há pouco mais de um ano trabalho como gerente de time de desenvolvimento. &lt;strong&gt;Já entrevistei muita gente, fiz seleção e o que mais você puder imaginar no processo seletivo&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Eu também conversei com vários profissionais&lt;/strong&gt;, tanto com desenvolvedoras de software quanto com gerentes e recrutadoras, para entender quais são as informações chave que você deve trazer no seu LinkedIn para chamar a atenção &lt;em&gt;do jeito certo&lt;/em&gt;!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Não importa se você está começando ou é Júnior, Pleno ou Sênior&lt;/strong&gt;. Ao final deste artigo você vai entender direitinho tudo o que precisa fazer pra tornar o seu perfil no LinkedIn mais atrativo e começar a receber convites para entrevistas 😎&lt;/p&gt;
&lt;h2&gt;Todo documento tem um público alvo&lt;/h2&gt;
&lt;p&gt;Antes de começar qualquer coisa, eu quero deixar claro que absolutamente tudo o que você escreve precisa ter um público alvo. No caso do LinkedIn, &lt;strong&gt;o seu público alvo são empresas e recrutadoras&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Tudo, absolutamente tudo que você escrever precisa levar em consideração quem vai ler: empresas e recrutadoras. Não adianta usar jargão pra todo lado, e piadas de código muitas vezes não vão funcionar. E muito menos deixe coisas implícitas.&lt;/p&gt;
&lt;p&gt;Por exemplo, se você escreve no perfil que trabalhou com &quot;testes&quot; e com &quot;javascript&quot; não é necessariamente óbvio para uma recrutadora que você conhece a ferramenta &quot;jest&quot;. Deixe tudo explícito o máximo que puder!&lt;/p&gt;
&lt;p&gt;Com o seu público alvo em mente, vamos dar um tapa no seu perfil a começar pelo básico.&lt;/p&gt;
&lt;h2&gt;O básico que TODO perfil precisa ter no LinkedIn&lt;/h2&gt;
&lt;p&gt;Aqui eu quero &lt;strong&gt;agradecer demais a &lt;a href=&quot;https://twitter.com/isanortontech&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Isabela Norton (@isanortontech)&lt;/a&gt;&lt;/strong&gt; pelas dicas. A Isabela é recrutadora especializada em vagas de desenvolvimento e de tecnologia, contrata pra trabalhar na gringa e usa LinkedIn como sua ferramenta principal pra encontrar candidatas. Já segue perfil dela agora pra receber mais dicas e receber vagas bacanudas na sua timeline.&lt;/p&gt;
&lt;p&gt;A partir da nossa conversa ficou claro pra mim que &lt;strong&gt;muita gente peca no básico&lt;/strong&gt; e deixa de incluir informações essenciais para uma pessoa recrutadora encontrar seu perfil.&lt;/p&gt;
&lt;p&gt;Lembre-se: o seu público alvo são empresas e recrutadoras. Como estas pessoas vão te encontrar? Através de buscas avançadas.&lt;/p&gt;
&lt;p&gt;&quot;Eu preciso de uma pessoa que saiba JavaScript, React e TDD, que esteja em Minas Gerais e fale inglês&quot;. Pense em quais termos serão buscados a partir desta frase. Você tem estes termos no seu perfil?&lt;/p&gt;
&lt;p&gt;Para te ajudar a criar o seu perfil no LinkedIn eu vou deixar aqui algumas dicas e o passo a passo para começar, em ordem de facilidade.&lt;/p&gt;
&lt;h3&gt;Passo 1: idiomas que você fala&lt;/h3&gt;
&lt;p&gt;Pra você que nasceu no Brasil é óbvio que seu idioma materno é o Português, mas ninguém no LinkedIn sabe da sua nacionalidade. E mesmo que soubesse, indicar &lt;em&gt;todas&lt;/em&gt; as línguas que você fala é importantíssimo para que pessoas no estrangeiro também encontrem seu perfil.&lt;/p&gt;
&lt;p&gt;Para adicionar os idiomas que você fala, vá até a página do seu perfil e role a página até a seção &quot;Idiomas&quot; e clique no sinal de adição (+) como na imagem abaixo:&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/35/adicionar-linguas.png&quot; alt=&quot;Meu perfil no LinkedIn, foco na seção de idiomas.&quot; width=&quot;1175&quot; height=&quot;579&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Meu perfil no LinkedIn, foco na seção de idiomas.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Após selecionar o idioma, defina a sua proficiência com aquele idioma e pronto:&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/35/selecionar-idioma.png&quot; alt=&quot;Selecionado o idioma Russo, e proficiência básica.&quot; width=&quot;832&quot; height=&quot;395&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Selecionado o idioma Russo, e proficiência básica.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Caso tenha dúvida sobre o que cada nível significa, aqui vão algumas dicas:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Básico&lt;/strong&gt;: você consegue falar bom dia, identificar algumas palavras em um texto, mas não necessariamente falar naquele idioma;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Limitada&lt;/strong&gt;: você consegue comunicar sobre o seu trabalho de forma suficiente, mas não necessariamente desenvolver uma conversa sobre um tópico. Por exemplo você sabe pedir um &lt;em&gt;code review&lt;/em&gt;, ler por cima uma documentação...;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Profissional&lt;/strong&gt;: você consegue desenrolar conversas sobre o seu dia a dia no trabalho, talvez com uma gambiarra linguística aqui e ali, e ler documentações sem muita dificuldade;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Completa&lt;/strong&gt;: você consegue falar com proficiência total no contexto de trabalho, e com pouquíssima frequência se pega procurando por palavras ou formas de explicar uma frase;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Nativo ou bilíngue&lt;/strong&gt;: você aprendeu a falar aquele idioma desde criança.&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;msg msg--info&quot;&gt;Para muitas vagas, inclusive no Brasil, é importante falar inglês. Indique seu nível de proficiência em inglês no seu perfil. Mesmo que seja apenas básico.&lt;/p&gt;
&lt;h3&gt;Passo 2: descrição do seu perfil&lt;/h3&gt;
&lt;p&gt;A descrição do seu perfil é o lugar perfeito pra descrever o que você procura e dá valor. Está em busca do primeiro emprego? Quer experiência profissional com uma linguagem diferente? Precisa mudar de cidade? Ou tá buscando transicionar de carreira? Este é o espaço pra tu escrever sobre isso!&lt;/p&gt;
&lt;p&gt;Este campo é importantíssimo para que recrutadoras consigam entender quais vagas encaixam no seu perfil e necessidades.&lt;/p&gt;
&lt;p&gt;No meu perfil eu indico o que atualmente é mais importante para recrutadoras saberem sobre mim: meu foco em desenvolvimento para web, meu interesse por liderança, comunidade e aprender coisas novas. Meus valores incluem honestidade e comunicação direta. E eu quero trabalhar do Brasil.&lt;/p&gt;
&lt;p&gt;Com estas informações eu deixo claro para qualquer visitante do perfil que não estou interessado em pequenas aventuras, em empresas com ambiente &lt;span style=&quot;text-decoration: line-through;&quot;&gt;tóxico&lt;/span&gt; meritocrático e que não estou disposto a &quot;vestir a camisa e trabalhar horas a mais&quot; e nem faria com que meus times façam algo assim.&lt;/p&gt;
&lt;p&gt;Para alterar a descrição do seu perfil, vá ao topo da página até a seção &quot;Sobre&quot; e clique no ícone do lápis para editar:&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/35/sobre-linkedin.png&quot; alt=&quot;Perfil do LinkedIn mostrando a seção &amp;quot;Sobre&amp;quot;.&quot; width=&quot;1166&quot; height=&quot;548&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Perfil do LinkedIn mostrando a seção &quot;Sobre&quot;.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Uma caixa de texto se abrirá na sua tela. Adicione as informações mais relevantes sobre você nesta caixa de texto. Quer trabalhar remoto ou do escritório? Quer trabalhar em qual cidade? Com qual linguagem? Está procurando uma empresa inclusiva? Escreve aqui:&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/35/editar-sobre-linkedin.png&quot; alt=&quot;Perfil do LinkedIn mostrando a tela de edição da descrição do perfil.&quot; width=&quot;1154&quot; height=&quot;609&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Perfil do LinkedIn mostrando a tela de edição da descrição do perfil.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p class=&quot;msg msg--info&quot;&gt;A descrição do seu perfil é uma das primeiras coisas que recrutadoras vão olhar. Coloque as informações mais importantes ali e não tenha medo de escrever algo pessoal.&lt;/p&gt;
&lt;h3&gt;Passo 3: uma boa foto de perfil&lt;/h3&gt;
&lt;p&gt;Você não precisa pagar por uma sessão de fotografia profissional, e nem posar de roupa social pra câmera. Mas uma foto em que só você aparece e que dê para ver seu rosto cai bem.&lt;/p&gt;
&lt;p&gt;Pessoalmente eu não sou muito fã dessa coisa de expor foto no perfil, mas isto aparentemente importa para quem busca. Ao ver uma foto padrão, aquele &lt;em&gt;placeholder&lt;/em&gt; cinza, eu imediatamente ignoraria o perfil. Mas um avatar do tipo cartoon eu até acho aceitável.&lt;/p&gt;
&lt;p&gt;O ideal, porém, é uma foto sua. Vamos colocar alguns parâmetros de qualidade aqui:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Só você aparece na foto;&lt;/li&gt;
&lt;li&gt;Sem óculos escuros;&lt;/li&gt;
&lt;li&gt;Sem chapéu/boné;&lt;/li&gt;
&lt;li&gt;Sem máscara (as coisas que a pandemia me obriga a escrever, hein...)&lt;/li&gt;
&lt;li&gt;Foto relativamente recente&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Para alterar a foto do seu perfil, navegue até o topo da página, clique na sua foto atual e a seguinte tela deverá aparecer pra ti:&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/35/Screenshot-2022-03-14-at-22.26.59.png&quot; alt=&quot;Tela de edição da foto de perfil no LinkedIn.&quot; width=&quot;1180&quot; height=&quot;630&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Tela de edição da foto de perfil no LinkedIn.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Clique no botão &quot;Adicionar foto&quot; com ícone de câmera. Depois escolha fazer  o upload de uma foto. Ao escolher qual foto subir, ajuste o zoom e corte até que a foto fique adequada:&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/35/Screenshot-2022-03-14-at-22.28.41.png&quot; alt=&quot;Ao escolher uma foto de perfil no LinkedIn, ajuste o zoom, posição e filtros corretamente.&quot; width=&quot;1151&quot; height=&quot;678&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Ao escolher uma foto de perfil no LinkedIn, ajuste o zoom, posição e filtros corretamente.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Notou como nesta foto tem outra pessoa e uma garrafa de álcool? Não é exatamente o que eu gostaria de mostrar no meu perfil. Então tome cuidado para remover estes elementos da foto ao ajustar o zoom.&lt;/p&gt;
&lt;p&gt;Eu, pessoalmente, não vejo problema nenhum em usar uma foto como a acima. Apesar de ser muito pessoal e totalmente fora do contexto de uma empresa, ela diz algo sobre mim. E eu estou confortável em transmitir esta imagem e deixar claro que sou um ser humano que tem gostos e se diverte.&lt;/p&gt;
&lt;p&gt;Considere também que eu já tenho uma década de experiência e um perfil competitivo. Seguir os mesmos passos para quem está começando talvez seja um tiro no pé.&lt;/p&gt;
&lt;p class=&quot;msg msg--info&quot;&gt;A foto do seu perfil transmite uma mensagem a quem visita seu perfil, tome cuidado para não transmitir uma mensagem que acabe te prejudicando.&lt;/p&gt;
&lt;h3&gt;Passo 4: habilidades&lt;/h3&gt;
&lt;p&gt;Você sabe Reactjs? Sabe PHP? E CSS?&lt;/p&gt;
&lt;p&gt;É importantíssimo colocar estas habilidades no seu perfil. Quando uma recrutadora busca por perfis que se encaixam numa vaga, normalmente estas habilidades do perfil ajudam a fazer o &lt;em&gt;match&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Mesmo que você não se sinta 100% proficiente com aquela habilidade, marque que a possui. O importante aqui é que encontrem o seu perfil.&lt;/p&gt;
&lt;p&gt;Para adicionar habilidades ao seu perfil, navegue até a seção &quot;Habilidades&quot; e clique no botão &quot;+&quot;:&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/35/adicionar-habilidade-linkedin.png&quot; alt=&quot;Seção de habilidades, e o botão &amp;quot;+&amp;quot; em foco.&quot; width=&quot;1162&quot; height=&quot;438&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Seção de habilidades, e o botão &quot;+&quot; em foco.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Uma tela com diferentes opções vai se abrir pra ti. Escolha uma habilidade daquela lista ou escreva e encontre na lista o que quer descrever. Na imagem abaixo eu estou adicionando a habilidade &lt;em&gt;Blogging&lt;/em&gt; (escrever em blogs):&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/35/adicionar-habilidade-blogging.png&quot; alt=&quot;Escolhendo a habilidade &amp;quot;Blogging&amp;quot; para adicionar ao meu perfil.&quot; width=&quot;1170&quot; height=&quot;744&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Escolhendo a habilidade &quot;&lt;em&gt;Blogging&lt;/em&gt;&quot; para adicionar ao meu perfil.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;No LinkedIn é possível que uma pessoa endosse a sua habilidade. Alguém pode ir até o seu perfil e dizer &quot;olha, esta pessoa MANJA de JavaScript&quot;...&lt;/p&gt;
&lt;p&gt;O que eu aprendi depois de conversar com diferentes profissionais de recrutamento é que: ninguém se importa com estes endossos. É bacana ter, mas eu não investiria muita energia em pedir endosso.&lt;/p&gt;
&lt;p class=&quot;msg msg--info&quot;&gt;Adicione habilidades ao seu perfil para que recrutadoras te encontrem mais facilmente. Não invista muito tempo pedindo endosso de outras pessoas, eles não são tão importantes.&lt;/p&gt;
&lt;h3&gt;Passo 5: experiências e descrições&lt;/h3&gt;
&lt;p&gt;Acho que está claro para todo mundo: se você tem experiência profissional, adicione a empresa, cargo e período no LinkedIn. Este é o básico!&lt;/p&gt;
&lt;p&gt;Uma reclamação comum que eu recebo de recrutadoras é que os perfis normalmente não descrevem o que a pessoa fez naquele cargo, e isso é importantíssimo pra saber em quais contextos as suas habilidades foram executadas.&lt;/p&gt;
&lt;p&gt;O que é interessante para quem analisa o seu perfil:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Com quais tecnologias a pessoa trabalhou;&lt;/li&gt;
&lt;li&gt;Quais responsabilidades aquela pessoa teve;&lt;/li&gt;
&lt;li&gt;Qual o tamanho do time/empresa com que a pessoa já teve experiência;&lt;/li&gt;
&lt;li&gt;Qual era o estilo de colaboração? Scrum, Kanban, Go horse...&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Eu também acho importante colocar o que você curtiu daquela experiência e alguma conquista sua.&lt;/p&gt;
&lt;p&gt;Para adicionar descrição às suas experiências, role até a seção &quot;Experiências&quot; e clique no ícone do lápis para editar as experiências atuais:&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/35/linkedin-experiencias.png&quot; alt=&quot;Seção de &amp;quot;Experiências&amp;quot; no perfil do LinkedIn.&quot; width=&quot;1162&quot; height=&quot;887&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Seção de &quot;Experiências&quot; no perfil do LinkedIn.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Uma nova tela com cada experiência vai aparecer. Selecione uma experiência que ainda não possua descrição, e clique no ícone do lápis para editar:&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/35/editar-experiencia-linkedin.png&quot; alt=&quot;Página de edição de experiências profissionais.&quot; width=&quot;1175&quot; height=&quot;1019&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Página de edição de experiências profissionais.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Ao final da página que irá se abrir você encontra uma caixa de texto chamada &quot;Descrição&quot; onde você pode adicionar mais informações sobre o que fez naquela posição:&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/35/editar-descricao-experiencia-linkedin.png&quot; alt=&quot;&quot; width=&quot;1159&quot; height=&quot;1057&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Página de edição de experiência profissional. Foco no campo &quot;Descrição&quot;.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Note que para aquela experiência eu procurei indicar os desafios e conquistas que eu superei e obtive. Se fosse uma experiência como programador, eu teria indicado as tecnologias, a escala, o estilo de trabalho, um projeto que tenha coordenado e por aí vai.&lt;/p&gt;
&lt;p class=&quot;msg msg--info&quot;&gt;Adicione uma descrição que indique o que fez, como fez, com quais tecnologias, desafios e conquistas para cada experiência profissional descrita no seu perfil!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Não se esqueça de honrar os termos de confidencialidade&lt;/strong&gt; que assinou no passado. É importante dar informação, mas cuidado para não abrir segredos da empresa aqui!&lt;/p&gt;
&lt;h3&gt;Passo 6: monitore a sua conduta e imagem online&lt;/h3&gt;
&lt;p&gt;Todas empresas onde eu trabalhei não fazem isso, mas já recebi muito relato de empresas que dão o famoso &lt;em&gt;stalk&lt;/em&gt; em quem se candidata: verificam facebook, instagram, twitter...&lt;/p&gt;
&lt;p&gt;Portanto monitore a sua imagem e, se possível, mantenha seus perfis separados. O perfil do LinkedIn monta uma imagem profissional de si, e as outras redes uma imagem pessoal. Eu recomendo não misturar as duas.&lt;/p&gt;
&lt;p&gt;E todos nós sabemos como o LinkedIn virou um grande grupo de whatsapp da família: gente mandando vídeo e GIF aleatório de estórias &quot;inspiradoras&quot; inventadas. Há muito espaço pra gente escrota e pra ser escrota ali.&lt;/p&gt;
&lt;p&gt;A minha dica: Nem todo mundo sabe, mas o LinkedIn mantém um resumo das suas atividades. O que você publicou, curtiu, comentou... Esta é uma forma simples e fácil para recrutadoras entenderem melhor quem você é e alguns traços da sua personalidade.&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/35/atividades-linkedin.png&quot; alt=&quot;Seção de atividades no perfil do LinkedIn.&quot; width=&quot;1163&quot; height=&quot;572&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Seção de atividades no perfil do LinkedIn.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p class=&quot;msg msg--info&quot;&gt;&lt;strong&gt;Não seja escroto no LinkedIn.&lt;/strong&gt; E se tiver algo que pode diminuir suas chances de arranjar um emprego ou ser alvo de preconceito – sabemos bem o que pode causar isso – evite mostrar aqui.&lt;/p&gt;
&lt;p&gt;Eu, comunista safado, não conecto redes que não são relevantes ao trabalho e evito expor minha posição política no LinkedIn. Quem se considera &lt;em&gt;queer&lt;/em&gt;, por exemplo, talvez queira seguir o mesmo caminho.&lt;/p&gt;
&lt;p&gt;E eu concordo que se a empresa é retrógrada ninguém deveria querer trabalhar lá em primeiro lugar. Mas eu também entendo que as vezes tanto faz o trabalho porque a vida não para, e muito menos os boletos param de chegar.&lt;/p&gt;
&lt;h2&gt;O passo além: como destacar o seu perfil frente aos outros&lt;/h2&gt;
&lt;p&gt;O que eu descrevi até este ponto é o básico do básico. Se você ainda não fez, para aqui e vai fazer!&lt;/p&gt;
&lt;p&gt;Daqui pra frente a gente começa a deixar o seu perfil mais atrativo. São alguns pequenos passos que vão chamar atenção e ajudar as empresas e recrutadoras a te chamarem pra uma entrevista.&lt;/p&gt;
&lt;h3&gt;Passo 7: altere o seu título para atrair visitas&lt;/h3&gt;
&lt;p&gt;O seu título é aquilo que aparece logo abaixo da sua foto de perfil. Aquele é um espaço incrível para oferecer informações úteis a quem olha o seu LinkedIn.&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/35/titulo-perfil-linkedin.png&quot; alt=&quot;Perfil do LinkedIn com o título em destaque.&quot; width=&quot;801&quot; height=&quot;441&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Perfil do LinkedIn com o título em destaque.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Note que este título não precisa necessariamente ser a sua experiência, mas sim algo relevante para quem contrata!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Muitas vezes este título pode ser o motivo para uma recrutadora clicar no seu perfil ou não.&lt;/strong&gt; Se uma vaga é para Pleno e seu título diz &quot;Procurando estágio&quot; ou &quot;Em transição&quot; provavelmente seu perfil será descartado antes mesmo de ser aberto!&lt;/p&gt;
&lt;p&gt;Caso você seja iniciante ou esteja em transição de carreira, use o título do seu perfil para indicar qual carreira quer seguir. &lt;strong&gt;Você não precisa trabalhar com programação para ser &lt;em&gt;Developer&lt;/em&gt;, você só precisa desenvolver software.&lt;/strong&gt; E isso você pode fazer mesmo sem trabalhar como &lt;em&gt;developer&lt;/em&gt;, por exemplo através de contribuições com &lt;em&gt;Open Source&lt;/em&gt; ou de projetos pessoais.&lt;/p&gt;
&lt;p&gt;Suponha que eu decidi que quero mudar a minha carreira um pouco e me especializar em Golang. Eu já li alguns livros e fiz umas aplicações de brincadeira. Um título útil seria &quot;&lt;em&gt;Desenvolvedor sênior se especializando em Golang&lt;/em&gt;&quot;.&lt;/p&gt;
&lt;p&gt;Não precisa mentir e nem inventar. Apenas deixe claro o que você quer que as pessoas saibam sobre você.&lt;/p&gt;
&lt;p&gt;Para alterar seu título, vá ao topo da página e clique no ícone do lápis à direita da sua foto de perfil:&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/35/editar-titulo-linkedin.png&quot; alt=&quot;Perfil do LinkedIn: clique no lápis para editar seu título.&quot; width=&quot;801&quot; height=&quot;561&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Perfil do LinkedIn: clique no lápis para editar seu título.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;A tela de edição irá aparecer. Seu título fica logo abaixo dos pronomes pelos quais quer que te chamem. Note que &lt;strong&gt;o título não precisa ser a mesma coisa que a sua posição atual.&lt;/strong&gt;&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/35/tela-editar-titulo-linkedin.png&quot; alt=&quot;Alterar título do LinkedIn. O título não precisa ser o mesmo que a sua posição atual!&quot; width=&quot;860&quot; height=&quot;982&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Alterar título do LinkedIn. O título não precisa ser o mesmo que a sua posição atual!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p class=&quot;msg msg--info&quot;&gt;Escreva no título do seu perfil o que vai fazer com que empresas e pessoas recrutadoras cliquem no seu perfil!&lt;/p&gt;
&lt;h3&gt;Passo 8: peça recomendações, e recomende!&lt;/h3&gt;
&lt;p&gt;Isto é algo que eu pequei muito por bastante tempo, mas recomendações são uma ferramenta incrível para transmitir maior confiança a quem emprega.&lt;/p&gt;
&lt;p&gt;Naturalmente você não pode recomendar a si mesmo. &lt;strong&gt;Você vai precisar pedir recomendações de outras pessoas&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Recomendações não ajudam tanto a mostrar como são suas habilidades em determinada tecnologia, mas sim se você consegue trabalhar bem em time, se o time aprende de você ou mesmo se você é uma pessoa confiável.&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/35/recomendacoes-perfil-linkedin.png&quot; alt=&quot;Tela de recomendações do perfil do LinkedIn.&quot; width=&quot;800&quot; height=&quot;441&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Tela de recomendações do perfil do LinkedIn.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p class=&quot;msg msg--info&quot;&gt;Peça recomendações de professoras, instrutoras, colegas de trabalho, gerentes, amigas...&lt;/p&gt;
&lt;p&gt;Se você pedir a 4 pessoas, com certeza ao menos 2 irão lhe recomendar 😉&lt;/p&gt;
&lt;p&gt;Outra coisa que a gente tende a esquecer é que por natureza o ser humano tende a ser recíproco (exceto em São Paulo 👀 – piadas que só um paulistano pode fazer). Se você parar escrever uma recomendação para 10 pessoas, provavelmente ao menos 1 vai te escrever uma recomendação de volta.&lt;/p&gt;
&lt;p&gt;Então além de pedir recomendações, recomende! Mesmo que seja uma recomendação curtinha. Em 1 hora por semana você consegue escrever recomendações o suficiente pra turbinar o seu perfil!&lt;/p&gt;
&lt;p class=&quot;msg msg--info&quot;&gt;Não apenas peça recomendações, recomende!&lt;/p&gt;
&lt;h3&gt;Passo 9: certificações&lt;/h3&gt;
&lt;p&gt;Este é um ponto controverso. Por experiência própria e relato de diferentes recrutadoras, eu sei que certificações não contam muito no perfil do LinkedIn. Muitas vezes serão ignoradas até mesmo durante suas entrevistas.&lt;/p&gt;
&lt;p&gt;Mas há dois casos em que certificações são úteis:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;para que te encontrem na busca do LinkedIn; e&lt;/li&gt;
&lt;li&gt;para áreas pouco conhecidas ou que exigem um selo de confiabilidade&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Por exemplo, empresas que trabalham com &lt;em&gt;blockchain&lt;/em&gt; podem precisar de uma pessoa desenvolvedora que saiba &lt;em&gt;CORDA&lt;/em&gt;. Como é uma tecnologia relativamente nova, a certificação ajuda em muito a demonstrar que você domina aquela tecnologia.&lt;/p&gt;
&lt;p&gt;Outro bom exemplo são as profissões de &lt;em&gt;Agile Coach&lt;/em&gt;, &lt;em&gt;Scrum Master&lt;/em&gt; ou mesmo para quem se especializa em &lt;em&gt;SAP&lt;/em&gt; ou &lt;em&gt;Salesforce&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Mas a certificação em PHP pra ti talvez não faça muita diferença. A não ser que a empresa exija certificação. O mesmo vai para AWS e outras...&lt;/p&gt;
&lt;p&gt;Para adicionar certificações, vá ao topo do seu perfil e clique no botão &quot;Adicionar licença ou certificação&quot;:&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/35/perfil-certificacoes-linkedin.png&quot; alt=&quot;Perfil do LinkedIn: adicionar certificação&quot; width=&quot;1148&quot; height=&quot;466&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Perfil do LinkedIn: adicionar certificação&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;A tela a seguir irá aparecer. Você pode indicar o nome da certificação, quem emitiu o certificado e a data:&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/35/adicionar-certificacao-linkedin.png&quot; alt=&quot;Tela: adicionar licença ou certificação ao seu perfil do LinkedIn.&quot; width=&quot;1175&quot; height=&quot;752&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Tela: adicionar licença ou certificação ao seu perfil do LinkedIn.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p class=&quot;msg msg--info&quot;&gt;Invista em certificações apenas para áreas que realmente precisam. Seu tempo será mais bem gasto trabalhando em outras áreas do seu perfil, ou lendo um livro.&lt;/p&gt;
&lt;h3&gt;Passo 10: links alternativos&lt;/h3&gt;
&lt;p&gt;Eu já participei de conferências, tenho meu próprio blog, tenho um Github que me dá bastante orgulho, já ajudei a organizar &lt;a href=&quot;https://podentender.com.br/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;o maior podcast de ciência em linha reta da América Latina e quiçá de Pernambuco&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Todos estes projetos e referências são importantes pra mostrar quem eu sou e com o que me importo: programação, ciência, compartilhar conteúdo, comunidade...&lt;/p&gt;
&lt;p&gt;Para adicionar um link alternativo, navegue até a seção de destaques do seu perfil e clique no botão &quot;+&quot; e selecione se quer adicionar um artigo, um post dentro do LinkedIn, um link, uma foto ou vídeo, etc.:&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/35/destaques-perfil-linkedin-2.png&quot; alt=&quot;Adicionar destaques ao perfil do LinkedIn.&quot; width=&quot;1145&quot; height=&quot;598&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Adicionar destaques ao perfil do LinkedIn.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p class=&quot;msg msg--info&quot;&gt;Adicione links alternativos que dêem credibilidade ao seu perfil. Adicione entrevistas, palestras, vídeos seus ou artigos que tenha escrito.&lt;/p&gt;
&lt;h3&gt;Passo 11: veja o perfil de outras pessoas e copie o que gostar&lt;/h3&gt;
&lt;p&gt;Esta, na minha opinião, é uma das melhores dicas. Obrigado novamente, &lt;a href=&quot;https://twitter.com/isanortontech&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Isabela Norton (@isanortontech)&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;A melhor forma de entender se eu perfil está bom ou não é comparando com outros perfis. Mas não caia na besteira de querer comparar habilidades, viu? Estou falando de comparar informação disponível.&lt;/p&gt;
&lt;p class=&quot;msg msg--info&quot;&gt;Faça o seu dever de casa: procure 5 perfis que você segue no LinkedIn, ou de influenciadoras por lá e anote o que você gostou e não gostou.&lt;/p&gt;
&lt;p&gt;O próximo passo é simples: copie o que gostou, evite o que não gostou 😉&lt;/p&gt;
&lt;h3&gt;Passo 12: indique que está a procura de trabalho&lt;/h3&gt;
&lt;p&gt;Nem todo mundo está procurando novas oportunidades agora. Uma forma fácil de indicar que você está é marcando no seu perfil do LinkedIn.&lt;/p&gt;
&lt;p&gt;No topo do seu perfil há um botão azul dizendo &quot;Aberto à...&quot;. Clique naquele botão e selecione a opção &quot;Encontrar um novo emprego&quot;, como na imagem abaixo:&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/35/open-to-work-linkedin.png&quot; alt=&quot;Menu: aberto a encontrar um novo emprego.&quot; width=&quot;599&quot; height=&quot;357&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Menu: aberto a encontrar um novo emprego.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;A próxima tela vai te perguntar que tipo de trabalho você está procurando e quem você quer que veja que está a procura de emprego. Você pode, por exemplo, mostrar pra todo mundo mas esconder da sua empresa atual:&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/35/quem-ve-linkedin.png&quot; alt=&quot;Aberto a encontrar novo emprego, e quem vê que estou disponível.&quot; width=&quot;1158&quot; height=&quot;729&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Aberto a encontrar novo emprego, e quem vê que estou disponível.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p class=&quot;msg msg--info&quot;&gt;Indique que está aceitando novos empregos e aguarde diferentes contatos 😉&lt;/p&gt;
&lt;h3&gt;Dica bônus: como aumentar sua visibilidade na rede&lt;/h3&gt;
&lt;p&gt;Lembra quando eu te disse sobre manter seu público alvo em mente?  Essa dica é um exemplo perfeito disso! Vamos brincar com o algoritmo do LinkedIn.&lt;/p&gt;
&lt;p class=&quot;msg msg--highlight &quot;&gt;&lt;strong&gt;💡 Você sabia?&lt;br&gt;&lt;br&gt;&lt;/strong&gt;A busca do LinkedIn mostra &lt;strong&gt;apenas conexões até o terceiro grau&lt;/strong&gt; para quem não é premium.&lt;/p&gt;
&lt;p&gt;Pois é, se a recrutadora não tiver uma conta premium no LinkedIn a busca será limitada. Levando em consideração que uma licença premium custa cerca de R$ 600,00 eu não assumiria que todas empresas e recrutadoras usam LinkedIn premium.&lt;/p&gt;
&lt;p&gt;Caso você não entenda bem o que são conexões de terceiro grau, dê uma olhada nesta &lt;a href=&quot;https://www.linkedin.com/help/linkedin/answer/5245/sua-rede-e-os-graus-de-conexao&quot; rel=&quot;nofollow&quot;&gt;&lt;/a&gt;&lt;a href=&quot;https://www.linkedin.com/help/linkedin/answer/5245/sua-rede-e-os-graus-de-conexao?lang=pt&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;explicação no centro de ajuda do próprio LinkedIn&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Portanto se você quer aumentar suas chances de ser encontrada por empresas e recrutadoras com e sem LinkedIn premium &lt;strong&gt;há uma forma relativamente simples de resolver este problema: criando mais conexões.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Adicione pessoas à sua rede. Pessoas com quem você já estudou, com quem trabalhou, influenciadoras ou até mesmo pessoas dentro da empresa para qual você quer trabalhar.&lt;/p&gt;
&lt;p class=&quot;msg msg--info&quot;&gt;Quanto mais pessoas você adicionar à sua rede e quanto mais pessoas existirem na rede delas, maiores serão as suas chances de aparecer numa busca do LinkedIn.&lt;/p&gt;
&lt;p&gt;Dica de ouro, vai! Merece um compartilhamento no Twitter e seguir o perfil da &lt;a href=&quot;twitter.com/isanortontech&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;Isabela (@isanortontech)&lt;/a&gt; e o meu, &lt;a href=&quot;https://twitter.com/nawarian&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;Nawarian (@nawarian)&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Conclusão&lt;/h2&gt;
&lt;p&gt;Estes 12 passos vão te ajudar em muito a deixar o seu perfil pronto para o primeiro contato com empresas e recrutadoras. &lt;strong&gt;Lembre-se sempre do seu público alvo ao escrever qualquer coisa no seu perfil&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;É claro que a coisa &lt;strong&gt;não para por aqui&lt;/strong&gt;. Você precisa entender como formatar seu Github, como gerenciar outras redes e por aí vai.&lt;/p&gt;
&lt;p&gt;Tudo isso é só o começo, viu? A intenção é &lt;strong&gt;atrair o primeiro contato e permitir que te alcancem com mais facilidade&lt;/strong&gt;. O que vai determinar sua contratação ou não serão suas entrevistas e habilidades técnicas e interpessoais.&lt;/p&gt;
&lt;p&gt;Um grande abraço e te vejo na próxima! 👋&lt;/p&gt;</content:encoded><category>produtividade</category><category>vagas</category><category>carreira</category></item><item><title>Revisão, comentários e críticas ao livro Refactoring, por Martin Fowler</title><link>https://codamos.com.br/livro-refactoring-martin-fowler/</link><guid isPermaLink="true">https://codamos.com.br/livro-refactoring-martin-fowler/</guid><description>Eu li este livro pela primeira vez há alguns anos, e esta já é minha terceira leitura do mesmo título. Eu recomendo DEMAIS ler este livro e tirar suas próprias conclusões, citações e o que mais for. E</description><pubDate>Mon, 14 Mar 2022 09:35:47 GMT</pubDate><content:encoded>&lt;p&gt;Eu li este livro pela primeira vez há alguns anos, e esta já é minha terceira leitura do mesmo título. Eu recomendo DEMAIS ler este livro e tirar suas próprias conclusões, citações e o que mais for.&lt;/p&gt;
&lt;p&gt;Este artigo vai com certeza enviesar a forma como você vai ler o &lt;a href=&quot;https://bit.ly/refactoring-mfowler&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;livro &lt;em&gt;Refactoring&lt;/em&gt;&lt;/a&gt;, mas o conteúdo e qualidade do livro não mudam. E caso você tenha dificuldade com leituras longas, com certeza vai ser útil pra ti ler este artigo primeiro.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Esta é uma literatura fundamental para toda pessoa que trabalha com desenvolvimento de software&lt;/strong&gt;. Eu desconfiaria de qualquer dev sênior que nunca tenha ouvido falar do termo &lt;em&gt;Refactoring (refatoração)&lt;/em&gt;.&lt;/p&gt;
&lt;div class=&quot;post__toc&quot;&gt;
&lt;h3&gt;Conteúdos deste artigo&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fu2gdquma50&quot;&gt;Revisão e ideias centrais&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fu2gdquma51&quot;&gt;A estrutura do livro&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fu2gdquma52&quot;&gt;O que é refatoração?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fu2gdquma53&quot;&gt;Por que refatorar?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fu2gdquma54&quot;&gt;Quando refatorar?&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fu2gdquma55&quot;&gt;Refatoração antes de alterar o código&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fu2gdquma56&quot;&gt;Refatoração depois de alterar o código&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fu2gdquma57&quot;&gt;O que testes têm a ver com refatoração?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fu2gdquma58&quot;&gt;Refatorar sempre, em pequenos passos&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fu2gdquma59&quot;&gt;Críticas ao livro Refactoring, por Martin Fowler&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fu2gdquma5a&quot;&gt;Definição de refatoração ao pé da letra não dá&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fu2gdquma5b&quot;&gt;O que eu devo dizer ao meu gerente?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fu2gdquma5c&quot;&gt;Dados duvidosos&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fu2gdquma5d&quot;&gt;O que fazer com códigos legados?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fu2gdquma5e&quot;&gt;Desmistificação do argumento da performance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fu2gdquma5f&quot;&gt;Uma refatoração pode desfazer a outra, e tudo bem&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fu2gdquma5g&quot;&gt;Considerações finais&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id=&quot;mcetoc_1fu2gdquma50&quot;&gt;Revisão e ideias centrais&lt;/h2&gt;
&lt;h3 id=&quot;mcetoc_1fu2gdquma51&quot;&gt;A estrutura do livro&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;O livro possui duas partes&lt;/strong&gt;: a primeira apresenta a &lt;strong&gt;teoria de refatoração&lt;/strong&gt; e alguns exemplos práticos enquanto a segunda parte é só &lt;strong&gt;um catálogo de refatorações&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Dentre os exemplos Martin Fowler mostra alguns códigos – a última edição vem com &lt;strong&gt;códigos em JavaScript&lt;/strong&gt;, bem feios por sinal – e explica, passo a passo, como torná-los &lt;strong&gt;mais legíveis e mais fáceis de testar&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;O catálogo de refatoração mostra não só o motivo daquela refatoração, mas também dá um nome à elas. Isto é poderozíssimo porque cria um vocabulário comum entre pessoas desenvolvedoras. &lt;strong&gt;Da mesma forma que você entende facilmente o que é uma classe do tipo &lt;em&gt;Factory&lt;/em&gt;, o livro busca criar compreensão sobre o que significa a refatoração &lt;em&gt;Extrair Método&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ler os exemplos do livro é uma experiência mágica&lt;/strong&gt; porque o autor não apenas explica o que está acontecendo linha a linha, mas também faz referência aos nomes das refatorações que utilizou de seu próprio catálogo.&lt;/p&gt;
&lt;p&gt;Neste artigo eu não vou focar no catálogo em si, mas sim na parte teórica. &lt;strong&gt;Se você tem curiosidade sobre o catálogo&lt;/strong&gt;, dê uma olhada na apresentação da incrível &lt;a href=&quot;https://twitter.com/jucycabrera&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Jucy Cabrera (@jucycabrera)&lt;/a&gt; fez ano passado no Locaweb PHP Community Summit.&lt;/p&gt;
&lt;p&gt;&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;//www.youtube.com/embed/SJPZxvEYXxI?start=7463&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;allowfullscreen&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p class=&quot;msg msg--highlight &quot;&gt;A apresentação da Jucy começa no minuto 02:03:00&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fu2gdquma52&quot;&gt;O que é refatoração?&lt;/h3&gt;
&lt;p&gt;Refatoração, de acordo com Martin Fowler, é o ato de &lt;strong&gt;alterar um código sem mudar o seu comportamento observável.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Por exemplo, a função a seguir recebe dois parâmetros e retorna um inteiro, contendo a soma destes dois parâmetros:&lt;/p&gt;
&lt;pre&gt;function sum(int a, int b): int&lt;br&gt;{&lt;br&gt;  for (; a &amp;lt; b; a++) return a&lt;br&gt;}&lt;/pre&gt;
&lt;p&gt;Não há nada de errado com este código, exceto pelo fato de fazer pouco sentido fazer uma soma desta forma. Mas de toda forma, se chamarmos a função desta forma &lt;code&gt;sum(10, 10)&lt;/code&gt; receberemos o valor 20, e se chamarmos assim &lt;code&gt;sum(20, 30)&lt;/code&gt; receberemos o valor 50.&lt;/p&gt;
&lt;p&gt;Alterar o código da função acima de forma que ao receber os mesmos parâmetros ela retornará os mesmos valores é uma refatoração. Vejamos:&lt;/p&gt;
&lt;pre&gt;function sum(int a, int b): int&lt;br&gt;{&lt;br&gt;  return a + b&lt;br&gt;}&lt;/pre&gt;
&lt;p&gt;Porém alterar a assinatura da função, por exemplo, não é uma refatoração. Ou adicionar lógicas à ela. O seguinte &lt;em&gt;snippet&lt;/em&gt; não pode ser considerado refatoração, porque muda a assinatura da função:&lt;/p&gt;
&lt;pre&gt;function sum(int a, int b): float&lt;br&gt;{&lt;br&gt;  if (a &amp;lt; 0 || b &amp;lt; 0) throw &apos;Dont be so negative&apos;&lt;br&gt;  return parseFloat(a + b)&lt;br&gt;}&lt;/pre&gt;
&lt;p&gt;Ao alterar a função acima desta forma nós deixamos de somente refatorar o código e passamos a reescrevê-lo por conta de três alterações principais:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;O tipo de retorno mudou de &lt;em&gt;int&lt;/em&gt; para &lt;em&gt;float;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Adicionamos uma lógica que lança exceção;&lt;/li&gt;
&lt;li&gt;Utilizamos a função &lt;code&gt;parseFloat()&lt;/code&gt; que pode alterar fundamentalmente o valor esperado&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Note também que &quot;refatoração&quot; depende muito do nível de abstração a partir do qual observamos. Uma reescrita a nível de função pode ser uma refatoração a nível de módulo.&lt;/p&gt;
&lt;p&gt;Um ponto importantíssimo citado no livro fala sobre as oportunidades de corrigir um erro ou mal funcionamento do software. Corrigir um &lt;em&gt;bug&lt;/em&gt; ou adicionar uma funcionalidade só porque &quot;está fácil&quot; ou na cara não é refatorar e deveria ser evitado.&lt;/p&gt;
&lt;p class=&quot;msg msg--success&quot;&gt;&lt;strong&gt;👉  Refatorar é alterar um código sem mudar o seu comportamento observável.&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fu2gdquma53&quot;&gt;Por que refatorar?&lt;/h3&gt;
&lt;p&gt;O livro desenvolve a ideia de que &lt;strong&gt;todo software perde qualidade com o tempo e sua arquitetura fica obsoleta&lt;/strong&gt;. Alguns dos motivos eu descrevo abaixo:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;O ambiente de desenvolvimento&lt;/strong&gt; (linguagem de programação, &lt;em&gt;framework&lt;/em&gt;, bibliotecas, infraestrutura...) &lt;strong&gt;evolui&lt;/strong&gt; com o tempo e algumas decisões de arquitetura ficam obsoletas;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ao adicionar código&lt;/strong&gt; seja para corrigir bugs ou adicionar funcionalidades, nós &lt;strong&gt;adicionamos dependências e débito técnico&lt;/strong&gt; que se acumula com o tempo&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Em vez de estressar a arquitetura e design ao extremo até o ponto de não podermos mais adicionar nenhuma funcionalidade, Martin Fowler propõe que a gente &lt;strong&gt;melhore a qualidade de nossos softwares com frequência&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Refatoração nos permite evoluir e atualizar a arquitetura de design do software constantemente. &lt;strong&gt;É importante refatorar porque desta forma evitamos a degradação do design do software de forma gradual em vez de investir em grandes correções e reescritas&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fu2gdquma54&quot;&gt;Quando refatorar?&lt;/h3&gt;
&lt;p&gt;O livro explicita &lt;strong&gt;dois momentos essenciais&lt;/strong&gt; para executar uma refatoração: &lt;strong&gt;antes e depois de escrever&lt;/strong&gt; alguma alteração no código.&lt;/p&gt;
&lt;h4 id=&quot;mcetoc_1fu2gdquma55&quot;&gt;Refatoração antes de alterar o código&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Quando se investiga um &lt;em&gt;bug&lt;/em&gt;&lt;/strong&gt;, refatorar aquele pedaço de código é uma técnica muito útil para entender o que aquele código faz. E quando é necessário cobrir o código com testes, fica muito mais fácil. &lt;strong&gt;Normalmente durante a refatoração, o &lt;em&gt;bug&lt;/em&gt; e sua correção ficam mais claros&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Por extensão, &lt;strong&gt;quando se precisa entender melhor o que determinado trecho de código faz&lt;/strong&gt;, a refatoração também é uma ferramenta incrível.&lt;/p&gt;
&lt;p class=&quot;msg msg--success&quot;&gt;&lt;strong&gt;👉  Sempre que você precisar escrever um trecho novo de código, refatore antes.&lt;/strong&gt;&lt;/p&gt;
&lt;h4 id=&quot;mcetoc_1fu2gdquma56&quot;&gt;Refatoração depois de alterar o código&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Quando a sua atualização estiver pronta para ser entregue&lt;/strong&gt;, é o momento perfeito para refatorar mais uma vez. Este momento é a sua oportunidade perfeita para revisar suas alterações e garantir que a próxima pessoa que visitar aquele código vai entender com facilidade o que foi escrito. Provavelmente vai ser você quem vai visitar este código da próxima vez de toda forma, seja gentil consigo 😉.&lt;/p&gt;
&lt;p&gt;Como eu já comentei no meu artigo sobre &lt;a href=&quot;/guia-estilo-de-codigo-para-iniciantes/&quot;&gt;estilo de código para iniciantes&lt;/a&gt;, &lt;strong&gt;um comportamento chave de toda pessoa desenvolvedora experiente é escrever código para pessoas em vez de para computadores&lt;/strong&gt;.&lt;a href=&quot;/guia-estilo-de-codigo-para-iniciantes/&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Outras oportunidades para refatoração após escrever o código podem aparecer &lt;strong&gt;durante um &lt;/strong&gt;&lt;em&gt;&lt;strong&gt;Code Review&lt;/strong&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fu2gdquma57&quot;&gt;O que testes têm a ver com refatoração?&lt;/h3&gt;
&lt;p&gt;A definição que o livro dá sobre refatoração é: &lt;strong&gt;alterar um código sem mudar o seu comportamento observável.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Eu só conheço uma forma de &lt;strong&gt;provar que o software não passou a se comportar de forma diferente: através de testes&lt;/strong&gt;. De preferência, testes automatizados.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;É essencial que um código esteja coberto com testes antes de passar por uma refatoração.&lt;/strong&gt; Do contrário você pode estar introduzindo bugs silenciosos sem sequer saber.&lt;/p&gt;
&lt;p class=&quot;msg msg--success&quot;&gt;👉  Se você não tinha cobertura de testes antes de refatorar, você não está fazendo uma refatoração mas sim uma reescrita.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fu2gdquma58&quot;&gt;Refatorar sempre, em pequenos passos&lt;/h3&gt;
&lt;p&gt;Em resumo, &lt;strong&gt;devemos refatorar sempre que possível&lt;/strong&gt;. Refatorar antes de escrever um código para que este possa receber as nossas alterações sem muita dificuldade, e depois de escrever um código como quem dá um acabamento ao trabalho.&lt;/p&gt;
&lt;p&gt;Como eu comentei no artigo sobre &lt;a href=&quot;/programacao-por-coincidencia/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;como evitar programar por coincidência&lt;/a&gt;, &lt;strong&gt;a refatoração é o &lt;em&gt;mise en place&lt;/em&gt; da pessoa programadora&lt;/strong&gt;. Não deveria ser opcional, mas sim parte do nosso fluxo normal de trabalho.&lt;/p&gt;
&lt;p&gt;É importante notar que o &lt;em&gt;code review&lt;/em&gt; pode ficar muito confuso quando muitas alterações são feitas por conta de refatoração. Minha recomendação é refatorar sempre em pequenos passos, e testar o software após cada passo. &lt;strong&gt;O ideal é fazer um commit para cada refatoração aplicada.&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&quot;msg msg--success&quot;&gt;👉  Para cada refatoração, faça um commit. Isso te ajuda a se organizar e a organizar o &lt;em&gt;Code Review &lt;/em&gt;mais tarde.&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1fu2gdquma59&quot;&gt;Críticas ao livro &lt;em&gt;Refactoring&lt;/em&gt;, por Martin Fowler&lt;/h2&gt;
&lt;p&gt;Todos sabemos que Martin Fowler é uma referência internacional quando se fala de desenvolvimento de software, mas &lt;strong&gt;ninguém é infalível&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Aqui, eu deixo algumas críticas minhas sobre o livro: são pontos de divergência ou apenas comentários que eu tenho e acho importante prestarmos atenção.&lt;/p&gt;
&lt;p&gt;Quando falamos de desenvolvimento de software, quase tudo depende. Então &lt;strong&gt;é importante manter estas críticas em mente para evitar dogmatismo em torno do tema&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fu2gdquma5a&quot;&gt;Definição de refatoração ao pé da letra não dá&lt;/h3&gt;
&lt;p&gt;Como eu comentei anteriormente, refatoração pode acontecer em diferentes níveis de abstração. Alterar a assinatura de uma função é considerado reescrita naquele escopo, mas ao observarmos um módulo pode ser considerado refatoração.&lt;/p&gt;
&lt;p&gt;Da mesma forma, é possível reescrever partes de um módulo enquanto fazemos uma refatoração a nível de API REST.&lt;/p&gt;
&lt;p&gt;O importante aqui é &lt;strong&gt;sempre refatorar somente com cobertura de testes e a pequenos passos incrementais&lt;/strong&gt;. Quanto maior o seu nível de abstração, mais importante é mover-se a passos pequenos.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fu2gdquma5b&quot;&gt;O que eu devo dizer ao meu gerente?&lt;/h3&gt;
&lt;p&gt;O livro diz brevemente como você, enquanto pessoa desenvolvedora, deveria justificar o tempo gasto em refatoração ao gerente/cliente. Afinal, refatoração consome mais tempo do que simplesmente escrever a sua funcionalidade.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;O livro nos instrui a simplesmente omitir a refatoração ao nosso cliente&lt;/strong&gt;. &quot;O que dizer? Nada!&quot;. A justificativa do livro é que a refatoração vai facilitar a preparação do ambiente para que você faça as alterações que precisa.&lt;/p&gt;
&lt;p&gt;Enquanto &lt;strong&gt;eu concordo com a justificativa&lt;/strong&gt;, eu discordo sobre precisarmos nos calar sobre o esforço de refatoração. Da mesma forma como um profissional de saúde precisa usar máscara e luvas, nós precisamos refatorar.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/guia-estilo-de-codigo-para-iniciantes/&quot;&gt;Como já eu escrevi antes&lt;/a&gt;, refatoração é o &lt;em&gt;mese en place&lt;/em&gt; da pessoa programadora. Não há necessidade de justificar a necessidade de refatorar um código, &lt;strong&gt;mas é necessário falar sobre e encorajar outras pessoas&lt;/strong&gt; a fazerem o mesmo.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fu2gdquma5c&quot;&gt;Dados duvidosos&lt;/h3&gt;
&lt;p&gt;Apesar de o livro trazer uma retórica bem convincente sobre refatoração, motivos para adotar a prática e como convencer seus colegas, a amostragem de dados é no mínimo... duvidosa.&lt;/p&gt;
&lt;p&gt;No capítulo 2, o autor mostra um gráfico onde compara o montante de funcionalidades entregues com o tempo em projetos com bom design vs. projetos com mal design. &lt;strong&gt;De acordo com o gráfico, projetos com bom design tem crescimento linear, projetos com mal design têm uma tendência quase constante de entregas.&lt;/strong&gt;&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/34/grafico-bom-design-vs-mau-design-2.png&quot; alt=&quot;Gráfico: funcionalidades x tempo, comparando bom design e mal design.&quot; width=&quot;490&quot; height=&quot;302&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Gráfico: funcionalidades x tempo, comparando bom design e mal design.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;Mas o autor não apresenta nenhum dado concreto ou explica como chegou àquele gráfico.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Pessoalmente eu não vejo muito problema sobre falta de dados, as práticas se justificam por si só. Mas na minha opinião, toda pessoa quando falar sobre engenharia de software, deveria evitar fazer afirmações desta natureza sem dados concretos e disponíveis.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fu2gdquma5d&quot;&gt;O que fazer com códigos legados?&lt;/h3&gt;
&lt;p&gt;O autor não dá muita informação sobre como lidar com sistemas legados e indica o livro &lt;em&gt;Working Effectively with Legacy Code&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Na minha opinião esta indicação é horrível. Este livro é terrível e induz quem lê a fazer exatamente o contrário de refatorar: dar manutenção ao mal design do sistema.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Eu recomendo a leitura crítica do &lt;a href=&quot;https://bit.ly/working-with-legacy-code-book&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;livro &lt;em&gt;Working Effectively with Legacy Code&lt;/em&gt;&lt;/a&gt;, não acho que devemos ignorar esta literatura. Mas tenho MUITAS ressalvas com este título e recomendo atenção dobrada ao aplicar as dicas descritas nele.&lt;/p&gt;
&lt;p&gt;Um exemplo mais em linha com o livro &lt;em&gt;Refactoring&lt;/em&gt;, na minha opinião, é o livro &lt;em&gt;&lt;a href=&quot;https://bit.ly/modernizing-php&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Modernizing Legacy PHP Applications&lt;/a&gt;&lt;/em&gt; do Paul M. Jones. Apesar de ser específico à aplicações PHP, o livro adota uma prática 100% em linha com a descrita pelo livro &lt;em&gt;Refactoring&lt;/em&gt;: pequenas alterações, modernização do design e pragmatismo.&lt;/p&gt;
&lt;p&gt;&lt;img class=&quot;post__image post__image--center&quot; src=&quot;/media/posts/34/sim-nao-meme.jpeg&quot; alt=&quot;Meme: personagem rejeitando o livro &amp;quot;Working effectively with legacy code&amp;quot; e aprovando o livro &amp;quot;Modernizing Legacy Applications in PHP&amp;quot;&quot; width=&quot;559&quot; height=&quot;447&quot;&gt;&lt;/p&gt;
&lt;p&gt;Eu acho especialmente estranha a indicação do livro &lt;em&gt;Working Effectively with Legacy Code &lt;/em&gt;porque o Martin Fowler já escreveu sobre &lt;a href=&quot;https://martinfowler.com/bliki/StranglerFigApplication.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;StranglerFigApplication&lt;/a&gt; antes, uma forma de evoluir o design da aplicação como um todo.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fu2gdquma5e&quot;&gt;Desmistificação do argumento da performance&lt;/h3&gt;
&lt;p&gt;Eu achei bacana que o livro buscou desmistificar o argumento da performance a todo custo. Já vi muito &lt;em&gt;code review&lt;/em&gt; ser recusado por códigos como o seguinte:&lt;/p&gt;
&lt;pre&gt;lista.map(...).map(...).filter(...)&lt;/pre&gt;
&lt;p&gt;A justificativa? O &lt;code&gt;map&lt;/code&gt; itera a lista inteira, encadear dois maps é ruim para a performance a lista inteira vai ser percorrida duas vezes. E o &lt;code&gt;filter&lt;/code&gt; ao final vai reduzir o número de itens na lista. Seria ideal colocar o filter primeiro para que a lista inteira seja menor antes do map.&lt;/p&gt;
&lt;p&gt;Faz sentido, mas dependendo do tipo de dado que o código está lidando, não faz nenhuma diferença na prática. Performance importa, mas micro otimizações podem ser ignoradas em favor de legibilidade de código.&lt;/p&gt;
&lt;p&gt;Mas é importante não levar isto como dogma (dogmas em geral são ruins, principalmente em desenvolvimento de software). &lt;strong&gt;Performance é importante e as vezes uma refatoração pode causar danos imensos em termos de performance.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Busque o equilíbrio.&lt;/strong&gt; Mas não aceite um &lt;em&gt;code review&lt;/em&gt; recusado que use performance como desculpa sem trazer dados. &lt;strong&gt;Se a discrepância de performance estiver na magnitude dos nanossegundos, quase sempre pode-se ignorar com segurança a recomendação de melhoria performance.&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fu2gdquma5f&quot;&gt;Uma refatoração pode desfazer a outra, e tudo bem&lt;/h3&gt;
&lt;p&gt;Algo que o livro menciona brevemente mas eu acho importante destacar é que as vezes uma refatoração vai desfazer o que outra refatoração fez antes. E isto é normal.&lt;/p&gt;
&lt;p&gt;A refatoração é um mecanismo que te ajuda a preparar o ambiente para receber seu código. Se voltar ao estado anterior é melhor para receber seu código, então voltemos ao estado anterior sem medo ou vergonha.&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1fu2gdquma5g&quot;&gt;Considerações finais&lt;/h2&gt;
&lt;p&gt;O livro &lt;em&gt;Refactoring&lt;/em&gt;, do Martin Fowler, é um dos livros base para toda pessoa programadora. Se você puder levar um único parágrafo deste texto todo contigo, leve este:&lt;/p&gt;
&lt;p class=&quot;msg msg--success&quot;&gt;Para refatorar, &lt;strong&gt;é essencial ter cobertura de testes&lt;/strong&gt;. Refatore antes de alterar o software. Refatore depois de alterar o software. Encoraje outras pessoas a fazer o mesmo!&lt;/p&gt;
&lt;p&gt;E, claro, &lt;strong&gt;leia o livro&lt;/strong&gt; e tire suas próprias conclusões.&lt;/p&gt;
&lt;p&gt;Neste artigo eu mencionei três livros. Aqui os links para cada um:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p class=&quot;p1&quot;&gt;&lt;a href=&quot;https://bit.ly/refactoring-mfowler&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Refactoring: Improving the Design of Existing Code, por Martin Fowler&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://bit.ly/working-with-legacy-code-book&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Working Effectively with Legacy Code, por Michael Feathers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://bit.ly/modernizing-php&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Modernizing Legacy Applications in PHP, por Paul M. Jones&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Até a próxima! 👋&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded><category>livro</category><category>produtividade</category></item><item><title>Node.js, V8, e as 5 fases do Event Loop</title><link>https://codamos.com.br/nodejs-v8-fases-do-event-loop/</link><guid isPermaLink="true">https://codamos.com.br/nodejs-v8-fases-do-event-loop/</guid><description>A linguagem JavaScript é conhecida por executar de forma assíncrona, apesar de não oferecer suporte direto a multithreading . O mecanismo que habilita este comportamento da linguagem é o Event Loop , </description><pubDate>Mon, 07 Mar 2022 12:01:30 GMT</pubDate><content:encoded>&lt;p&gt;A linguagem JavaScript é conhecida por executar de forma assíncrona, apesar de não oferecer suporte direto a &lt;em&gt;multithreading&lt;/em&gt;. O mecanismo que habilita este comportamento da linguagem é o &lt;em&gt;Event Loop&lt;/em&gt;, que eu vou explicar melhor sobre neste post.&lt;/p&gt;
&lt;p&gt;O ambiente NodeJS em si utiliza diferentes &lt;em&gt;threads&lt;/em&gt; internamente, mas este mecanismo não é exposto via JavaScript. &lt;a href=&quot;/como-funciona-javascript-motor-v8/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Para aprender sobre as diferentes threads do NodeJS, dá uma olhada neste outro artigo sobre como funciona o motor V8&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As minhas duas referências para escrever este post foram a documentação oficial do NodeJS e o livro &lt;a href=&quot;https://bit.ly/distributed-systems-with-nodejs&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Distributed Systems with Node.js&lt;/a&gt;, do Thomas Hunter e publicado pela O&apos;Reilly.&lt;/p&gt;
&lt;h2&gt;Código bloqueante e não bloqueante? Hã?&lt;/h2&gt;
&lt;p&gt;Deixa eu explicar um pouquinho melhor o que é uma operação de E/S e qual a diferença entre esta operação ser bloqueante ou não bloqueante.&lt;/p&gt;
&lt;p&gt;Operações de Entrada e Saída (E/S) são todas as operações que não dependem somente do Processador (CPU) e memória. Toda interação com o disco rígido, teclado, mouse, internet, bluetooth... todas essas interações são consideradas operações de E/S.&lt;/p&gt;
&lt;p&gt;Naturalmente toda operação de E/S demoram um tempo consideravelmente maior do que operações &quot;puras&quot; que dependem somente da CPU.&lt;/p&gt;
&lt;p&gt;Vamos imaginar um programa que executa duas operações: &lt;code&gt;Operação A&lt;/code&gt; e &lt;code&gt;Operação B&lt;/code&gt;. A Operação A leva um pouquinho mais tempo para finalizar em comparação à Operação B e as duas são executadas em sequência. Veja:&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/33/operacao-a-operacao-b-em-sequencia.png&quot; alt=&quot;Duas operações executando em sequência. A Operação A leva um pouco mais de tempo que a Operação B.&quot; width=&quot;478&quot; height=&quot;208&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Duas operações executando em sequência. A &lt;em&gt;Operação A&lt;/em&gt; leva um pouco mais de tempo que a &lt;em&gt;Operação B&lt;/em&gt;.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Agora vamos considerar que a &lt;code&gt;Operação A&lt;/code&gt; na verdade demora mais tempo para executar porque precisa escrever num arquivo chamado &lt;code&gt;arquivo.txt&lt;/code&gt;, uma operação de E/S representada pela sub-rotina &lt;code&gt;Escrever &quot;arquivo.txt&quot;&lt;/code&gt; na próxima figura:&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/33/operacao-a-escreve-arquivo-txt.png&quot; alt=&quot;Operação A, explicitamente bloqueada pela sub-rotina Escrever &amp;quot;arquivo.txt&amp;quot;. Só depois desta execução, a Operação B irá rodar.&quot; width=&quot;478&quot; height=&quot;208&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Operação A, explicitamente bloqueada pela sub-rotina &lt;em&gt;Escrever &quot;arquivo.txt&quot;&lt;/em&gt;. Só depois desta execução, a Operação B irá rodar.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Note que a &lt;em&gt;Operação A&lt;/em&gt; depende de que a sub-rotina chegue ao seu fim para poder ser finalizada, e que de toda forma &lt;em&gt;Operação B&lt;/em&gt; só é executada depois de tudo isso.&lt;/p&gt;
&lt;p&gt;Este esquema pode ser considerado &lt;strong&gt;&lt;em&gt;bloqueante&lt;/em&gt;&lt;/strong&gt; porque a &lt;em&gt;Operação A&lt;/em&gt; fica &quot;bloqueada&quot;, aguardando o resultado da sub-rotina &lt;em&gt;Escrever &quot;arquivo.txt&quot;&lt;/em&gt; e nada além disso é executado. Uma representação mais justa ficaria assim:&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/33/es-bloqueante.png&quot; alt=&quot;Explicitamente a Operação A executa um pouco, é interrompida pela sub-rotina Escrever &amp;quot;arquivo.txt&amp;quot; e retomada assim que a sub-rotina se encerra. Só depois a Operação B executa.&quot; width=&quot;478&quot; height=&quot;208&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Explicitamente a Operação A executa um pouco, é interrompida pela sub-rotina &lt;em&gt;Escrever &quot;arquivo.txt&quot;&lt;/em&gt; e retomada assim que a sub-rotina se encerra. Só depois a Operação B executa.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Acontece que, como eu mencionei antes, a sub-rotina &lt;em&gt;Escrever &quot;arquivo.txt&quot;&lt;/em&gt; não depende tão somente da CPU. Na realidade a menor parte do tempo desta operação se dá em tempo de CPU, enquanto a maior parte do tempo é gasta em periféricos.&lt;/p&gt;
&lt;p&gt;Uma outra forma de resolver este problema é permitir que a CPU execute diferentes operações enquanto aguarda a resposta do hardware de E/S. Esta forma é chamada de &lt;strong&gt;&lt;em&gt;não bloqueante&lt;/em&gt;&lt;/strong&gt; e é mais ou menos como na imagem a seguir:&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/33/es-nao-bloqueante-2.png&quot; alt=&quot;Execução não bloqueante. A Operação A inicia e solicita uma operação de E/S, que roda em paralelo. Imediatamente a Operação B executa. Assim que a operação de E/S está pronta, retomamos a Operação A.&quot; width=&quot;478&quot; height=&quot;208&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Execução &lt;em&gt;não bloqueante. &lt;/em&gt;A Operação A inicia e solicita uma operação de E/S, que roda em paralelo. Imediatamente a Operação B executa. Assim que a operação de E/S está pronta, retomamos a Operação A.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Inicialmente a &lt;em&gt;Operação A&lt;/em&gt; solicita uma operação de E/S e delega ao Sistema Operacional para que lide com aquela operação. Desta forma o processo está livre para executar outras operações, e imediatamente começa a executar a &lt;em&gt;Operação B&lt;/em&gt;. Finalmente o Sistema Operacional nos informa que a operação de E/S finalizou, e podemos retomar o restante da &lt;em&gt;Operação A&lt;/em&gt; que havia sido interrompida.&lt;/p&gt;
&lt;p class=&quot;msg msg--success&quot;&gt;Este modelo, onde uma operação de E/S não precisa segurar a aplicação inteira, é chamado de &lt;em&gt;&lt;strong&gt;E/S não bloqueante&lt;/strong&gt;&lt;/em&gt;&lt;em&gt; – ou non-blocking I/O, em inglês.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;É natural pensar que uma aplicação não possui apenas 2 operações, mas sim milhares delas. Gerenciar tudo isso não é uma tarefa trivial e muito menos uma tarefa que você deva se preocupar em resolver todas as vezes.&lt;/p&gt;
&lt;p&gt;O motor V8 e, por conseguinte, o ambiente Node.js resolvem o problema de gerenciamento destas tarefas e suas interrupções através de um mecanismo chamado &lt;em&gt;Event Loop&lt;/em&gt;.&lt;/p&gt;
&lt;h2&gt;O que é o &lt;em&gt;Event Loop&lt;/em&gt;?&lt;/h2&gt;
&lt;p&gt;O &lt;em&gt;Event Loop&lt;/em&gt; é um mecanismo que agrega diversas filas internas e &lt;em&gt;threads&lt;/em&gt; para otimizar o processamento e toma proveito de técnicas como E/S não bloqueante e sinais do sistema operacional.&lt;/p&gt;
&lt;p&gt;O &lt;em&gt;Event Loop&lt;/em&gt; no motor V8 mantém um &lt;em&gt;thread principal&lt;/em&gt; que gerencia várias filas e determina quais operações devem executar em que momentos. Quando necessário executar uma operação mais custosa, como uma operação de E/S, a &lt;em&gt;thread principal&lt;/em&gt; então solicita uma nova &lt;em&gt;thread&lt;/em&gt; para cuidar daquela operação.&lt;/p&gt;
&lt;p&gt;Eu tentei ilustrar este mecanismo no GIF abaixo:&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/33/fila-operacoes-es.gif&quot; alt=&quot;Animação (ultra simplificada) exemplificando como as operações são enviadas à filas específicas.&quot; width=&quot;571&quot; height=&quot;282&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Animação (ultra simplificada) exemplificando como as operações são enviadas à filas específicas.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Esta é uma representação ultra simplificada da coisa toda, mas serve para ilustrar mais ou menos o que o &lt;em&gt;Event Loop&lt;/em&gt; faz.&lt;/p&gt;
&lt;p class=&quot;msg msg--success&quot;&gt;O &lt;em&gt;event loop&lt;/em&gt; possui diferentes filas com &lt;em&gt;callbacks (funções)&lt;/em&gt; e gerencia quando determinada função nestas filas deveria executar.&lt;/p&gt;
&lt;p&gt;Mas eu não quero manter essa explicação superficial (e parcialmente errada). Vamos dar uma olhadinha na forma como o &lt;em&gt;Event Loop&lt;/em&gt; funciona.&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-size: 29.4733px; letter-spacing: -0.552px;&quot;&gt;&lt;strong&gt;As 5 fases do &lt;em&gt;Event Loop&lt;/em&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Quando um processo Node.js é inicializado, o &lt;em&gt;Event Loop&lt;/em&gt; começa. Dentro de um script várias chamadas a funções, chamadas assíncronas, &lt;em&gt;timers&lt;/em&gt; e outros tipos de chamadas podem acontecer.&lt;/p&gt;
&lt;p&gt;Como o nome sugere, o &lt;em&gt;Event Loop&lt;/em&gt; é na verdade um loop infinito (&lt;code&gt;while true&lt;/code&gt; mesmo) que a cada iteração tenta executar um pouquinho de cada fila diferente. Há 5 fases distintas que o &lt;em&gt;Event Loop&lt;/em&gt; trata a cada iteração.&lt;/p&gt;
&lt;p&gt;Uma visualização mega simplificada (e incorreta) e didática do &lt;em&gt;Event Loop&lt;/em&gt; é a seguinte:&lt;/p&gt;
&lt;pre&gt;while (true) {&lt;br&gt;  poll()&lt;br&gt;  check()&lt;br&gt;  close()&lt;br&gt;  timers()&lt;br&gt;  pending()&lt;br&gt;}&lt;/pre&gt;
&lt;p&gt;Cada função chamada alí representa uma fase da iteração do &lt;em&gt;Event Loop&lt;/em&gt;. Abaixo eu descrevo com mais detalhes o que cada fase faz. Mas por enquanto, este infográfico já deve te ajudar a entender um pouco o que tá rolando:&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/33/fases-js-2.png&quot; alt=&quot;As 5 fases do ciclo de vida do Event Loop no JavaScript.&quot; width=&quot;1024&quot; height=&quot;768&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;As 5 fases do ciclo de vida do &lt;em&gt;Event Loop&lt;/em&gt; no JavaScript: &lt;em&gt;poll&lt;/em&gt;, &lt;em&gt;check&lt;/em&gt;, &lt;em&gt;close&lt;/em&gt;, &lt;em&gt;timers&lt;/em&gt; e &lt;em&gt;pending&lt;/em&gt;.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Cada uma das fases acima possui uma fila de &lt;em&gt;callbacks&lt;/em&gt;. Quando a fase se inicia, Node.js tenta executar &lt;em&gt;todos&lt;/em&gt; os &lt;em&gt;callbacks&lt;/em&gt; daquela fila: até que a fila fique vazia ou até que o número máximo de &lt;em&gt;callbacks&lt;/em&gt; por iteração já tenham executado.&lt;/p&gt;
&lt;p&gt;Algo assim:&lt;/p&gt;
&lt;pre&gt;function poll() {&lt;br&gt;  let maxIterations = 10 // número aleatório que eu escolhi&lt;br&gt;  while (maxIterations--) {&lt;br&gt;    runNextCallback()&lt;br&gt;  }&lt;br&gt;  // fim da fase &lt;em&gt;Poll&lt;/em&gt;&lt;br&gt;}&lt;/pre&gt;
&lt;p&gt;Cada fase possui filas, lógicas e parâmetros diferentes. Vamos dar uma olhada em cada delas uma agora.&lt;/p&gt;
&lt;p class=&quot;msg msg--success&quot;&gt;&lt;strong&gt;Importante:&lt;/strong&gt; existe um tempo limite que o Node.js pode gastar entre cada fase e, quando este limite é atingido, avançamos diretamente para a próxima fase.&lt;/p&gt;
&lt;h3 id=&quot;header-timers&quot;&gt;timers&lt;/h3&gt;
&lt;p&gt;Um &lt;em&gt;timer&lt;/em&gt; define um intervalo a partir do qual um código será executado.&lt;/p&gt;
&lt;p&gt;Por exemplo, o código &lt;code&gt;setTimeout(() =&amp;gt; console.log(&apos;Hello, world&apos;), 1000)&lt;/code&gt; garante que o &quot;Hello, world&quot; será jogado no console, no mínimo, daqui a 1000ms. Mas não oferece nenhuma garantia de que executará &lt;em&gt;exatamente&lt;/em&gt; daqui a 1000ms.&lt;/p&gt;
&lt;p&gt;Em situações normais estes &lt;em&gt;timers&lt;/em&gt; executam no tempo especificado, mas outros &lt;em&gt;callbacks&lt;/em&gt; podem interferir no tempo que leva para iniciar um &lt;em&gt;timer&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Há dois tipos de &lt;em&gt;callbacks&lt;/em&gt; que entram na fila dos &lt;em&gt;timers:&lt;/em&gt; &lt;em&gt;timeouts&lt;/em&gt; e &lt;em&gt;intervals&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;O &lt;em&gt;timeout&lt;/em&gt; agenda uma função para ser executada &lt;em&gt;uma vez&lt;/em&gt; no futuro. Enquanto o &lt;em&gt;interval&lt;/em&gt; agenda uma função para ser executada infinitamente num intervalo definido.&lt;/p&gt;
&lt;p&gt;Aqui um exemplo de timeout e interval:&lt;/p&gt;
&lt;pre&gt;setTimeout(() =&amp;gt; {&lt;br&gt;  console.log(&apos;Hello, timeout&apos;)&lt;br&gt;}, 1000)&lt;br&gt;&lt;br&gt;let i = 0&lt;br&gt;setInterval(() =&amp;gt; {&lt;br&gt;  console.log(`Hello, interval: ${i}`)&lt;br&gt;  i++&lt;br&gt;}, 1000)&lt;/pre&gt;
&lt;p&gt;O snippet acima produziria a seguinte saída:&lt;/p&gt;
&lt;pre&gt;1s: Hello, timeout&lt;br&gt;1s: Hello, interval: 0&lt;br&gt;2s: Hello, interval: 1&lt;br&gt;3s: Hello, interval: 2&lt;br&gt;...&lt;/pre&gt;
&lt;h3 id=&quot;header-pending-callbacks&quot;&gt;pending&lt;a id=&quot;pending-callbacks&quot; class=&quot;anchor&quot; href=&quot;https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/#pending-callbacks&quot; aria-labelledby=&quot;header-pending-callbacks&quot;&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Esta fase executa os &lt;em&gt;callbacks&lt;/em&gt; para algumas operações de sistema. Por exemplo quando um socket TCP recebe &lt;code&gt;ECONNREFUSED&lt;/code&gt; ao tentar se conectar, o seu respectivo &lt;em&gt;callback&lt;/em&gt; será invocado. É nesta fase que este &lt;em&gt;callback&lt;/em&gt; é invocado.&lt;/p&gt;
&lt;h3 id=&quot;header-poll&quot;&gt;poll&lt;/h3&gt;
&lt;p&gt;Nesta fase o Node.js vai solicitar (&lt;em&gt;poll&lt;/em&gt;) ao Sistema Operacional as operações de E/S que já estão prontas para serem processadas.&lt;/p&gt;
&lt;p class=&quot;msg msg--highlight &quot;&gt;O código que você escreve em JavaScript normalmente é executado nesta fase!&lt;/p&gt;
&lt;p&gt;A partir disso, executa os &lt;em&gt;callbacks&lt;/em&gt; destas operações prontas até a fila ficar vazia OU até atingir o limite máximo de tempo nesta fase.&lt;/p&gt;
&lt;p&gt;Ao finalizar esta fase, o &lt;em&gt;event loop&lt;/em&gt; invoca a fase &lt;em&gt;check&lt;/em&gt;.&lt;/p&gt;
&lt;h3 id=&quot;header-check&quot;&gt;check&lt;/h3&gt;
&lt;p&gt;Esta fase executa um único tipo de &lt;em&gt;callback&lt;/em&gt;: os callbacks agendados pela função &lt;code&gt;setImmediate()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;É como se fosse um &lt;em&gt;timer&lt;/em&gt;, mas com sua própria fila e alta prioridade de execução logo após a fase &lt;em&gt;poll&lt;/em&gt;.&lt;/p&gt;
&lt;h3 id=&quot;header-close-callbacks&quot;&gt;close&lt;a id=&quot;close-callbacks&quot; class=&quot;anchor&quot; href=&quot;https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/#close-callbacks&quot; aria-labelledby=&quot;header-close-callbacks&quot;&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Esta fase gerencia conexões que foram fechadas de repente, como quando um socket se fecha. O evento &lt;code&gt;close&lt;/code&gt; é emitido nesta fase.&lt;/p&gt;
&lt;h2&gt;A fase escondida: &lt;em&gt;process.nextTick()&lt;/em&gt;&lt;/h2&gt;
&lt;p&gt;Existe um mecanismo que eu não descrevi aqui mas que é importante explicar. É o &lt;code&gt;process.nextTick()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A forma como utilizamos é parecida com o &lt;em&gt;setImmediate()&lt;/em&gt;:&lt;/p&gt;
&lt;pre&gt;process.nextTick(() =&amp;gt; {&lt;br&gt;  // ...&lt;br&gt;})&lt;/pre&gt;
&lt;p&gt;Mas há uma diferença fundamental: &lt;em&gt;process.nextTick()&lt;/em&gt; opera numa fila própria, a &lt;code&gt;nextTickQueue&lt;/code&gt;. E executa os &lt;em&gt;callbacks&lt;/em&gt; desta fila imediatamente depois de cada fase.&lt;/p&gt;
&lt;p&gt;Corrigindo o snippet anterior sobre o &lt;em&gt;event loop&lt;/em&gt;, poderíamos representar o &lt;em&gt;process.nextTick()&lt;/em&gt; desta forma:&lt;/p&gt;
&lt;pre&gt;while (true) {&lt;br&gt;  poll()&lt;br&gt;  nextTick()&lt;br&gt;  check()&lt;br&gt;  nextTick()&lt;br&gt;  close()&lt;br&gt;  nextTick()&lt;br&gt;  timers()&lt;br&gt;  nextTick()&lt;br&gt;  pending()&lt;br&gt;  nextTick()&lt;br&gt;}&lt;/pre&gt;
&lt;p&gt;Portanto é importante sempre tomar MUITO cuidado ao utilizar &lt;em&gt;process.nextTick()&lt;/em&gt;. Se você rodar alguma lógica pesada, ou gerar recursão nesta fase, pode tirar um tempo precioso que seria utilizado pelas outras fases.&lt;/p&gt;
&lt;p class=&quot;msg msg--success&quot;&gt;A não ser que você saiba bem o que está fazendo e tenha um ótimo motivo, prefira usar &lt;em&gt;setImmediate()&lt;/em&gt; em vez de &lt;em&gt;process.nextTick()&lt;/em&gt;.&lt;/p&gt;
&lt;h2&gt;Conclusão&lt;/h2&gt;
&lt;p&gt;O motor V8, e por conseguinte, o Node.js utilizam um mecanismo chamado &lt;em&gt;Event Loop&lt;/em&gt; pra gerenciar diversas filas de &lt;em&gt;callbacks&lt;/em&gt; que são executados em 5 fases diferentes: &lt;em&gt;poll&lt;/em&gt;, &lt;em&gt;check&lt;/em&gt;, &lt;em&gt;close&lt;/em&gt;, &lt;em&gt;timers&lt;/em&gt; e &lt;em&gt;pending&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Além disso, para executar operações de Entrada e Saída, outras &lt;em&gt;threads &lt;/em&gt;são utilizadas, aumentando o número de processos que podem ser executados em paralelo.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Este foi mais um artigo da série de estudos que eu tenho feito sobre o ecossistema Node.js. E apesar de o conteúdo não dar trabalho, estes gráficos e GIFs todos deram um trabalhão!&lt;/p&gt;
&lt;p&gt;Você pode me ajudar compartilhando este artigo nas suas redes sociais. Caso queira compartilhar as imagens, dê também um link pra este artigo.&lt;/p&gt;
&lt;p&gt;Até a próxima! 👋&lt;/p&gt;</content:encoded><category>javascript</category></item><item><title>Programação por coincidência: 6 dicas para iniciantes evitarem este erro</title><link>https://codamos.com.br/programacao-por-coincidencia/</link><guid isPermaLink="true">https://codamos.com.br/programacao-por-coincidencia/</guid><description>O livro &quot;Programador Pragmático&quot; escrito por David Thomas e Andrew Hunt traz um conceito chave que eu acho essencial passar para frente, especialmente para quem está iniciando: a programação por coinc</description><pubDate>Thu, 03 Mar 2022 18:19:06 GMT</pubDate><content:encoded>&lt;p&gt;O livro &quot;Programador Pragmático&quot; escrito por David Thomas e Andrew Hunt traz um conceito chave que eu acho essencial passar para frente, especialmente para quem está iniciando: a programação por coincidência.&lt;/p&gt;
&lt;p&gt;Eu não recomendo ler e confiar neste livro cegamente, tenho várias ressalvas sobre o conteúdo e, sinceramente, acho que o pouco conteúdo útil do livro é explicado de forma burra. Talvez num futuro eu faça uma resenha sobre este livro especificamente.&lt;/p&gt;
&lt;p&gt;Colocando isto de lado, o conceito de &lt;em&gt;programação por coincidência &lt;/em&gt;que o livro traz é muito bom e é algo que eu recomendo a todas pessoas iniciando na área de desenvolvimento de software a aprender sobre.&lt;/p&gt;
&lt;h2&gt;O que é programar por coincidência?&lt;/h2&gt;
&lt;p&gt;Já passou por esta situação onde você se envolveu tanto com o código que já tem trocentas abas abertas no seu editor de texto, perdeu a noção de o que o arquivo atual faz e então resolve colocar o famoso &lt;em&gt;echo&lt;/em&gt; e rodar o programa de novo pra entender onde está.&lt;/p&gt;
&lt;figure contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image&quot; src=&quot;/media/posts/32/meme-funcionou-por-que.jpg&quot; alt=&quot;Pessoa confusa em frente ao computador e a frase &amp;quot;Tá, a gambeta funcionou... mas por que careilhos?&amp;quot;&quot; width=&quot;960&quot; height=&quot;540&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Pessoa confusa em frente ao computador e a frase &quot;Tá, a gambeta funcionou... mas por que careilhos?&quot;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Atitudes como &quot;deixa eu trocar esta linha por aquela&quot; ou &quot;deixa eu ver se isso aqui funciona&quot; são claros sintomas de que você está programando por coincidência.&lt;/p&gt;
&lt;p&gt;Programar por coincidência é alterar algum código ou configuração&lt;strong&gt; sem ter a menor ideia de o que aquilo vai causar. &lt;/strong&gt;Em outras palavras:&lt;/p&gt;
&lt;p class=&quot;msg msg--success&quot;&gt;Programar por coincidência é escrever código sem uma intenção concreta.&lt;/p&gt;
&lt;p&gt;Programar com intenção, saber exatamente o que você quer alcançar com aquelas linhas de código, é o primeiro passo para escrever para humanos, como pessoas mais experientes fazem.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/guia-estilo-de-codigo-para-iniciantes/&quot;&gt;Veja aqui um artigo onde eu falo sobre como &quot;dev júnior escreve código para computadores e dev sênior escreve código para pessoas&quot;&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Mas se eu entreguei a tarefa, qual o problema?&lt;/h2&gt;
&lt;p&gt;O problema de programar por coincidência, ou sem intenção, é que &lt;strong&gt;isto gasta muito tempo e energia&lt;/strong&gt; desnecessariamente. Para a empresa funciona bem, mas para você é uma porcaria!&lt;/p&gt;
&lt;p&gt;Alguns dos problemas que eu vejo em programar por coincidência, especialmente para quem tem menos experiência:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;muito esforço e energia desperdiçados;&lt;/li&gt;
&lt;li&gt;dificuldade no aprendizado no longo prazo;&lt;/li&gt;
&lt;li&gt;falta de confiança na solução final;&lt;/li&gt;
&lt;li&gt;dificuldade na hora de pedir ajuda ou justificar suas decisões numa revisão de código&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Em geral, &lt;strong&gt;programar por coincidência só tende a te fazer mal&lt;/strong&gt;. O único benefício que eu vejo é que, depois de sofrer tantas horas pra resolver um problema, a vitória é doce.&lt;/p&gt;
&lt;p&gt;Mas cuidado, este é um caminho perigoso e pode te custar muito tempo e saúde mental.&lt;/p&gt;
&lt;h2&gt;Como programar por intenção e não por coincidência?&lt;/h2&gt;
&lt;p&gt;Existe algumas técnicas que podem te ajudar a programar com maior intencionalidade em vez de por coincidência e palpites. Eu vou mostrar 6 delas aqui.&lt;/p&gt;
&lt;p&gt;Lembre-se que quase toda verdade em desenvolvimento de software nunca é absoluta, e pode ser respondida com um belo &quot;depende&quot;.&lt;/p&gt;
&lt;p&gt;Então não tome este texto como uma série de dogmas a serem seguidos, mas eu garanto que ao adotar ao menos uma destas dicas você já vai conseguir evoluir melhor na sua carreira.&lt;/p&gt;
&lt;h3&gt;1 - Entenda os seu requisitos antes de aplicar uma solução&lt;/h3&gt;
&lt;p&gt;Para muita gente isso parece óbvio, mas é muito comum entre iniciantes ler uma tarefa/problema/bug e já sair marretando o código pra tentar resolver.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://youtu.be/2i8emwUZRWc&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Como já disse o Rei do Kuduro, neum fésse eisso!&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Assim que você identificar o problema, a primeira coisa que você precisa entender é: quais são os sinais que me dizem se eu atingi meu objetivo ou não?&lt;/p&gt;
&lt;p&gt;Por exemplo, um problema que o codamos.com.br tem atualmente é que nós não oferecemos uma &lt;em&gt;Newsletter&lt;/em&gt;. A solução para este problema não é adotar um servidor, pagar um serviço de disparo de e-mails e nem escrever a newsletter. A solução é &lt;em&gt;oferecer uma newsletter&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Note nuance da resposta! Ela deixa explícito &lt;strong&gt;&lt;em&gt;o que&lt;/em&gt;&lt;/strong&gt; precisa ser feito, não &lt;em&gt;o &lt;strong&gt;como&lt;/strong&gt;&lt;/em&gt; precisa ser feito.&lt;/p&gt;
&lt;p&gt;E este é o primeiro e mais importante passo de todos. &lt;strong&gt;Você precisa entender qual resultado desejado&lt;/strong&gt;. Enquanto este resultado não for verdade, a sua solução não resolve o problema.&lt;/p&gt;
&lt;p&gt;O próximo passo é quebrar a sua solução em vários pedacinhos independentes.&lt;/p&gt;
&lt;h3&gt;2 - Quebre sua tarefa em várias partes menores&lt;/h3&gt;
&lt;p&gt;Isto também deve acontecer antes de escrever qualquer linha de código. É ideal planejar o que você vai fazer antes de começar a codificar.&lt;/p&gt;
&lt;p&gt;O plano nem sempre vai ser executado 100% como você imaginou, mas saber por onde começar é essencial!&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--left&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image&quot; src=&quot;/media/posts/32/machado-afiado-2.jpg&quot; alt=&quot;Um machado afiado sobre uma pilha de lenha cortada.&quot; width=&quot;960&quot; height=&quot;1440&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Um machado afiado sobre uma pilha de lenha cortada.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;A metáfora do lenhador se encaixa bem aqui: você pode cortar uma árvore em 6 horas de esforço com o machado do jeito que está, ou &lt;strong&gt;investir 2 horas afiando o machado e cortar a árvore em apenas 1 hora&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Não corte árvores, tá? O ponto aqui é: coloque mais esforço no seu plano antes de agir e isso vai te salvar tempo, energia e saúde mental!&lt;/p&gt;
&lt;p&gt;Pegue um bloco de notas, notas adesivas ou um programa de tarefas e escreva o seu plano de ação. &lt;strong&gt;Dê uma olhada no código e anote quais partes do código você vai precisar alterar&lt;/strong&gt;. Isso ajuda muito a executar a correção depois.&lt;/p&gt;
&lt;p&gt;Abaixo eu mostro uma tarefa que eu executei recentemente na minha empresa, olha como eu preparei antes de codificar qualquer coisa. Eu basicamente olhei os requisitos, procurei no código o que eu preciso fazer, onde e anotei lá:&lt;/p&gt;
&lt;pre&gt;Problema:&lt;br&gt;Os posts de &quot;press release&quot; ficam dentro do Wordpress e não são disponíveis no nosso site.&lt;br&gt;&lt;br&gt;Solução:&lt;br&gt;Disponibilizar os posts de &quot;press release&quot; no nosso site.&lt;br&gt;&lt;br&gt;Requisitos:&lt;br&gt;- Adicionar uma rota &quot;/press/{slug}&quot; que mostra o mesmo conteúdo de &quot;/blog/post/{slug}&quot; no Wordpress, mostrar apenas posts na categoria &quot;press release&quot;&lt;br&gt;&lt;br&gt;- Redirecionar para &quot;/press&quot; se o post não existir ou não pertencer à categoria &quot;press release&quot;&lt;br&gt;&lt;br&gt;- Adicionar uma rota &quot;/press-releases&quot; que mostra o mesmo conteúdo de &quot;/blog/category/press-release&quot; no Wordpress&lt;br&gt;&lt;br&gt;Como executar:&lt;br&gt;- Adicionar rota &quot;/press/{slug}&quot;. Ver &lt;strong&gt;BlogDetail.php:36&lt;/strong&gt;&lt;br&gt;&lt;br&gt;- Adicionar rota &quot;/press-releases&quot;. Ver &lt;strong&gt;BlogOverview.php:31&lt;/strong&gt;&lt;br&gt;&lt;br&gt;- Adicionar redirecionamento para posts fora de &quot;press release&quot;. Ver &lt;strong&gt;BlogDetail.php:197&lt;/strong&gt;&lt;br&gt;&lt;br&gt;- Modificar links canônicos. Ver &lt;strong&gt;BlogDetail.php:169&lt;/strong&gt;&lt;/pre&gt;
&lt;p&gt;Preparar uma lista desta leva cerca de 20 minutos, e vai guiar o seu desenvolvimento como uma flecha em direção ao centro do alvo 🎯 !&lt;/p&gt;
&lt;p&gt;Note que simplesmente por saber &quot;como executar&quot; uma coisa você já não precisa abrir trocentos mil arquivos. Sabemos exatamente quais arquivos abrir e onde olhar.&lt;/p&gt;
&lt;p&gt;Siga esta lista item a item, em ordem e sem misturar. Você vai ver como seu fluxo de desenvolvimento vai ficar bem menos confuso! 😉&lt;/p&gt;
&lt;h3&gt;3 - Refatoração em primeiro lugar!&lt;/h3&gt;
&lt;p&gt;Refatorar é alterar um código sem mudar seu resultado. &lt;a href=&quot;/livro-refactoring-martin-fowler/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Eu escrevi aqui um artigo bem detalhado sobre o livro que original o termo: Refactoring, por Martin Fowler.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Por exemplo, transformar este código (que não faz o menor sentido):&lt;/p&gt;
&lt;pre&gt;function sum(int a, int b): int {&lt;br&gt;  for (int i = 0; i &amp;lt; b; i++) {&lt;br&gt;    a++;&lt;br&gt;  }&lt;br&gt;&lt;br&gt;  return a;&lt;br&gt;}&lt;/pre&gt;
&lt;p&gt;Neste código:&lt;/p&gt;
&lt;pre&gt;function sum(int a, int b): int {&lt;br&gt;  return a + b;&lt;br&gt;}&lt;/pre&gt;
&lt;p&gt;Isto é uma refatoração. Porque mudamos o corpo da função, mas não mudamos os parâmetros e nem o resultado. (Quem tá prestando atenção sabe que a gente quebrou uma lógica aí, mas vou deixar em aberto)&lt;/p&gt;
&lt;p&gt;Note como o primeiro &lt;em&gt;snippet&lt;/em&gt; de código é bem mais confuso e, de certa forma, desnecessário.&lt;/p&gt;
&lt;p&gt;Às vezes nós escrevemos código assim sem perceber. Coisas que poderiam ser muito mais simples acabam sendo feitas de forma complicada. &lt;strong&gt;E é normal, não significa que você seja um mau profissional por escrever código assim.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Mas é exatamente por conta deste comportamento que nós precisamos programar sempre de forma defensiva e &lt;strong&gt;preparar o ambiente antes de trabalhar&lt;/strong&gt;.&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--right&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image&quot; src=&quot;/media/posts/32/mise-en-place.jpg&quot; alt=&quot;Mise en place: tudo cortadinho e preparado para a hora de cozinhar.&quot; width=&quot;959&quot; height=&quot;1440&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Mise en place: tudo cortadinho e preparado para a hora de cozinhar.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Chefs de cozinha têm um nome especial para esta preparação antes do trabalho. É o tal do &lt;em&gt;mise en place&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;O nome é chatinho, mas a prática faz todo sentido. Se você for cortar e limpar tudo na hora que precisar, sua cozinha vai ficar um caos.&lt;/p&gt;
&lt;p&gt;Mas se tudo estiver preparadinho e antes de montar o prato, a execução em si vai ser simples e rápida e você vai poder focar no que importa.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nós, que trabalhamos com desenvolvimento de software, também precisamos de um mise en place. O nosso se chama &lt;em&gt;refatoração&lt;/em&gt;!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;É claro que metáforas são imprecisas em certos pontos, mas esta aqui vai te ajudar a criar uma imagem sobre refatoração que é importantíssima: não é algo &quot;a mais&quot; que você faz mas sim algo essencial pra começar a trabalhar.&lt;/p&gt;
&lt;p class=&quot;msg msg--success&quot;&gt;Refatoração é o &lt;em&gt;mise en place&lt;/em&gt; da pessoa programadora.&lt;/p&gt;
&lt;p&gt;A minha dica aqui é: &lt;strong&gt;antes de trabalhar numa determinada classe, função ou pedaço da aplicação, faça uma refatoração de leve na intenção de entender melhor aquele código.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Desta forma você vai entender melhor o código antes de escrever alguma coisa, vai ter um ambiente pronto pra trabalhar e, de quebra, vai deixar o código num estado melhor para a próxima pessoa que o visitar. Provavelmente será você mesmo, então refatore pelo seu próprio bem 😉&lt;/p&gt;
&lt;h3&gt;4 - Refatoração sem testes não é refatoração&lt;/h3&gt;
&lt;p&gt;Essa ideia de preparar o ambiente é linda, mas o fato é que as vezes nós mudamos uma determinada lógica, uma vírgula e o sistema todo pode entrar em colapso.&lt;/p&gt;
&lt;p&gt;Como eu disse antes, refatorar é alterar um código sem mudar seu resultado. &lt;strong&gt;Como provar que a mudança que fizemos no código não alterou seu resultado?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Com testes!&lt;/p&gt;
&lt;p&gt;De preferência, com testes automatizados. Vamos retomar o exemplo anterior e escrever alguns testes:&lt;/p&gt;
&lt;pre&gt;Teste 01: positivos&lt;br&gt;&lt;br&gt;Ao chamar a função sum() com os valores 10 e 20, meu retorno deverá ser 30.&lt;br&gt;&lt;br&gt;Teste 02: negativos&lt;br&gt;Ao chamar a função sum() com os valores -10 e -5, meu retorno deverá ser -15.&lt;br&gt;&lt;br&gt;Teste 03: positivos e negativos&lt;br&gt;Ao chamar a função sum() com os valores 10 e -5, meu retorno deverá ser 5.&lt;/pre&gt;
&lt;p&gt;Note que eu não preciso de uma ferramenta específica para escrever testes. O foco é entender que dado algum tipo de entrada, eu espero que a minha função faça algum processamento e gere algum tipo de saída.&lt;/p&gt;
&lt;p&gt;Se antes de começar a refatorar os testes estavam passando, ao terminar de refatorar eles devem continuar passando.&lt;/p&gt;
&lt;p&gt;O ideal, é claro, é que você utilize uma ferramenta de automação de testes como o &lt;em&gt;&lt;a href=&quot;/testes-php-phpunit/&quot;&gt;PHPUnit&lt;/a&gt;&lt;/em&gt; ou &lt;em&gt;Jest.&lt;/em&gt;&lt;/p&gt;
&lt;figure contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image&quot; src=&quot;/media/posts/32/phpunit-testes-passando.jpg&quot; alt=&quot;Captura de tela: uma suíte de testes com PHPUnit pasando.&quot; width=&quot;960&quot; height=&quot;284&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Captura de tela: uma suíte de testes com PHPUnit pasando.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p class=&quot;msg msg--success&quot;&gt;Se você já possui testes, refatore. Se não possui, crie testes primeiro e depois refatore.&lt;/p&gt;
&lt;h3&gt;5 - Testes são sua melhor ferramenta de apoio&lt;/h3&gt;
&lt;p&gt;Eu já escrevi alguns artigos sobre como testes podem te ajudar em diferentes aspectos da sua carreira. Desde &lt;a href=&quot;/tdl-aprendizado-por-testes/&quot;&gt;como aprender linguagens de programação novas usando TDL&lt;/a&gt; até &lt;a href=&quot;/tdd-php-exemplos/&quot;&gt;como escrever código de forma segura e assertiva com TDD&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;O principal ponto aqui é que &lt;strong&gt;quando a gente escreve um teste, nos forçamos a pensar sobre o resultado antes mesmo da implementação.&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&quot;msg msg--success&quot;&gt;Quanto mais você praticar e escrever testes, mais natural vai ser programar por intenção em vez de por coincidência.&lt;/p&gt;
&lt;p&gt;Além disso, um teste bem escrito também serve como guia para a próxima pessoa que precisar entender aquele pedaço de código ou como usar aquela função.&lt;/p&gt;
&lt;h3&gt;6 - Refatore após terminar de codificar sua funcionalidade&lt;/h3&gt;
&lt;p&gt;Se você já fez uma refatoração &lt;em&gt;antes&lt;/em&gt; de codificar, deve entender bem o que o código faz.&lt;/p&gt;
&lt;p&gt;Se ao fazer a refatoração e implementar a funcionalidade do jeito que precisava os testes continuam passando, sua tarefa está quase pronta para ser entregue: precisa ser finalizada com uma bela refatoração!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lembre-se: pessoas programadoras mais experientes escrevem código para pessoas, não para computadores.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Agora que seus testes estão passando, dê aquela polida no código para que fique mais fácil entender. A próxima pessoa que ler seu código vai ficar agradecida. Lembre-se que esta pessoa provavelmente será você mesmo 😉&lt;/p&gt;
&lt;p class=&quot;msg msg--success&quot;&gt;Ao finalizar uma entrega, refatore o seu código para facilitar a vida de quem vai fazer a revisão.&lt;/p&gt;
&lt;p&gt;Se você refatorar o código pensando em quem vai revisar, com total certeza vai fazer com que seja mais fácil de ser lido por um humano.&lt;/p&gt;
&lt;h2&gt;Conclusão&lt;/h2&gt;
&lt;figure class=&quot;post__image post__image--left&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image&quot; src=&quot;/media/posts/32/se-nao-sabe-onde-quer-ir-qualquer-caminho-serve.jpg&quot; alt=&quot;Se você não sabe onde quer ir, qualquer caminho serve.&quot; width=&quot;960&quot; height=&quot;540&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Se você não sabe onde quer ir, qualquer caminho serve.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Caso não tenha ficado claro, deixemos claro aqui: programar por coincidência é ruim! Isto vai atrasar a sua vida, a sua carreira e o seu time.&lt;/p&gt;
&lt;p&gt;Adote as 6 dicas que mencionei no texto e vai notar como programar vai ficar bem mais fácil pra ti!&lt;/p&gt;
&lt;p&gt;Sempre que escrever algum trecho de código, &lt;strong&gt;faça o máximo esforço possível para entender a &lt;em&gt;intenção&lt;/em&gt; do código que quer escrever.&lt;/strong&gt;&lt;/p&gt;</content:encoded><category>junior</category><category>livro</category><category>produtividade</category></item><item><title>Lacrei: vagas para pessoas voluntárias</title><link>https://codamos.com.br/vagas-time-tecnologia-lacrei/</link><guid isPermaLink="true">https://codamos.com.br/vagas-time-tecnologia-lacrei/</guid><description>A Lacrei é o primeiro portal criado para conectar a comunidade LGBTQIA+ a profissionais de saúde, advogades e empresas que respeitam a diversidade oferecendo oportunidades de trabalho e desenvolviment</description><pubDate>Sat, 26 Feb 2022 11:07:11 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img class=&quot;post__image post__image--left&quot; src=&quot;/media/posts/31/logo-lacrei.svg&quot; alt=&quot;Logotipo do projeto Lacrei&quot; width=&quot;128&quot; height=&quot;128&quot;&gt;&lt;/p&gt;
&lt;p&gt;A &lt;a href=&quot;https://www.portallacrei.com.br/&quot; target=&quot;_blank&quot; rel=&quot;nofollow sponsored noopener noreferrer&quot;&gt;Lacrei&lt;/a&gt; é o&lt;strong&gt; primeiro portal criado para conectar a comunidade LGBTQIA+ a profissionais de saúde, advogades e empresas que respeitam a diversidade&lt;/strong&gt; oferecendo oportunidades de trabalho e desenvolvimento profissional.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;A plataforma facilita o contato e a informação para que pessoas LGBTQIAP+ possam encontrar, de forma prática e segura, serviços profissionais, acolhedores e inclusivos, de forma fácil e digital. Aqui, profissionais e empresas falam a nossa língua e escutam o que temos a dizer.&lt;/p&gt;
&lt;div class=&quot;gallery gallery-wrapper--wide&quot; contenteditable=&quot;false&quot; data-is-empty=&quot;false&quot; data-columns=&quot;2&quot;&gt;
&lt;figure class=&quot;gallery__item&quot;&gt;&lt;a href=&quot;/media/posts/31/gallery/lacrei-saude.png&quot; data-size=&quot;599x661&quot;&gt;&lt;img src=&quot;/media/posts/31/gallery/lacrei-saude-thumbnail.png&quot; alt=&quot;Lacrei Saúde&quot; width=&quot;599&quot; height=&quot;661&quot;&gt;&lt;/a&gt;
&lt;figcaption&gt;Lacrei Saúde&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;gallery__item&quot;&gt;&lt;a href=&quot;/media/posts/31/gallery/lacrei-juridico.png&quot; data-size=&quot;513x607&quot;&gt;&lt;img src=&quot;/media/posts/31/gallery/lacrei-juridico-thumbnail.png&quot; alt=&quot;Lacrei Jurídico&quot; width=&quot;513&quot; height=&quot;607&quot;&gt;&lt;/a&gt;
&lt;figcaption&gt;Lacrei Jurídico&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;Em parceria com o blog &lt;a href=&quot;/sobre-o-codamoscombr/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Codamos&lt;/a&gt;, a Lacrei anuncia vagas de tecnologia para voluntariado em 4 áreas diferentes. São oportunidades incríveis para &lt;strong&gt;praticar suas habilidades e desenvolver seu portfólio&lt;/strong&gt; com uma carga horária acessível e &lt;strong&gt;100% remoto&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Todas vagas possuem carga horária de 10 horas semanais e são 100% remotas, para trabalhar com times que buscam diversidade&lt;/p&gt;
&lt;h2&gt;Vaga para Liderança técnica (Tech Lead)&lt;/h2&gt;
&lt;p class=&quot;msg msg--info&quot;&gt;As vagas são para candidatas mulheres, comunidade negra e comunidade LGBTQIAPN+.&lt;/p&gt;
&lt;p&gt;A pessoa Tech Lead na Lacrei é uma pessoa técnica podendo ter atuação prática, pondo a mão na massa, apesar de liderar o time de desenvolvedores da Lacrei.&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--left&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/31/tech-lead.jpeg&quot; alt=&quot;Mulher em sessão de pair programming.&quot; width=&quot;640&quot; height=&quot;959&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Teach lead em sessão de pair programming&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;São &lt;strong&gt;dois times&lt;/strong&gt;: um de back end e outro de front end, que se encontram semanalmente e participam de uma das 3 squads. São aproximadamente &lt;strong&gt;25 pessoas voluntárias desenvolvedoras&lt;/strong&gt;, em &lt;strong&gt;times multidisciplinares&lt;/strong&gt; com pessoas de UX/UI, Front e Back -end.&lt;/p&gt;
&lt;p&gt;Neste papel você terá a oportunidade de melhorar suas habilidades como pessoa programadora ao mesmo tempo que desenvolve aspectos de liderança. Nossos times utilizam a &lt;strong&gt;metodologia Scrum&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Parte de suas responsabilidades como Tech Lead é &lt;strong&gt;trazer as novidades tecnológicas&lt;/strong&gt; e jeitos diferentes de &lt;strong&gt;resolver problemas de forma mais eficiente&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Além disso, a expectativa é que ela consiga &lt;strong&gt;manter o time focado&lt;/strong&gt; no que precisa ser feito, &lt;strong&gt;priorize corretamente as atividades&lt;/strong&gt; e entregue resultados tirando o melhor de cada membro do time.&lt;/p&gt;
&lt;p class=&quot;msg msg--success&quot;&gt;&lt;a href=&quot;https://bit.ly/lacrei-tech-lead&quot; target=&quot;_blank&quot; rel=&quot;nofollow sponsored noopener noreferrer&quot;&gt;Clique aqui para inscrever-se.&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Vaga para Front-end (ReactJS)&lt;/h2&gt;
&lt;p class=&quot;msg msg--info&quot;&gt;As vagas são para candidatas mulheres, comunidade negra e comunidade LGBTQIAPN+.&lt;/p&gt;
&lt;p&gt;Utilizamos a &lt;strong&gt;metodologia Scrum&lt;/strong&gt; e atuamos juntamente com os times de UX/UI Design e Back-end dentro das Squads sempre com a &lt;strong&gt;supervisão das nossas Products Owners&lt;/strong&gt;.&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--right&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/31/reactjs-captura-de-tela.jpeg&quot; alt=&quot;Captura de tela que mostra um fragmento de código em ReactJS&quot; width=&quot;640&quot; height=&quot;426&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Captura de tela que mostra um fragmento de código em ReactJS&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Nossa atividade voluntária compreende também a conversar com outras pessoas voluntárias, sua coordenadora e com sua Product Owner e &lt;strong&gt;comparecer virtualmente nas reuniões estipuladas&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Sendo assim, você deverá compreender a importância da Lacrei, ser empático com a comunidade e treinar a sua comunicação.&lt;/p&gt;
&lt;h3&gt;Times e Horários&lt;/h3&gt;
&lt;p&gt;Squad Institucional: Terça das 19 horas as 20 horas e Quarta das 19 as 20 horas.&lt;/p&gt;
&lt;p&gt;Squad Jornada da Pessoa Profissional: Horários: Terça e Quarta das 19 às 20 horas.&lt;/p&gt;
&lt;p&gt;Squad Jornada da Pessoa Usuária: Segunda das 19 as 20 horas e Quarta das 19 as 20 horas.&lt;/p&gt;
&lt;h3&gt;Requisitos&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;NPM ou Yarn&lt;/li&gt;
&lt;li&gt;ReactJS e Gatsby&lt;/li&gt;
&lt;li&gt;Styled Components&lt;/li&gt;
&lt;li&gt;Consumir APIs&lt;/li&gt;
&lt;li&gt;Familiaridade com Git&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;msg msg--success&quot;&gt;&lt;a href=&quot;https://bit.ly/lacrei-front-end&quot; target=&quot;null&quot; rel=&quot;nofollow sponsored&quot;&gt;Clique aqui para inscrever-se.&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Vaga para Back-end (Python)&lt;/h2&gt;
&lt;p class=&quot;msg msg--info&quot;&gt;As vagas são para candidatas mulheres, comunidade negra e comunidade LGBTQIAPN+.&lt;/p&gt;
&lt;p&gt;Python é uma linguagem de programação de alto nível, ou seja, com sintaxe mais simplificada e próxima da linguagem humana, utilizada nas mais diversas aplicações, como desktop, web, servidores e ciência de dados.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Hoje utilizamos outra tecnologia e estamos te convidando para fazer essa migração&lt;/strong&gt;, aceita esse desafio!?&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--left&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/31/pessoa-programadora-python.jpeg&quot; alt=&quot;Pessoa programadora desenvolvendo em Python.&quot; width=&quot;640&quot; height=&quot;427&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Pessoa programadora desenvolvendo em Python&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3&gt;Requisitos&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Python&lt;/li&gt;
&lt;li&gt;Django&lt;/li&gt;
&lt;li&gt;PostgreSQL&lt;/li&gt;
&lt;li&gt;Testes unitários&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p class=&quot;msg msg--success&quot;&gt;&lt;a href=&quot;https://bit.ly/lacrei-python&quot; target=&quot;_blank&quot; rel=&quot;nofollow sponsored noopener noreferrer&quot;&gt;Clique aqui para inscrever-se.&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Vaga para profissional de Inteligência Artificial&lt;/h2&gt;
&lt;p class=&quot;msg msg--info&quot;&gt;As vagas são para candidatas mulheres, comunidade negra e comunidade LGBTQIAPN+.&lt;/p&gt;
&lt;p&gt;Na plataforma Lacrei há vários filtros que uma pessoa usuária pode querer aplicar, e para oferecer uma experiência melhor desenvolvemos o nosso próprio algoritmo para extrair entidades de termos de busca usando o &lt;strong&gt;modelo Bert NER&lt;/strong&gt;.&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--right&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/31/rede.jpeg&quot; alt=&quot;Ilustração de vários pinos conectados, formando uma rede.&quot; width=&quot;640&quot; height=&quot;426&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Ilustração de vários pinos conectados, formando uma rede&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Estamos buscando programadoras de Inteligência Artificial e Aprendizado de Máquina para nos ajudar nessa caminhada.&lt;/p&gt;
&lt;p&gt;Precisamos de alguém para criar e aperfeiçoar nosso algoritmo de Processamento de Linguagem Natural para &lt;strong&gt;extração de entidades&lt;/strong&gt;, e essa é a sua tarefa nesse time.&lt;/p&gt;
&lt;p class=&quot;msg msg--success&quot;&gt;&lt;a href=&quot;https://bit.ly/lacrei-ia&quot; target=&quot;_blank&quot; rel=&quot;nofollow sponsored noopener noreferrer&quot;&gt;Clique aqui para inscrever-se.&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Se você quiser ajudar esta iniciativa mas não pode contribuir com tempo, compartilhe este post em suas redes - já serve de grande ajuda para o projeto!&lt;/p&gt;</content:encoded><category>lacrei</category><category>vagas</category></item><item><title>Estilo de código: o que tode dev júnior PRECISA saber</title><link>https://codamos.com.br/guia-estilo-de-codigo-para-iniciantes/</link><guid isPermaLink="true">https://codamos.com.br/guia-estilo-de-codigo-para-iniciantes/</guid><description>A área de desenvolvimento de software é um tanto quanto peculiar quando se trata de fundamentos e verdades absolutas: são poucas as frases de efeito que são aceitas por unanimidade e não são seguidas </description><pubDate>Thu, 17 Feb 2022 17:56:00 GMT</pubDate><content:encoded>&lt;p&gt;A área de desenvolvimento de software é um tanto quanto peculiar quando se trata de fundamentos e verdades absolutas: são poucas as frases de efeito que são aceitas por unanimidade e não são seguidas daquele poderoso &lt;em&gt;depende&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Um dos poucos fundamentos que normalmente sobrevive discussões é sobre a importância da estilização do seu código. É claro que há muita discordância e treta pela internet sobre qual estilo usar, mas ao menos todo mundo concorda que estilizar o código é essencial em diversos casos.&lt;/p&gt;
&lt;p&gt;Este artigo não vai te apresentar nenhuma visão sobre qual estilo de código é o melhor, ou criticar estilos existentes. A minha intenção é munir você, dev júnior, com as ferramentas básicas que vão te ajudar a entender a importância da estilização de código e como isto vai afetar o seu aprendizado daqui pra frente - até o fim da sua carreira.&lt;/p&gt;
&lt;h2&gt;Dev júnior escreve pra computadores, dev sênior escreve pra pessoas&lt;/h2&gt;
&lt;p&gt;O motivo principal de eu escrever este artigo é que depois de várias sessões de mentoria com iniciantes tanto no front-end quanto no back-end percebi que muitas das confusões e dificuldades que essas pessoas tiveram poderiam ser mitigadas com a adoção de algumas boas práticas sobre estilo de código.&lt;/p&gt;
&lt;p&gt;Eu já perdi a conta do número de sessões em que mentorandes chegaram para mim com quilos e mais quilos de código para resolver problemas simples, sem entender o que aquele espaguete estava fazendo. Ao mesmo tempo, já compartilhei códigos super complexos que qualquer júnior com o mínimo de conhecimento consegue entender e modificar.&lt;/p&gt;
&lt;p class=&quot;msg msg--info&quot;&gt;&lt;strong&gt;A diferença é simples: &lt;/strong&gt;dev júnior costuma escrever código que máquinas apenas entendem, enquanto dev sênior costuma escrever código para que pessoas entendam.&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image&quot; src=&quot;/media/posts/30/programador-bicho-social.jpg&quot; alt=&quot;Um programador, em frente ao computador, socializando com outra pessoa.&quot; width=&quot;960&quot; height=&quot;640&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Um programador, em frente ao computador, socializando com outra pessoa.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;O maior erro de quem inicia na programação é achar que a forma como se escreve código não faz diferença. Vejamos um exemplo:&lt;/p&gt;
&lt;pre&gt;const words = [&apos;Hello&apos;, &apos;world&apos;]&lt;br&gt;let sentence = &apos;&apos;&lt;br&gt;for (const i in words) {  &lt;br&gt;  sentence = sentence.concat(words[i])&lt;br&gt;  if (i &amp;lt; words.length - 1) sentence = sentence.concat(&apos;, &apos;)&lt;br&gt;}&lt;br&gt;&lt;br&gt;console.log(sentence)&lt;/pre&gt;
&lt;p&gt;O código acima deverá cuspir na tela o valor &lt;code&gt;Hello, world&lt;/code&gt; e nada mais, certo? Errado!&lt;/p&gt;
&lt;p&gt;O código acima cria três variáveis e deixa duas delas no escopo local, sem contar no montante de operações desnecessárias. Na verdade,  o código acima poderia ser simplificado para algo assim:&lt;/p&gt;
&lt;pre&gt;const sentence = [&apos;Hello&apos;, &apos;world&apos;].join(&apos;, &apos;)&lt;br&gt;console.log(sentence)&lt;/pre&gt;
&lt;p&gt;E aqui eu deixo claro o seguinte: código complexo é diferente de código complicado!&lt;/p&gt;
&lt;p&gt;Uma boa definição de &lt;em&gt;complicado&lt;/em&gt; que se adequa ao que quero dizer, lá do dicio, é algo &quot;Exageradamente detalhado; que possui elementos em demasia [...]&quot;.&lt;/p&gt;
&lt;p&gt;Enquanto a definição de &lt;em&gt;complexo&lt;/em&gt; por lá nos diz que é uma &quot;Construção com inúmeras partes que estão ligadas entre si, formando um todo [...]&quot;. O que a gente considera &lt;em&gt;engenhoso&lt;/em&gt;, na minha opinião. Que é justamente o que a nossa profissão se propõe a fazer.&lt;/p&gt;
&lt;p&gt;A primeira chavinha que eu quero te ajudar a virar, dev júnior, é a de entender que código complicado vale menos do que código complexo. &lt;strong&gt;Código bom é o que nós dois conseguimos ler!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Abaixo eu vou descrever um pouco mais sobre o porquê de ser essencial você aprender a estilizar código desde já!&lt;/p&gt;
&lt;h2&gt;Estilizar o código te ajuda a pedir ajuda&lt;/h2&gt;
&lt;p&gt;Vamos partir de um pressuposto simples: &lt;em&gt;&quot;Hey, me ajuda!&quot;&lt;/em&gt; é bem diferente de &lt;em&gt;&quot;Hey, faz pra mim?&quot;&lt;/em&gt;. Por isso o jeito certo de pedir ajuda é reduzir o problema ao máximo possível.&lt;/p&gt;
&lt;p&gt;Uma das grandes fontes de confusão e dificuldade na hora de pedir ajuda, é localizar o problema. Vamos ver um exemplo?&lt;/p&gt;
&lt;pre&gt;/**&lt;br&gt; * Hey, me ajuda? O compilador diz que deu pau na linha 2&lt;br&gt; */&lt;br&gt;1. ((function(){console.log( a + 1 / 100&lt;br&gt;2. );}&lt;/pre&gt;
&lt;p&gt;É somente natural que você não entenda onde está o problema. Eu mesmo não faço a menor ideia de o que tá acontecendo ali.&lt;/p&gt;
&lt;p&gt;Com o código um pouco mais organizado talvez você nem precise pedir ajuda. Vamos isolar cada bloco em sua própria linha e ver o que aconteceu:&lt;/p&gt;
&lt;pre&gt;1. (&lt;br&gt;2.   (&lt;br&gt;3.      function () {&lt;br&gt;4.        console.log(a + 1 / 100)&lt;br&gt;5. // ...&lt;/pre&gt;
&lt;p&gt;Depois da linha 5 ficou claro que faltaram alguns parênteses e chaves. Uma chave &lt;code&gt;}&lt;/code&gt; para fechar o escopo da função, dois parênteses pra fechar a expressão das linhas 1 e 2.&lt;/p&gt;
&lt;p class=&quot;msg msg--highlight  msg--info&quot;&gt;Estilizar seu código vai te ajudar a entender o que VOCÊ está fazendo em primeiro lugar. E torna muito mais fácil para outras pessoas te ajudarem mais tarde.&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image&quot; src=&quot;/media/posts/30/estudantes-computacao-confusos.jpg&quot; alt=&quot;Três estudantes tentando entender algo na tela do computador.&quot; width=&quot;960&quot; height=&quot;639&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Três estudantes tentando entender algo na tela do computador.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Como dizia minha incrível mãe: casa simples não é desculpa pra ser suja. Eu espero que você adote isso como uma regra de etiqueta: pedir ajuda com um código porco e mal formatado é uma falta de respeito enorme. Sempre mantenha a casa limpa!&lt;/p&gt;
&lt;p&gt;Espero que tenha ficado clara a importância de estilizar o seu código enquanto iniciante no mundo da programação. Agora vem comigo, que eu vou te explicar o que eu quero dizer com estilo de código.&lt;/p&gt;
&lt;h2&gt;O que é estilo de código&lt;/h2&gt;
&lt;p&gt;A metáfora da casa limpa se aplica muito bem aqui. No fim das contas você, e qualquer outra pessoa desenvolvedora, deveria ser capaz de navegar no código que escrevem com facilidade.&lt;/p&gt;
&lt;p&gt;O estilo de código adota regras que afetam vários aspectos do seu software. Algumas destas regras são sobre:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;estilo de formatação;&lt;/li&gt;
&lt;li&gt;regras de indentação de código;&lt;/li&gt;
&lt;li&gt;regras para quebra de linha;&lt;/li&gt;
&lt;li&gt;limite de caracteres por linha;&lt;/li&gt;
&lt;li&gt;nomenclatura de variáveis, funções, classes e métodos;&lt;/li&gt;
&lt;li&gt;organização em pastas e nomes de arquivos;&lt;/li&gt;
&lt;li&gt;outras boas práticas&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;msg msg--info&quot;&gt;Não adianta apenas adotar um estilo de código. É importante ser consistente com aquele estilo.&lt;/p&gt;
&lt;p&gt;Por exemplo, se você indentou um arquivo JavaScript com 2 espaços, o próximo arquivo não pode ser indentado com 4 espaços.&lt;/p&gt;
&lt;p&gt;Para o computador, tanto faz se você usa 2 ou 4 espaços para indentar. Mas lembre-se: o computador é só mais um elemento na enorme lista de consumidores do seu código. &lt;strong&gt;Escreva código para pessoas, não para computadores!&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;Quebra de linha tá aí pra ser utilizada&lt;/h3&gt;
&lt;p&gt;Parece besteira, mas faz toda a diferença!&lt;/p&gt;
&lt;p&gt;Gente, nós estamos  em 2022! Uma quebra de linha custa o que? 2 bytes? Não tem motivo pra economizar linha, né.&lt;/p&gt;
&lt;p&gt;Bora quebrar linha sem dó! Saiu um ponto e vírgula? Dá-lhe enter!&lt;/p&gt;
&lt;p&gt;Bate o olho e me diz o que esse código faz:&lt;/p&gt;
&lt;pre&gt;const primeira = 10; const terceira = 20; const segunda = 30;&lt;br&gt;console.log(primeira, terceira, segunda, primeira * 2);&lt;/pre&gt;
&lt;p&gt;Agora bate o olho nesse aqui e me diz o que ele faz:&lt;/p&gt;
&lt;pre&gt;const primeira = 10;&lt;br&gt;const terceira = 20;&lt;br&gt;const segunda = 30;&lt;br&gt;&lt;br&gt;console.log(&lt;br&gt;  primeira,&lt;br&gt;  terceira,&lt;br&gt;  segunda,&lt;br&gt;  primeira * 2&lt;br&gt;);&lt;/pre&gt;
&lt;p&gt;Faz sentido eu quebrar linha até mesmo dentro do &lt;em&gt;console.log&lt;/em&gt;? No fim das contas fica mais fácil ler o que eu tô passando pra dentro da função.&lt;/p&gt;
&lt;p&gt;A época dos monitores de 320x240 pixels já passou faz tempo, gente. Vamo sem meguelar quebra de linha!&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image&quot; src=&quot;/media/posts/30/computador-antigo.jpg&quot; alt=&quot;Um computador antigo, da época em que fazia sentido economizar espaço na tela!!&quot; width=&quot;960&quot; height=&quot;639&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Um computador antigo, da época em que fazia sentido economizar espaço na tela!!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3&gt;Indentação de código&lt;/h3&gt;
&lt;p&gt;Indentação é quando a gente afasta o código da margem pra organizar. Quando se abre um bloco de código, normalmente é hora de indentar.&lt;/p&gt;
&lt;p&gt;Aqui um código não indentado:&lt;/p&gt;
&lt;pre&gt;function euOdeioAMinhaVida() {&lt;br&gt;const motivo = &apos;Porque eu não indento código!&apos;;&lt;br&gt;if (motivo.length &amp;gt; 100) {&lt;br&gt;console.log(&apos;Mó filosofia do ódio&apos;)&lt;br&gt;}&lt;br&gt;else&lt;br&gt;{&lt;br&gt;console.log(&apos;E o motivo é simples:&apos;, motivo)&lt;br&gt;}&lt;br&gt;}&lt;/pre&gt;
&lt;p&gt;Um código parecido, mas com indentação:&lt;/p&gt;
&lt;pre&gt;function euAmoAMinhaVida() {&lt;br&gt;  const motivo = &apos;Porque eu indento código!&apos;;&lt;br&gt;&lt;br&gt;  if (motivo.length &amp;gt; 100) {&lt;br&gt;    console.log(&apos;Olha que delícia essa indentação&apos;)&lt;br&gt;  } else {&lt;br&gt;    console.log(&apos;E o motivo é simples:&apos;, motivo)&lt;br&gt;  }&lt;br&gt;}&lt;/pre&gt;
&lt;p&gt;No bloco de código do corpo da função &lt;code&gt;euAmoAMinhaVida()&lt;/code&gt; eu adicionei uma indentação. Lá dentro tem alguns IFs. Pro bloco de cada IF, eu adicionei mais uma indentação.&lt;/p&gt;
&lt;p&gt;Tem gente que se importa sobre o seu código usar Tabulações ou Espaços para indentação. Tem gente que se importa ainda se ao indentar com espaços você usa 2, 4 ou 6 espaços...&lt;/p&gt;
&lt;p&gt;Tanto faz!&lt;/p&gt;
&lt;p&gt;O importante é indentar o código sempre e ser consistente com seu estilo de indentação. Se começou usando 2 espaços, continua com 2 espaços. E por favor não caia na besteira de indentar um arquivo com 2 espaços, outro com 4, outro com 6 e montar uma salada de indentação. &lt;strong&gt;Consistência!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Claro que a indentação por si só não é suficiente para escrever um código bom e que todo mundo vá entender. O Hadouken que o diga:&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/30/code_hadouken-2.jpeg&quot; alt=&quot;Famoso Hadouken da indentação.&quot; width=&quot;720&quot; height=&quot;511&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Famoso Hadouken da indentação.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3&gt;Ferramentas automatizadas&lt;/h3&gt;
&lt;p&gt;Daí você me pergunta: tá, mas como eu sei qual o jeito certo de estilizar o código? Tem de quebrar linha no lugar certo, tem de indentar do jeito certo... Onde eu acho isso tudo?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cada linguagem de programação tem sua comunidade e suas convenções.&lt;/strong&gt; Você precisa procurar entender a de cada linguagem com que pretende trabalhar.&lt;/p&gt;
&lt;p&gt;Para a nossa sorte, existem ferramentas que controlam e dizem pra gente quando algo está errado. Algumas até corrigem o código pra gente!&lt;/p&gt;
&lt;p&gt;No mundo JavaScript/TypeScript tem o tal do &lt;a href=&quot;https://eslint.org/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Eslint&lt;/a&gt;. No mundo PHP, tem o &lt;a href=&quot;https://github.com/squizlabs/PHP_CodeSniffer&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;PHP Code Sniffer&lt;/a&gt;. O Rust tem o &lt;a href=&quot;https://codamos.com.br/ambiente-de-desenvolvimento-rust.html#rustfmt&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;rustfmt&lt;/a&gt; e por aí vai.&lt;/p&gt;
&lt;p&gt;O bom de usar uma ferramenta automatizada, é que você vai desenvolver a &quot;memória muscular&quot; de como escrever código sem precisar decorar milhares de regras pra cada linguagem.&lt;/p&gt;
&lt;p class=&quot;msg msg--info&quot;&gt;&lt;strong&gt;Dica de ouro:&lt;/strong&gt; sempre que fizer um &lt;em&gt;coding challenge&lt;/em&gt; pra passar naquela entrevista, adicione um linter como o eslint ou phpcs. Vai te dar alguns pontos na avaliação 😉.&lt;/p&gt;
&lt;h3&gt;Escolha de nomes para variáveis e funções&lt;/h3&gt;
&lt;p&gt;O nome é importante, gente. Vamos combinar aqui: variável &lt;code&gt;a&lt;/code&gt;, &lt;code&gt;b&lt;/code&gt; ou &lt;code&gt;c&lt;/code&gt; não faz o menor sentido a não ser que você esteja fazendo um programa pra solucionar equações de segundo grau! E eu não quero nem ver variável &lt;code&gt;tmp&lt;/code&gt;, ein...&lt;/p&gt;
&lt;p&gt;Todas as regras que se aplicam a nome de variáveis também se aplicam a classes, métodos e funções.&lt;/p&gt;
&lt;p&gt;Vamos combinar três cláusulas pétreas aqui, tá?&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Não abrevie nomes: &lt;code&gt;fmt&lt;/code&gt; não faz sentido NENHUM! Use o nome completo, não precisa economizar bytes em disco;&lt;/li&gt;
&lt;li&gt;Sem nomes sequenciais: &lt;code&gt;line&lt;/code&gt;, &lt;code&gt;line2&lt;/code&gt;, &lt;code&gt;line3&lt;/code&gt;... Isso é coisa de maluque! Precisa de uma lista? Use uma lista e pronto!&lt;/li&gt;
&lt;li&gt;Dê significado semântico pros seus nomes: o nome precisa fazer sentido no contexto em que está inserido. Deixa eu explicar um pouco melhor...&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Eu já trabalhei numa empresa que dizia o seguinte: toda variável precisa ter um prefixo que indica o tipo dela. Uma variável &lt;code&gt;var&lt;/code&gt; do tipo inteiro se chama &lt;code&gt;iVar&lt;/code&gt;, do tipo boolean &lt;code&gt;bVar&lt;/code&gt;, do tipo float fica &lt;code&gt;fVar&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Gente, o ano é 2022! Sua IDE e ferramentas de análise estática já vão garantir o tipo de uma variável. Não tem motivo prefixar ou sufixar variável com tipo. Isso não adiciona nenhum sentido semântico.&lt;/p&gt;
&lt;p&gt;Agora quer ver como a semântica muda a compreensão de código? Olha aqui:&lt;/p&gt;
&lt;pre&gt;if (number % 2 === 0) {&lt;br&gt;  // ...&lt;br&gt;}&lt;/pre&gt;
&lt;p&gt;O código acima faz exatamente a mesma coisa que este aqui:&lt;/p&gt;
&lt;pre&gt;const isNumberEven = number % 2 === 0&lt;br&gt;&lt;br&gt;if (isNumberEven) {&lt;br&gt;  // ...&lt;br&gt;}&lt;/pre&gt;
&lt;p&gt;Qual IF você entende com mais facilidade?&lt;/p&gt;
&lt;p class=&quot;msg msg--info&quot;&gt;&lt;strong&gt;Pela semântica, vale tudo! Até criar variável &quot;inútil&quot;.&lt;/strong&gt; Estamos em 2022, você não precisa economizar bits e bytes. Criar uma variável a mais não vai comer sua memória RAM e de quebra vai economizar um tempão de quem lê seu código, inclusive você!&lt;/p&gt;
&lt;h2&gt;Como mecanizar estas práticas&lt;/h2&gt;
&lt;p&gt;E a coisa é esta mesmo: mecanizar. Você precisa adotar estas práticas automaticamente, quase sem pensar!&lt;/p&gt;
&lt;p&gt;Aqui vão algumas dicas pra não se perder nas regras.&lt;/p&gt;
&lt;h3&gt;Feche blocos imediatamente depois de abrir&lt;/h3&gt;
&lt;p&gt;Já se deparou com a situação em que abriu um parêntese, e depois outro, e mais outro e mais outro, e acaba precisando contar parênteses pra saber onde fechar o que?&lt;/p&gt;
&lt;p&gt;&lt;code&gt;a + (b * c ( x + y + (d ^ 2)) + 10)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Sai dessa vida, gente... Ficar contando parêntese, pára com isso...&lt;/p&gt;
&lt;p&gt;Abriu o parêntese? Fecha imediatamente e continua só depois! Abriu chaves? Fecha imediatamente e continua só depois! Seu código vai te exigir pular linha? Pula a linha primeiro e depois volta pra onde tava!&lt;/p&gt;
&lt;pre&gt;if () {&lt;br&gt;}&lt;/pre&gt;
&lt;p&gt;Sabe esse IF aí em cima? Eu quero que você prometa pra mim que só vai escrever a condição dentro dos parênteses depois que tiver digitado o &lt;code&gt;)&lt;/code&gt;.&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/30/close_parens_early.gif&quot; alt=&quot;GIF animado exemplificando como devemos sempre abrir e fechar blocos imediatamente e só depois implementar o código.&quot; width=&quot;1268&quot; height=&quot;772&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;GIF animado exemplificando como devemos sempre abrir e fechar blocos imediatamente e só depois implementar o código.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p class=&quot;msg msg--highlight  msg--info&quot;&gt;Cuide primeiro da sintaxe, depois da semântica! Abriu parêntese, fecha imediatamente. Abriu chaves, fecha imediatamente.&lt;/p&gt;
&lt;h3&gt;A regra dos 80 caracteres&lt;/h3&gt;
&lt;p&gt;Se tu tiver usando uma tela grande pra ler este texto vai reparar que eu não deixo o texto usar a sua tela toda. Sabe o motivo? Porque tu não iria ler, simples assim.&lt;/p&gt;
&lt;p&gt;Linhas longas não são lidas! Quanto maior a linha, menor a atenção que ela vai receber.&lt;/p&gt;
&lt;p&gt;Uma regra comum é a de quebrar a linha depois de um limite. Algumas comunidades adotam 80 caracteres, outras 120. Adote um e seja feliz.&lt;/p&gt;
&lt;p&gt;A maioria dos editores de código vão te ajudar com isso ao colocar uma linha vertical no meio na sua tela. Se o seu código encostar nesta linha, é hora de quebrar linha.&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image&quot; src=&quot;/media/posts/30/ide-quebra-de-linha.jpg&quot; alt=&quot;Imagem mostrando linha vertical guia e exemplos de quebra de linha.&quot; width=&quot;960&quot; height=&quot;473&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Imagem mostrando linha vertical guia e exemplos de quebra de linha.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Agora, atenção ein! Não vai quebrar a linha como quem joga entulho no quintal do vizinho! Se você quebrar linha no contexto de elementos separados por vírgula, dê uma linha para cada elemento.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Não faça isso:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;echo sprintf(&apos;Minha string %s formatada %d vezes&apos;, &apos;Nawarian&apos;,&lt;br&gt;  10);&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Faça isso:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;echo sprintf(&lt;br&gt;  &apos;Minha string %s formatada %d vezes&apos;,&lt;br&gt;  &apos;Nawarian&apos;,&lt;br&gt;  10&lt;br&gt;);&lt;/pre&gt;
&lt;p&gt;E note que o parêntese que fecha a função &lt;code&gt;sprintf&lt;/code&gt; está alinhado verticalmente com o começo da linha que abriu aquele parêntese. Além disso, os parâmetros, cada um em sua linha, estão indentados uma única vez.&lt;/p&gt;
&lt;p class=&quot;msg msg--highlight  msg--info&quot;&gt;Linhas grandes não são lidas, são feias que dói e deveriam te causar repulsa! Quebre a linha sempre que precisar e use uma regra padrão.&lt;/p&gt;
&lt;h3&gt;Escreva seu código duas vezes&lt;/h3&gt;
&lt;p&gt;No início da nossa carreira a gente costuma escrever código e se funcionar, funcionou! Segue o jogo.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Você precisa cortar este hábito o quanto antes!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Sempre que você terminar de escrever um código, volte ao começo e leia tudo de novo pra ver se tem algo que você pode deixar mais claro.&lt;/p&gt;
&lt;p&gt;Lembre-se: você quer escrever código para outras pessoas lerem, não só para o computador ler.&lt;/p&gt;
&lt;p&gt;Uma quebra de linha, um nome de variável melhor, uma modificação na lógica... tudo isso pode ajudar bastante.&lt;/p&gt;
&lt;p&gt;Vou te dar um exemplo. Olha o seguinte snippet de um emulador que eu escrevi:&lt;/p&gt;
&lt;pre&gt;function readZeroPage(): int&lt;br&gt;{&lt;br&gt;  return $this-&amp;gt;bus-&amp;gt;read($this-&amp;gt;state-&amp;gt;pc++) &amp;amp; 0xFF;&lt;br&gt;}&lt;/pre&gt;
&lt;p class=&quot;msg msg--highlight &quot;&gt;Sim, estou escrevendo um emulador de Nintendinho 8-bit. Dá uma olhada no meu &lt;a href=&quot;/devlog-emulador-nes-arquitetura/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Devlog sobre como criar um emulador de NES&lt;/a&gt; pra aprender como fazer o seu.&lt;/p&gt;
&lt;p&gt;O exemplo acima está bem simplificado pra quem entende o domínio. Mas se eu quiser simplificar para que todo mundo possa entender com menos dificuldade, poderia ter algo assim:&lt;/p&gt;
&lt;pre&gt;function readZeroPage(): int&lt;br&gt;{&lt;br&gt;  $address = getProgramCounterAddress();&lt;br&gt;  incrementProgramCounter();&lt;br&gt;&lt;br&gt;  $zeroPageValue = $this-&amp;gt;bus-&amp;gt;read($address);&lt;br&gt;&lt;br&gt;  return asInt8($zeroPageValue);&lt;br&gt;}&lt;/pre&gt;
&lt;p&gt;O que é um código bom ou legível é totalmente subjetivo e depende não só de quem lê, mas também do contexto. No caso do desenvolvimento de um emulador de CPU os conceitos de &lt;code&gt;pc&lt;/code&gt;, &lt;code&gt;bus&lt;/code&gt;, &lt;code&gt;zero page&lt;/code&gt; e &lt;code&gt;int8&lt;/code&gt; são bem comuns. Mas é inegável que o segundo exemplo de código explica muito mais sobre o que está acontecendo do que o primeiro.&lt;/p&gt;
&lt;p class=&quot;msg msg--info&quot;&gt;Depois de escrever seu código - seja uma página, uma função ou um mesmo um IF - releia tudo para identificar se você pode tornar o contexto mais explícito e comunicar a sua intenção com código.&lt;/p&gt;
&lt;h3&gt;Não escreva código como é ensinado em cursos e faculdades&lt;/h3&gt;
&lt;p&gt;Existe um problema muito comum com iniciantes que acabaram de ver um curso ou estão na faculdade. O código das pessoas nessa fase normalmente é BEM RUIM de entender.&lt;/p&gt;
&lt;p&gt;Isto porque nos cursos nós ensinamos conceitos, métodos e técnicas. O estilo de código fica secundário e dá mais trabalho de ensinar ao mesmo tempo.&lt;/p&gt;
&lt;p&gt;Especialmente em faculdades, professores mais velhos - com todo o respeito, nós devemos a modernidade a estes profissionais - adotam costumes que eram comuns há algumas décadas atrás, quando precisávamos economizar espaço a todo custo e conseguíamos parar em frente a um texto por mais de 1 hora sem receber uma notificação de que alguém está tretando no Twitter!&lt;/p&gt;
&lt;p&gt;Boa parte das práticas que são adotadas durante cursos (alô variável temp!) precisam ser extintas do seu vocabulário! Absorva o conteúdo, não o estilo!&lt;/p&gt;
&lt;p&gt;E pra deixar claro, o problema não são os professores mais velhos. O problema é que professores normalmente não escrevem código profissionalmente há alguns bons anos.&lt;/p&gt;
&lt;p class=&quot;msg msg--info&quot;&gt;Adote o estilo de profissionais que trabalham com desenvolvimento software, não ensinando desenvolvimento de software. São duas profissões distintas!&lt;/p&gt;
&lt;h2&gt;O mais importante te tudo: leia código de pessoas mais experientes&lt;/h2&gt;
&lt;p&gt;Fica claro que se você não pode confiar no código de quem te ensina código, precisamos buscar inspiração noutro lugar.&lt;/p&gt;
&lt;p&gt;Como eu disse antes, cada linguagem tem as suas comunidades, convenções e estilos. Cabe a você aprender os estilos que lhe interessam.&lt;/p&gt;
&lt;p&gt;Aqui vão algumas dicas de como achar essa inspiração.&lt;/p&gt;
&lt;h3&gt;Navegue no Github em busca de &lt;em&gt;Pull Requests&lt;/em&gt;&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Pull Requests&lt;/em&gt; são incríveis fontes de conhecimento sobre como as outras pessoas escrevem código.&lt;/p&gt;
&lt;p&gt;Olha &lt;a href=&quot;https://github.com/Seldaek/monolog/pull/1578&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;este exemplo&lt;/a&gt; do repositório aberto do Monolog. Você consegue ver quais arquivos foram modificados, onde e como. Além disso, os responsáveis pelo repositório adicionam comentários e perguntas sobre o código.&lt;/p&gt;
&lt;p&gt;Uma das melhores formas de aprender como escrever código de acordo com o estilo da sua comunidade, é lendo pull requests enviados para esta comunidade.&lt;/p&gt;
&lt;p&gt;Mais efetivo ainda é você enviar um pull request e receber comentários de volta. A comunidade ganha, você ganha, todo mundo ganha!&lt;/p&gt;
&lt;h3&gt;Navegue nos repositórios da sua empresa&lt;/h3&gt;
&lt;p&gt;No contexto de uma empresa, o melhor é ver como as outras pessoas já operam.&lt;/p&gt;
&lt;p&gt;Normalmente se a empresa é moderna no quesito desenvolvimento de software, esta será uma fonte incrível. Mas se você duvida da qualidade do código e das pessoas que o produzem, ignore esta dica - e procure outro emprego o quanto antes.&lt;/p&gt;
&lt;h3&gt;Participe, mesmo que como ouvinte, de discussões sobre estilização de código&lt;/h3&gt;
&lt;p&gt;O que eu disse lá no começo é muito verdade. Tudo depende, e muitas pessoas desenvolvedoras gostam de discutir de fundamentos a nuances sobre estilo de código.&lt;/p&gt;
&lt;p&gt;Participe destas discussões o quanto puder: em reuniões, em conferências, em fóruns, no Twitter... Não importa se você estiver errade! Se alguém te corrigir você terá aprendido. Mas o mais importante é ver outras pessoas trocando conhecimento e opiniões também.&lt;/p&gt;
&lt;h2&gt;Voa, juninhe! Voa!&lt;/h2&gt;
&lt;p&gt;É claro que eu escrevi este artigo num tom mais energético e duro, mas a intenção não é te desmotivar.&lt;/p&gt;
&lt;p&gt;Eu quero que estilo de código seja algo natural pra ti, e que você incorpore estas dicas no seu dia a dia de forma automática pra que possa focar na lógica que está aprendendo, em vez de se preocupar com bobeiras de estilo.&lt;/p&gt;
&lt;p&gt;Se a estilização for tarefa mecânica pra ti, vão te ficar disponíveis muito mais neurônios pra focar no que importa: resolver o seu problema de código.&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image&quot; src=&quot;/media/posts/30/tres-programadoras-felizes.jpg&quot; alt=&quot;Três programadoras em frente ao computador, felizes que o teste passou!&quot; width=&quot;960&quot; height=&quot;640&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Três programadoras em frente ao computador, felizes que o teste passou!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Vai que a sua jornada tá só começando e o futuro é próspero! Voa, juninhe! Voa!&lt;/p&gt;
&lt;p&gt;Compartilha este texto com a galera pra ajudar e trazer pra discussão, belezera? Te vejo na próxima.&lt;/p&gt;</content:encoded><category>junior</category><category>produtividade</category></item><item><title>Sokoban Devlog #01: jogador e movimento</title><link>https://codamos.com.br/devlog-sokoban-jogador-movimento/</link><guid isPermaLink="true">https://codamos.com.br/devlog-sokoban-jogador-movimento/</guid><description>Atenção: o próximo post só vai ser escrito depois de 20 retuítes aqui . Assim você me dá uma força pra crescer o site e me manter motivado a escrever as próximas partes 😉 O post de hoje vai ser bem m</description><pubDate>Sat, 12 Feb 2022 09:22:18 GMT</pubDate><content:encoded>&lt;p class=&quot;msg msg--highlight &quot;&gt;&lt;strong&gt;Atenção:&lt;/strong&gt; o próximo post só vai ser escrito &lt;a href=&quot;https://twitter.com/nawarian/status/1492429776681902082&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;depois de 20 retuítes aqui&lt;/a&gt;. Assim você me dá uma força pra crescer o site e me manter motivado a escrever as próximas partes 😉&lt;/p&gt;
&lt;p&gt;O post de hoje vai ser bem massa pra quem nunca brincou com desenvolvimento de jogos ou tem vontade de entender como fazer sem nenhuma engine como o Godot, Game Maker, Unity ou outras!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;O nosso objetivo é desenhar um personagem na tela e movimentá-lo usando as teclas W,A,S,D.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;No post anterior nós explicamos o objetivo deste projetinho e montamos um ambiente de trabalho simples com Make e compilamos uma janela simples, &lt;a href=&quot;/devlog-sokoban-raylib-esqueleto/&quot;&gt;dá uma olhada nele aqui&lt;/a&gt; caso tenha perdido. Ele é essencial para acompanhar a série toda.&lt;/p&gt;
&lt;div class=&quot;post__toc&quot;&gt;
&lt;h3&gt;Conteúdos do post&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1frmesnsr63&quot;&gt;Gráficos open source: Kenney Sokoban!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1frmesnsr64&quot;&gt;Compilando o jogador&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1frmesnsr65&quot;&gt;Vamos amarrar o sprite ao jogador&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1frmk2abn1f2&quot;&gt;player_create()&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1frmk2abn1f3&quot;&gt;player_destroy()&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1frmk2abn1f4&quot;&gt;player_draw()&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1frmk2abn1f5&quot;&gt;player_update()&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1frmk2abn1f6&quot;&gt;Próximos passos&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id=&quot;mcetoc_1frmesnsr63&quot;&gt;Gráficos open source: Kenney Sokoban!&lt;/h2&gt;
&lt;p&gt;Eu não sou lá um designer gráfico, então normalmente eu uso assets de código aberto disponíveis na internet. &lt;a href=&quot;https://opengameart.org/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;OpenGameArt&lt;/a&gt; e &lt;a href=&quot;https://kenney.nl/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;KenneY&lt;/a&gt; são dois pontos de partida ótimos para fazer prototipação.&lt;/p&gt;
&lt;p&gt;O site KenneY possui um pack específico para jogos do tipo Sokoban, você consegue baixar o pack através &lt;a href=&quot;https://kenney.nl/assets/sokoban&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;deste link&lt;/a&gt;. Todos os assets desenvolvidos pelo Kenney ficam disponíveis com a licença &lt;a href=&quot;https://creativecommons.org/publicdomain/zero/1.0/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Creative Commons (CC0 1.0 Universal)&lt;/a&gt;, que nos permite fazer de tudo com aquele conteúdo: baixar, utilizar para projetos pessoais e comerciais, modificar... E sem sequer precisar pedir permissão. Tá tudo liberado!&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/29/preview_kenneynl.png&quot; alt=&quot;Spritesheet do pacote Sokoban, disponível no site kenney.nl&quot; width=&quot;918&quot; height=&quot;515&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Spritesheet do pacote Sokoban, disponível no site kenney.nl&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Após baixar e extrair o conteúdo, vou mover todos os arquivos do pacote kenney_sokobanpack para um diretório chamado &lt;code&gt;assets/&lt;/code&gt; na raiz do projeto.&lt;/p&gt;
&lt;pre&gt;$ mkdir assets/&lt;br&gt;$ mv ~/Downloads/kenney_sokobanpack ./assets/kenney_sokobanpack/&lt;/pre&gt;
&lt;p&gt;Vários arquivos dentro desta pasta são repetidos e eu não vou me preocupar em limpar a pasta agora. Outros arquivos eu vou fazer questão de manter, como por exemplo o arquivo License.txt e os previews que mantém o logo/assinatura do autor.&lt;/p&gt;
&lt;p&gt;Após adicionar o arquivo, faço &lt;a href=&quot;https://github.com/Terrario/sokoban/commit/4c47834edeafbe37cce406cca8ca444e2a018f0d&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;meu commit&lt;/a&gt; em paz e sigo pra próxima etapa: adicionar o esqueleto do jogador!&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1frmesnsr64&quot;&gt;Compilando o jogador&lt;/h2&gt;
&lt;p&gt;Pra continuar com tudo simplificado, eu vou separar o esforço de compilar o programa do esforço de programar o programa.&lt;/p&gt;
&lt;p&gt;Neste jogo, um jogador possui quatro funções essenciais:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;create: instancia o objeto &lt;em&gt;Player&lt;/em&gt;; Executa antes de o jogo começar&lt;/li&gt;
&lt;li&gt;update: move o jogador, permite interagir com objetos na tela, etc.; Executa no começo do Game Loop&lt;/li&gt;
&lt;li&gt;draw: desenha o jogador na tela; Executa entre os métodos Begin e End Drawing(), após todos os updates&lt;/li&gt;
&lt;li&gt;destroy: libera o espaço de memória utilizado pelo jogador (objetos dinamicamente alocados e sprites); Executa quando saímos do Game Loop&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Quando eu escrevi os arquivos, ignorei a função draw(), mas no próximo commit eu adiciono 😉&lt;/p&gt;
&lt;p&gt;Eu vou precisar criar dois arquivos: &lt;code&gt;src/player.h&lt;/code&gt; e &lt;code&gt;src/player.c&lt;/code&gt;. Se você precisa entender o motivo de a gente precisar de dois arquivos pra mesma coisa em C, me dá um toque que eu escrevo sobre. Mas por enquanto, só confia!&lt;/p&gt;
&lt;p&gt;Neste projeto, você vai notar que todo arquivo de cabeçalho (.h) segue uma estrutura mais ou menos assim:&lt;/p&gt;
&lt;pre&gt;#ifndef __nomedoarquivo_h_&lt;br&gt;#define __nomedoarquivo_h_&lt;br&gt;&lt;br&gt;// Código&lt;br&gt;&lt;br&gt;#endif&lt;/pre&gt;
&lt;p&gt;Essas diretivas (ifndef, define endif) combinadas nos permitem ter certeza de que mesmo se a gente incluir o arquivo de cabeçalho duas vezes no programa, a gente não vai bagunçar com o processo de compilação.&lt;/p&gt;
&lt;p&gt;Pois vamos então adicionar o arquivo &lt;code&gt;src/player.h&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;#ifndef __player_h_&lt;br&gt;#define __player_h_&lt;br&gt;&lt;br&gt;#include &quot;raylib.h&quot;&lt;br&gt;&lt;br&gt;typedef struct {&lt;br&gt;    Texture2D texture;&lt;br&gt;    Rectangle rec;&lt;br&gt;} Player;&lt;br&gt;&lt;br&gt;void player_create();&lt;br&gt;void player_destroy();&lt;br&gt;void player_update();&lt;br&gt;&lt;br&gt;#endif&lt;/pre&gt;
&lt;p&gt;Note que eu criei uma struct com dois campos: &lt;code&gt;Texture2D texture&lt;/code&gt; e &lt;code&gt;Rectangle rec&lt;/code&gt;. Ambos tipos vem da biblioteca Raylib. O campo &lt;em&gt;texture&lt;/em&gt; nos permite guardar uma imagem que será carregada na VRAM, enquanto o campo &lt;em&gt;rec&lt;/em&gt; possui atributos de um retângulo: x, y, width e height.&lt;/p&gt;
&lt;p&gt;Em seguida, defini a assinatura das três funções que mencionei acima. Todas com o prefixo &lt;em&gt;player_&lt;/em&gt;.&lt;/p&gt;
&lt;p class=&quot;msg msg--info&quot;&gt;Prefixar suas funções em C é uma boa prática e pode te salvar muito tempo no futuro, tanto ao procurar quanto ao refatorar código.&lt;/p&gt;
&lt;p&gt;E aqui entra o arquivo &lt;code&gt;src/player.c&lt;/code&gt;, que implementa as funções prototipadas acima:&lt;/p&gt;
&lt;pre&gt;#include &quot;raylib.h&quot;&lt;br&gt;&lt;br&gt;#include &quot;player.h&quot;&lt;br&gt;&lt;br&gt;Player p;&lt;br&gt;&lt;br&gt;void player_create()&lt;br&gt;{&lt;br&gt;}&lt;br&gt;&lt;br&gt;void player_destroy()&lt;br&gt;{&lt;br&gt;}&lt;br&gt;&lt;br&gt;void player_update()&lt;br&gt;{&lt;br&gt;}&lt;/pre&gt;
&lt;p&gt;Note que nós fizemos o include do arquivo &lt;code&gt;player.h&lt;/code&gt;. Sem este include, o tipo Player não seria  encontrado e o nosso arquivo &lt;code&gt;player.c&lt;/code&gt; não seria nunca compilado.&lt;/p&gt;
&lt;p&gt;Como eu disse antes, eu esqueci de escrever a função &lt;code&gt;void player_draw()&lt;/code&gt; e corrijo isto no próximo passo.&lt;/p&gt;
&lt;p&gt;Note que a variável &lt;code&gt;Player p&lt;/code&gt; foi definida no escopo global. Esta é a única forma de manter a variável &lt;em&gt;p&lt;/em&gt; acessível por todas as funções &lt;em&gt;player_*&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Naturalmente, precisamos utilizar as novas funções. Vamos modificar a função main() dentro do arquivo &lt;code&gt;sokoban.c&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;#include &quot;raylib.h&quot;&lt;br&gt;#include &quot;player.h&quot; // struct Player, funções player_*&lt;br&gt;&lt;br&gt;int main(void)&lt;br&gt;{&lt;br&gt;    // ...&lt;br&gt;    player_create(); // instancia o jogador antes de entrar no Loop&lt;br&gt;&lt;br&gt;&lt;span class=&quot;pl-k&quot;&gt;    while&lt;/span&gt; (!&lt;span class=&quot;pl-c1&quot;&gt;WindowShouldClose&lt;/span&gt;()) {&lt;br&gt;        player_update(); // movimentos, itens, pontuação...&lt;br&gt;&lt;br&gt;        // ...&lt;br&gt;    }&lt;br&gt;&lt;br&gt;    player_destroy();&lt;br&gt;&lt;br&gt;    // ...&lt;br&gt;}&lt;/pre&gt;
&lt;p&gt;O último passo é amarrar os novos arquivos no processo de compilação. Para isto, vamos modificar uma única linha do arquivo &lt;code&gt;Makefile&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;pl-smi&quot;&gt;OBJS&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;$(&lt;span class=&quot;pl-smi&quot;&gt;OUT_DIR&lt;/span&gt;)&lt;/span&gt;/player.o &lt;span class=&quot;blob-code-inner blob-code-marker js-code-nav-pass &quot; data-code-marker=&quot;+&quot;&gt;&lt;span class=&quot;pl-s&quot;&gt;$(&lt;span class=&quot;pl-smi&quot;&gt;OUT_DIR&lt;/span&gt;)&lt;/span&gt;/sokoban.o&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Se você se lembra bem, a regra &lt;em&gt;all&lt;/em&gt; do nosso &lt;em&gt;Makefile&lt;/em&gt; utiliza a variável &lt;em&gt;OBJS&lt;/em&gt; como entrada do nosso processo de compilação. Sempre que quisermos adicionar um objeto &lt;em&gt;.o &lt;/em&gt;ao projeto principal, basta adicioná-lo a esta lista.&lt;/p&gt;
&lt;p&gt;O commit que representa esta seção você encontra &lt;a href=&quot;https://github.com/Terrario/sokoban/commit/882d4b7b1a38f66fa6af83c8ec78df601c85f576&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;aqui&lt;/a&gt;. O resultado por enquanto é isso aqui:&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/29/Screenshot-2022-02-12-at-09.27.34.png&quot; alt=&quot;Linha de comando apresenta as chamadas de compilador incluindo o arquivo src/player.c e build/player.o&quot; width=&quot;891&quot; height=&quot;828&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Linha de comando apresenta as chamadas de compilador incluindo o arquivo src/player.c e build/player.o&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;mcetoc_1frmesnsr65&quot;&gt;Vamos amarrar o sprite ao jogador&lt;/h2&gt;
&lt;p&gt;Primeiro, deixa eu criar a função &lt;code&gt;void player_draw()&lt;/code&gt; que eu falhei em colocar da última vez:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;src/player.h&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;pl-k&quot;&gt;// ...&lt;br&gt;void&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;player_destroy&lt;/span&gt;();&lt;br&gt;&lt;span class=&quot;pl-k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;player_draw&lt;/span&gt;();&lt;br&gt;// ...&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;src/player.c&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;// ...&lt;br&gt;void player_draw()&lt;br&gt;{&lt;br&gt;}&lt;br&gt;&lt;br&gt;void player_update()&lt;br&gt;{&lt;br&gt;    // ...&lt;br&gt;}&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;src/sokoban.c&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;// ...&lt;br&gt;BeginDrawing();&lt;br&gt;    ClearBackground(BLACK);&lt;br&gt;&lt;br&gt;    player_draw();&lt;br&gt;&lt;br&gt;    DrawFPS(0, 0);&lt;br&gt;EndDrawing();&lt;br&gt;// ...&lt;/pre&gt;
&lt;p&gt;Outra correção que eu preciso fazer, é sobre a variável global &lt;code&gt;Player p&lt;/code&gt;. Eu preciso ser capaz de alocar esta variável de forma dinâmica (usando &lt;em&gt;malloc&lt;/em&gt;). Portanto eu vou mudar a declaração da variável para que seja um ponteiro. Para declarar uma variável como ponteiro, basta prefixar seu nome com um asterisco:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;src/player.c&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;// ...&lt;br&gt;&lt;br&gt;Player *p;&lt;br&gt;&lt;br&gt;// ...&lt;/pre&gt;
&lt;p&gt;Se você compilar e rodar agora, absolutamente NADA deverá ter mudado. Vamos então implementar as funções &lt;em&gt;player_*&lt;/em&gt; uma por uma para dar vida ao nosso jogo.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1frmk2abn1f2&quot;&gt;player_create()&lt;/h3&gt;
&lt;p&gt;A variável &lt;em&gt;p&lt;/em&gt; está em escopo global. Nós só precisamos alocá-la em memória, carregar a textura e dar uma posição para o jogador. O meio da tela está bom por agora.&lt;/p&gt;
&lt;p&gt;Aqui fica a implementação completa da função player_create:&lt;/p&gt;
&lt;pre&gt;&lt;span class=&quot;pl-k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;pl-en&quot;&gt;player_create&lt;/span&gt;()&lt;br&gt;{&lt;br&gt;    p = (Player *) &lt;span class=&quot;pl-c1&quot;&gt;malloc&lt;/span&gt;(&lt;span class=&quot;pl-k&quot;&gt;sizeof&lt;/span&gt;(Player));&lt;br&gt;&lt;br&gt;    p-&amp;gt;&lt;span class=&quot;pl-smi&quot;&gt;texture&lt;/span&gt; = &lt;span class=&quot;pl-c1&quot;&gt;LoadTexture&lt;/span&gt;(&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;assets/kenney_sokobanpack/PNG/Retina/Player/player_03.png&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;);&lt;br&gt;    p-&amp;gt;&lt;span class=&quot;pl-smi&quot;&gt;rec&lt;/span&gt; = (Rectangle) {&lt;br&gt;        &lt;span class=&quot;pl-c1&quot;&gt;GetScreenWidth&lt;/span&gt;() / &lt;span class=&quot;pl-c1&quot;&gt;2&lt;/span&gt; - p-&amp;gt;&lt;span class=&quot;pl-smi&quot;&gt;texture&lt;/span&gt;.&lt;span class=&quot;pl-smi&quot;&gt;width&lt;/span&gt; / &lt;span class=&quot;pl-c1&quot;&gt;2&lt;/span&gt;,&lt;br&gt;        &lt;span class=&quot;pl-c1&quot;&gt;GetScreenHeight&lt;/span&gt;() / &lt;span class=&quot;pl-c1&quot;&gt;2&lt;/span&gt; - p-&amp;gt;&lt;span class=&quot;pl-smi&quot;&gt;texture&lt;/span&gt;.&lt;span class=&quot;pl-smi&quot;&gt;height&lt;/span&gt; / &lt;span class=&quot;pl-c1&quot;&gt;2&lt;/span&gt;,&lt;br&gt;        128,&lt;br&gt;        128&lt;br&gt;    };&lt;br&gt;}&lt;/pre&gt;
&lt;p&gt;qq tá cotecenu? Vamos por partes:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;p = (Player *) malloc(sizeof(Player));&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Antes desta linha, nós tínhamos algo como &lt;code&gt;Player *p;&lt;/code&gt;, que declara a existência de um ponteiro. Mas na verdade este ponteiro é &lt;code&gt;NULL&lt;/code&gt; e não está pronto para guardar valor nenhum. Em outras palavras, o compilador ainda não nos deu memória para guardar um objeto do tipo &lt;em&gt;struct Player&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;A função &lt;em&gt;malloc()&lt;/em&gt; nos permite alocar memória de forma dinâmica. O parâmetro desta função é o tamanho (em bytes) de memória que eu quero. No caso, eu pedi espaço o suficiente para guardar um objeto do tipo &lt;em&gt;struct Player&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;O retorno da função &lt;em&gt;malloc&lt;/em&gt; é um endereço de memória reservado para nós, que tem exatamente aquele tamanho.&lt;/p&gt;
&lt;p&gt;O cast &lt;code&gt;(Player *)&lt;/code&gt; serve apenas para dizer ao compilador que a gente pode confiar que aquele pedaço de memória pode ser tratado como um &lt;em&gt;struct Player&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;O resto é bem fácil de explicar.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;p-&amp;gt;&lt;span class=&quot;pl-smi&quot;&gt;texture&lt;/span&gt; = &lt;span class=&quot;pl-c1&quot;&gt;LoadTexture&lt;/span&gt;(&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;.../player_03.png&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;);&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Carregamos para a VRAM o arquivo &lt;em&gt;player_03.png&lt;/em&gt; do sokoban pack. A função &lt;em&gt;LoadTexture&lt;/em&gt; vem da Raylib.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;p-&amp;gt;&lt;span class=&quot;pl-smi&quot;&gt;rec&lt;/span&gt; = (Rectangle) { 0 }&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Aqui nós montamos o retângulo que representa o jogador. &lt;em&gt;Rectangle&lt;/em&gt; é uma struct que a Raylib fornece. Seu formato é &lt;code&gt;{ float x; float y; float width; float height }&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;O tamanho da textura é de 128x128, portanto o que estamos fazendo é posicionar o jogador no meio da tela.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1frmk2abn1f3&quot;&gt;player_destroy()&lt;/h3&gt;
&lt;p&gt;O mais fácil de explicar agora, é a função destroy() que deverá ser chamada quando saímos do Game Loop (quando você pressionar ESC).&lt;/p&gt;
&lt;p&gt;Nós precisamos limpar dois espaços de memória importantíssimos: a textura que carregamos e o próprio objeto &lt;em&gt;Player *p&lt;/em&gt;.&lt;/p&gt;
&lt;p class=&quot;msg msg--info&quot;&gt;Quando você solicitar um pedaço de memória de forma dinâmica, usando &lt;em&gt;malloc()&lt;/em&gt;, lembre-se SEMPRE de limpar este espaço de memória depois, usando &lt;em&gt;free()&lt;/em&gt;. Do contrário você vai gerar &lt;em&gt;memory leaks&lt;/em&gt; que são difíceis de encontrar.&lt;/p&gt;
&lt;p&gt;E é assim que nós fazemos:&lt;/p&gt;
&lt;pre&gt;void player_destroy()&lt;br&gt;{&lt;br&gt;    UnloadTexture(p-&amp;gt;texture);&lt;br&gt;    free(p);&lt;br&gt;}&lt;/pre&gt;
&lt;p&gt;Note que nós limpamos &lt;em&gt;p-&amp;gt;texture&lt;/em&gt; ANTES de limpar &lt;em&gt;p&lt;/em&gt;. Isto porque &lt;em&gt;p-&amp;gt;texture &lt;/em&gt;é só um ponteiro para uma tabela da própria Raylib. Se nós destruíssemos a variável &lt;em&gt;p&lt;/em&gt; antes, não teríamos mais acesso ao identificador da textura e portanto ela ficaria em memória para sempre, apesar de não ser utilizada.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1frmk2abn1f4&quot;&gt;player_draw()&lt;/h3&gt;
&lt;pre&gt;void player_draw()&lt;br&gt;{&lt;br&gt;    if (p == NULL) {&lt;br&gt;        return;&lt;br&gt;    }&lt;br&gt;&lt;br&gt;    DrawTexture(&lt;br&gt;        p-&amp;gt;texture,&lt;br&gt;        p-&amp;gt;rec.x,&lt;br&gt;        p-&amp;gt;rec.y,&lt;br&gt;        WHITE&lt;br&gt;    );&lt;br&gt;}&lt;/pre&gt;
&lt;p&gt;Primeiro verificamos a possibilidade de &lt;em&gt;p&lt;/em&gt; ser um ponteiro nulo. Desta vez nós evitamos um &lt;em&gt;segmentation fault&lt;/em&gt; caso qualquer bug estranho acabe limpando a variável &lt;em&gt;p&lt;/em&gt; antes de chamar a função &lt;em&gt;player_draw()&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Depois utilizamos a função &lt;code&gt;void DrawTexture(Texture2D tex, float x, float y, Color tint)&lt;/code&gt; da biblioteca Raylib. Isto deverá desenhar a textura inteira (128x128) na tela, nas coordenadas (&lt;em&gt;p-&amp;gt;rec.x; p-&amp;gt;rec.y&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;A partir daqui já podemos ver algum resultado:&lt;/p&gt;
&lt;p&gt;&lt;img class=&quot;post__image&quot; src=&quot;/media/posts/29/Screenshot-2022-02-12-at-09.55.42.png&quot; alt=&quot;&quot; width=&quot;799&quot; height=&quot;624&quot;&gt;&lt;/p&gt;
&lt;p&gt;Maaassa!!&lt;/p&gt;
&lt;p&gt;Mas ainda não adicionamos movimento ao jogador. Vamos mexer no update.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1frmk2abn1f5&quot;&gt;player_update()&lt;/h3&gt;
&lt;p&gt;Vamos assumir algumas coisas aqui:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A textura tem dimensões de 128x128. Portanto para parecer que o jogador andou para qualquer direção, precisamos o deslocar em 128 pixels naquela direção;&lt;/li&gt;
&lt;li&gt;Não nos interessa fazer um movimento &quot;macio&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A Raylib tem uma função muito útil chamada &lt;em&gt;IsKeyPressed&lt;/em&gt;, com a seguinte assinatura: &lt;code&gt;bool IsKeyPressed(int key)&lt;/code&gt;. Ela também tem um tipo chamado &lt;em&gt;Vector2&lt;/em&gt;, que é um struct com os seguintes campos: &lt;code&gt;{ float x, float y }&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Um valor &lt;em&gt;bool&lt;/em&gt; também pode ser representado como 0 ou 1. Portanto &lt;code&gt;10 - true&lt;/code&gt; teoricamente é igual a 9.&lt;/p&gt;
&lt;p&gt;Então vamos ao código e eu te explico o o que eu fiz:&lt;/p&gt;
&lt;pre&gt;void player_update()&lt;br&gt;{&lt;br&gt;    Vector2 delta = { 0 };&lt;br&gt;&lt;br&gt;    delta.x = (&lt;span class=&quot;pl-c1&quot;&gt;IsKeyPressed&lt;/span&gt;(KEY_D) - &lt;span class=&quot;pl-c1&quot;&gt;IsKeyPressed&lt;/span&gt;(KEY_A)) * &lt;span class=&quot;pl-c1&quot;&gt;128&lt;/span&gt;;&lt;br&gt;    delta.y = (&lt;span class=&quot;pl-c1&quot;&gt;IsKeyPressed&lt;/span&gt;(KEY_S) - &lt;span class=&quot;pl-c1&quot;&gt;IsKeyPressed&lt;/span&gt;(KEY_W)) * &lt;span class=&quot;pl-c1&quot;&gt;128&lt;/span&gt;;&lt;br&gt;&lt;br&gt;    p-&amp;gt;rec.x += delta.x;&lt;br&gt;    p-&amp;gt;rec.y += delta.y;&lt;br&gt;}&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Vector2 delta = { 0 };&lt;/code&gt; aqui nós apenas criamos uma variável do tipo &lt;em&gt;struct Vector2&lt;/em&gt; com o valor x = 0 e y = 0.&lt;/p&gt;
&lt;p&gt;Em seguida fizemos uma matemática simples para a movimentação horizontal e vertical. Os resultados de &lt;em&gt;IsKeyPressed(KEY_*) - IsKeyPressed(KEY_*)&lt;/em&gt; sempre serão 1, 0 ou -1. Veja a tabela abaixo:&lt;/p&gt;
&lt;table class=&quot;align-center&quot; style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;0&quot;&gt;&lt;caption&gt;&lt;em&gt;Tabela verdade para a subtração IsKeyPressed() - IsKeyPressed()&lt;/em&gt;&lt;/caption&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 37.6918%;&quot;&gt;&lt;strong&gt;Expressão (bool)&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;width: 31.6946%;&quot;&gt;&lt;strong&gt;Equivalente (int)&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;width: 30.6136%;&quot;&gt;&lt;strong&gt;Valor&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 37.6918%;&quot;&gt;true - false&lt;/td&gt;
&lt;td style=&quot;width: 31.6946%;&quot;&gt;1 - 0&lt;/td&gt;
&lt;td style=&quot;width: 30.6136%;&quot;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 37.6918%;&quot;&gt;false - false&lt;/td&gt;
&lt;td style=&quot;width: 31.6946%;&quot;&gt;0 - 0&lt;/td&gt;
&lt;td style=&quot;width: 30.6136%;&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 37.6918%;&quot;&gt;true - true&lt;/td&gt;
&lt;td style=&quot;width: 31.6946%;&quot;&gt;1 - 1&lt;/td&gt;
&lt;td style=&quot;width: 30.6136%;&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 37.6918%;&quot;&gt;false - true&lt;/td&gt;
&lt;td style=&quot;width: 31.6946%;&quot;&gt;0 - 1&lt;/td&gt;
&lt;td style=&quot;width: 30.6136%;&quot;&gt;-1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Portanto ao multiplicar este resultado por 128, temos um movimento que representa 128, 0 ou -128 pixels.&lt;/p&gt;
&lt;p&gt;O resultado deste cálculo estamos armazenando na variável &lt;em&gt;delta&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Depois somamos delta.x e delta.y ao p-&amp;gt;rec (retângulo que representa o jogador). E com isso temos o movimento preparado. Vamos esclarecer com um pseudo caso de testes:&lt;/p&gt;
&lt;pre&gt;// Supondo que p-&amp;gt;rec está nas coordenadas (100, 100)&lt;br&gt;p-&amp;gt;rec.x = 100;&lt;br&gt;p-&amp;gt;rec.y = 100;&lt;br&gt;&lt;br&gt;// Se eu pressionar a tecla A e nenhuma outra tecla&lt;br&gt;delta.x = (false - true) * 128; // -1 * 128 = -128&lt;br&gt;delta.y = (false - false) * 128; // 0 * 128 = 0&lt;br&gt;&lt;br&gt;// Então a posição do jogador deverá ser (-28, 100)&lt;br&gt;p-&amp;gt;rec.x += delta.x; // 100 + (-128) = -28&lt;br&gt;p-&amp;gt;rec.y += delta.y; // 100 + 0 = 100&lt;/pre&gt;
&lt;p&gt;E aqui você confere o resultado na íntegra:&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/29/sokoban_player_demo.gif&quot; alt=&quot;GIF animado ilustrando o resultado do post de hoje: um personagem se movendo pela tela.&quot; width=&quot;1416&quot; height=&quot;882&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;GIF animado ilustrando o resultado do post de hoje: um personagem se movendo pela tela.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Depois eu disso eu só dei uma limpadinha no código pra remover aquele número 128 mágico de lá e usar variáveis em vez disso.&lt;/p&gt;
&lt;p&gt;O Pull Request todo você encontra aqui: &lt;a href=&quot;https://github.com/Terrario/sokoban/pull/2&quot; rel=&quot;nofollow&quot;&gt;Terrario/sokobão PR #2&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1frmk2abn1f6&quot;&gt;Próximos passos&lt;/h2&gt;
&lt;p&gt;Bom, nós já criamos o jogador. Agora precisamos criar alguns obstáculos na tela.&lt;/p&gt;
&lt;p&gt;No próximo post vamos implementar um bloco simples. E a partir disso vamos trabalhar com colisão: um jogador não pode atravessar um bloco.&lt;/p&gt;
&lt;p class=&quot;msg msg--info&quot;&gt;Mas eu preciso da sua ajuda pra desenvolver o próximo post. Preciso que você divulgue este post aqui. Quando eu alcançar &lt;a href=&quot;https://twitter.com/nawarian/status/1492429776681902082&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;20 retuítes aqui&lt;/a&gt;, começo a escrever o próximo post.&lt;/p&gt;
&lt;p&gt;Desta forma você me ajuda a popularizar o blog e ajuda outras pessoas encontrar este conteúdo massa!&lt;/p&gt;
&lt;p&gt;Até a próxima! 👋&lt;/p&gt;</content:encoded><category>c</category><category>devlog</category><category>jogos</category><category>raylib</category><category>sokoban</category></item><item><title>ConstruDelas: Capacitação em .NET, inscrições abertas!</title><link>https://codamos.com.br/capacitacao-net-construdelas-fevereiro-2022/</link><guid isPermaLink="true">https://codamos.com.br/capacitacao-net-construdelas-fevereiro-2022/</guid><description>Inscrições até o dia 25/02/2022, corre se candidatar! Estão abertas as inscrições para o ConstruDelas, programa de formação de mulheres em desenvolvimento back-end .NET, em parceria com a @juntossomos</description><pubDate>Mon, 07 Feb 2022 15:16:16 GMT</pubDate><content:encoded>&lt;p class=&quot;msg msg--info&quot;&gt;Inscrições até o dia 25/02/2022, corre se candidatar!&lt;/p&gt;
&lt;p&gt;Estão abertas as inscrições para o ConstruDelas, programa de formação de mulheres em desenvolvimento back-end .NET, em parceria com a &lt;a href=&quot;https://bit.ly/juntossomosmais_construdelas&quot; target=&quot;_blank&quot; rel=&quot;nofollow sponsored noopener noreferrer&quot;&gt;@juntossomosmais&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;O ConstruDelas tem duração de 21 semanas com &lt;strong&gt;29 vagas&lt;/strong&gt; que atenderão, preferencialmente, mulheres em vulnerabilidade social, econômica, negras ou LGBTQIAP+, com pouco ou nenhum conhecimento em programação, para receberem um treinamento gratuito com o objetivo de atuarem como desenvolvedoras.&lt;/p&gt;
&lt;p&gt;Não são exigidas experiências prévias ou formação profissional em tecnologia!&lt;/p&gt;
&lt;p&gt;Acesse o link &lt;a href=&quot;https://bit.ly/construdelas_fev_2022&quot; target=&quot;_blank&quot; rel=&quot;nofollow sponsored noopener noreferrer&quot;&gt;https://womakerscode.org/construdelas&lt;/a&gt; para se inscrever.&lt;/p&gt;
&lt;h2&gt;Como participar&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Preencha do formulário de inscrição, até o dia 25 de Fevereiro, às 18h&lt;/li&gt;
&lt;li&gt;Envie um vídeo de apresentação&lt;/li&gt;
&lt;li&gt;Realize o curso de introdução até 26/02, às 18h&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Edital&lt;/h2&gt;
&lt;p&gt;Para mais informações sobre o processo de seleção e quem pode participar, dá uma olhadinha no Edital &lt;a href=&quot;https://bit.ly/construdelas_edital_fev_2022&quot; target=&quot;_blank&quot; rel=&quot;nofollow sponsored noopener noreferrer&quot;&gt;aqui&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Curtiu? Faça a sua inscrição e se você conhece outra mulher que pode se interessar por essa oportunidade, manda este link pra ela, marca nos comentários ou o que for!&lt;/p&gt;
&lt;blockquote class=&quot;twitter-tweet&quot;&gt;
&lt;p dir=&quot;ltr&quot; lang=&quot;pt&quot;&gt;Salve, salve. Novidade massa na área!&lt;br&gt;&lt;br&gt;A galera do &lt;a href=&quot;https://twitter.com/womakerscode?ref_src=twsrc%5Etfw&quot;&gt;@womakerscode&lt;/a&gt; junto da &lt;a href=&quot;https://twitter.com/hashtag/juntossomosmais?src=hash&amp;amp;ref_src=twsrc%5Etfw&quot;&gt;#juntossomosmais&lt;/a&gt; está com inscrições abertas pra uma capacitação &lt;a href=&quot;https://twitter.com/hashtag/net?src=hash&amp;amp;ref_src=twsrc%5Etfw&quot;&gt;#net&lt;/a&gt; para &lt;a href=&quot;https://twitter.com/hashtag/mulheres?src=hash&amp;amp;ref_src=twsrc%5Etfw&quot;&gt;#mulheres&lt;/a&gt;. Bora se inscrever e compartilhar com geral!!&lt;a href=&quot;https://t.co/OwpYQJ18s9&quot;&gt;https://t.co/OwpYQJ18s9&lt;/a&gt;&lt;/p&gt;
— Níckolas Da Silva (nawarian) (@nawarian) &lt;a href=&quot;https://twitter.com/nawarian/status/1490707066859704320?ref_src=twsrc%5Etfw&quot;&gt;February 7, 2022&lt;/a&gt;&lt;/blockquote&gt;
&lt;p&gt;
&lt;script async=&quot;&quot; src=&quot;https://platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;
&lt;/p&gt;</content:encoded><category>net</category></item><item><title>Sokoban Devlog #00: esqueleto da aplicação</title><link>https://codamos.com.br/devlog-sokoban-raylib-esqueleto/</link><guid isPermaLink="true">https://codamos.com.br/devlog-sokoban-raylib-esqueleto/</guid><description>Conteúdo do post Vamos preparar o nosso ambiente de desenvolvimento Repositório no Github Uma janela simples usando raylib Automação de build com make Alguns toques finais Próximos passos A raylib é u</description><pubDate>Fri, 28 Jan 2022 12:48:08 GMT</pubDate><content:encoded>&lt;div class=&quot;post__toc&quot;&gt;
&lt;h3&gt;Conteúdo do post&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fq8vqlt0142&quot;&gt;Vamos preparar o nosso ambiente de desenvolvimento&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fq8vqlt0143&quot;&gt;Repositório no Github&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fq8vqlt0144&quot;&gt;Uma janela simples usando raylib&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fq8vqlt0145&quot;&gt;Automação de build com make&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fq8vqlt0146&quot;&gt;Alguns toques finais&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fq8vqlt0147&quot;&gt;Próximos passos&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p&gt;A &lt;a href=&quot;https://raylib.com/&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;raylib&lt;/a&gt; é uma biblioteca de desenvolvimento de jogos escrita em C. Não traz consigo coisas como gerenciamento de assets, gravidade e outras ferramentas prontas. Apenas o básico que alguém precisa para desenvolver jogos sem muita dor de cabeça.&lt;/p&gt;
&lt;p&gt;Desde que eu comecei a &lt;a href=&quot;/php-ffi/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;usar a raylib com o PHP&lt;/a&gt;, comecei a tomar gosto por desenvolver com a linguagem C. E acho que já está mais do que na hora de encarar um projeto em C do começo ao fim. Portanto vou iniciar a série Sokoban usando raylib.&lt;/p&gt;
&lt;p&gt;A ideia de escrever um jogo do tipo Sokoban é simples: eu não sou um &lt;em&gt;Game Designer&lt;/em&gt; e a única habilidade que eu quero desenvolver é a de programar em C. Sokoban é um jogo simples o suficiente em termos de gráficos e que vai me permitir praticar bastante minhas habilidades em C.&lt;/p&gt;
&lt;p&gt;Sokoban é um estilo de jogo do tipo &lt;em&gt;puzzle&lt;/em&gt;, onde você passa de fase ao empurrar caixas no lugar correto de forma a resolver o quebra cabeças. Aqui tem um vídeo que ilustra bem como um jogo do tipo Sokoban se parece:&lt;/p&gt;
&lt;p&gt;&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube-nocookie.com/embed/Vdu6ut88SQY&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;allowfullscreen&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1fq8vqlt0142&quot;&gt;Vamos preparar o nosso ambiente de desenvolvimento&lt;/h2&gt;
&lt;p&gt;O primeiro post, naturalmente, vai tratar do ambiente de desenvolvimento. E neste caso vou manter tudo muito simples. As ferramentas que vou utilizar para desenvolvimento:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;VIM - editor de textos&lt;/li&gt;
&lt;li&gt;clang - compilador C, padrão no MacOS&lt;/li&gt;
&lt;li&gt;make - ferramenta de automação de &lt;em&gt;build&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;pkg-config - nos ajuda a encontrar diretório das bibliotecas no computador&lt;/li&gt;
&lt;li&gt;raylib - biblioteca de programação de jogos&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Uma única linha de comando já deve instalar tudo o que a gente precisa no MacOS:&lt;/p&gt;
&lt;pre&gt;$ brew install vim make pkg-config raylib&lt;/pre&gt;
&lt;p&gt;Com tudo instalado, vamos criar um projeto vazio e rodar a nossa primeira janela para ter certeza de que tudo está funcionando.&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1fq8vqlt0143&quot;&gt;Repositório no Github&lt;/h2&gt;
&lt;p&gt;Vou criar um novo repositório chamado &lt;a href=&quot;https://github.com/Terrario/sokoban&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;Terrario/sokoban&lt;/a&gt;. E já vou inicializar este repositório com um README.md, licença GPL-3 e um &lt;code&gt;.gitignore&lt;/code&gt; básico.&lt;/p&gt;
&lt;figure class=&quot;post__image&quot;&gt;
&lt;p&gt;&lt;img class=&quot;post__image post__image--center&quot; src=&quot;/media/posts/27/github_repo_screenshot.png&quot; alt=&quot;&quot; width=&quot;739&quot; height=&quot;847&quot;&gt;&lt;/p&gt;
&lt;/figure&gt;
&lt;p&gt;Com o repositório criado, posso fazer o clone na minha máquina:&lt;/p&gt;
&lt;pre&gt;$ git clone &lt;a href=&quot;mailto:git@github.com:Terrario/sokoban.git&quot;&gt;git@github.com:Terrario/sokoban.git&lt;/a&gt;&lt;br&gt;$ cd sokoban/&lt;/pre&gt;
&lt;p&gt;E agora já posso preparar a janela do Raylib e deixar tudo certo pra compilar e rodar o programa.&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1fq8vqlt0144&quot;&gt;Uma janela simples usando raylib&lt;/h2&gt;
&lt;p&gt;Vou criar um arquivo &lt;code&gt;src/sokoban.c&lt;/code&gt; que vai conter a nossa função main(). Nele vou colocar o seguinte snippet:&lt;/p&gt;
&lt;pre&gt;#include &quot;raylib.h&quot;&lt;br&gt;&lt;br&gt;int main(void)&lt;br&gt;{&lt;br&gt;    InitWindow(800, 600, &quot;Sokobão&quot;);&lt;br&gt;    SetTargetFPS(60);&lt;br&gt;    &lt;br&gt;    while (!WindowShouldClose()) {&lt;br&gt;        // Game loop&lt;br&gt;        BeginDrawing();&lt;br&gt;            ClearBackground(BLACK);&lt;br&gt;&lt;br&gt;            DrawFPS(0, 0);&lt;br&gt;        EndDrawing();&lt;br&gt;    }&lt;br&gt;&lt;br&gt;    CloseWindow();&lt;br&gt;&lt;br&gt;    return 0;&lt;br&gt;}&lt;/pre&gt;
&lt;p&gt;O programa acima não faz nada de mais. Em sequência nós:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Criamos uma janela de 800x600 e título &quot;Sokobão&quot;&lt;/li&gt;
&lt;li&gt;Definimos que o nosso jogo roda em 60 frames por segundo&lt;/li&gt;
&lt;li&gt;Montamos o loop infinito (game loop)&lt;/li&gt;
&lt;li&gt;Dentro do loop infinito, desenhamos na tela
&lt;ol&gt;
&lt;li&gt;Primeiro pintamos a tela toda de preto&lt;/li&gt;
&lt;li&gt;Depois desenhamos o &lt;em&gt;framerate&lt;/em&gt; nas coordenadas x = 0, y = 0 da tela&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Ao sair do loop (pressionar &lt;em&gt;ESC&lt;/em&gt;), fechamos a janela&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Vamos compilar e ver se funciona!&lt;/p&gt;
&lt;pre&gt;$ mkdir build/&lt;br&gt;$ clang src/sokoban.c -o build/sokoban -lraylib&lt;br&gt;$ ./build/sokoban&lt;/pre&gt;
&lt;figure class=&quot;post__image&quot;&gt;
&lt;p&gt;&lt;img class=&quot;post__image post__image--center&quot; src=&quot;/media/posts/27/janela_raylib_c.png&quot; alt=&quot;&quot; width=&quot;768&quot; height=&quot;481&quot;&gt;&lt;/p&gt;
&lt;/figure&gt;
&lt;p&gt;Parece funcionar bonitinho 🎉&lt;/p&gt;
&lt;p&gt;Agora vamos automatizar a build um pouco.&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1fq8vqlt0145&quot;&gt;Automação de build com &lt;em&gt;make&lt;/em&gt;&lt;/h2&gt;
&lt;p&gt;Vamos criar um arquivo chamado &lt;code&gt;Makefile&lt;/code&gt; com o seguinte conteúdo:&lt;/p&gt;
&lt;pre&gt;CC=clang&lt;br&gt;CFLAGS=`pkg-config --cflags raylib` -std=c99&lt;br&gt;LIBS=`pkg-config --libs raylib`&lt;br&gt;&lt;br&gt;MKDIR=mkdir -p&lt;br&gt;RMDIR=rm -rf&lt;br&gt;&lt;br&gt;SRC_DIR=src&lt;br&gt;OUT_DIR=build&lt;br&gt;&lt;br&gt;OBJS=$(OUT_DIR)/sokoban.o&lt;br&gt;&lt;br&gt;all: $(OUT_DIR) $(OBJS)&lt;br&gt; $(CC) $(OBJS) -o $(OUT_DIR)/sokoban $(LIBS)&lt;br&gt;&lt;br&gt;run: all&lt;br&gt; $(OUT_DIR)/sokoban&lt;br&gt;&lt;br&gt;clean:&lt;br&gt; $(RMDIR) $(OUT_DIR)&lt;br&gt;&lt;br&gt;.PHONY: clean&lt;br&gt;&lt;br&gt;$(OUT_DIR)/%.o: $(SRC_DIR)/%.c&lt;br&gt; $(CC) -c $&amp;lt; -o $@ $(CFLAGS)&lt;br&gt;&lt;br&gt;$(OUT_DIR):&lt;br&gt; $(MKDIR) $(OUT_DIR)&lt;/pre&gt;
&lt;p class=&quot;msg msg--info&quot;&gt;&lt;strong&gt;Lembre-se:&lt;/strong&gt; Makefile não usa espaços para indentação, mas sim tabulações.&lt;/p&gt;
&lt;p&gt;Se o &lt;em&gt;Makefile&lt;/em&gt; ficou estranho, me dá um alô que eu posso escrever um tutorial só sobre makefiles. O que é importante pra gente é a variável &lt;code&gt;&lt;em&gt;OBJS&lt;/em&gt;&lt;/code&gt; que no momento só aponta para um objeto. Conforme nós adicionarmos mais arquivos .c no projeto, vamos modificar aquela variável.&lt;/p&gt;
&lt;p&gt;É possível fazer isso de forma mais dinâmica, mas eu não acho que esse projeto vá crescer tanto em número de arquivos. Se crescer, eu mudo o &lt;em&gt;Makefile&lt;/em&gt; 😛.&lt;/p&gt;
&lt;p&gt;Agora basta rodar &lt;em&gt;make clean run&lt;/em&gt; pra recompilar o projeto todo e executar a nossa janelinha:&lt;/p&gt;
&lt;pre&gt;$ make clean run&lt;/pre&gt;
&lt;figure class=&quot;post__image&quot;&gt;
&lt;p&gt;&lt;img class=&quot;post__image post__image--center&quot; src=&quot;/media/posts/27/janela_raylib_c_2.png&quot; alt=&quot;&quot; width=&quot;768&quot; height=&quot;480&quot;&gt;&lt;/p&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;mcetoc_1fq8vqlt0146&quot;&gt;Alguns toques finais&lt;/h2&gt;
&lt;p&gt;Vamos deixar tudo organizadinho antes de fechar o post e limpar o repositório um pouco.&lt;/p&gt;
&lt;p&gt;Nós não queremos nunca que a pasta &lt;em&gt;build&lt;/em&gt; suba para o repositório. Então vou adicionar estas linhas ao arquivo &lt;code&gt;.gitignore&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;# Build folder&lt;br&gt;build&lt;/pre&gt;
&lt;p&gt;Agora vamos adicionar jogar tudo para o Github. Afinal de contas, se não está na internet, não existe 😉.&lt;/p&gt;
&lt;p&gt;Se quiser saber como subir arquivos no Github, dá uma olhada neste post fera do &lt;a href=&quot;https://github.com/japostulo&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;João Apostulo&lt;/a&gt; sobre &lt;a href=&quot;/subindo-arquivos-no-github/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;como subir arquivos no github&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1fq8vqlt0147&quot;&gt;Próximos passos&lt;/h2&gt;
&lt;p&gt;O próximo passo vai ser carregar os assets para o nosso projeto e fazer um bonequinho se mexer na tela.&lt;/p&gt;
&lt;p&gt;Eu vou usar os assets &lt;a href=&quot;https://kenney.nl/assets/sokoban&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;&lt;em&gt;Open Source&lt;/em&gt; do Kenney&lt;/a&gt; pra isso. Aqui tem uma imagem de exemplo direto do site dele:&lt;/p&gt;
&lt;figure class=&quot;post__image&quot;&gt;
&lt;p&gt;&lt;img class=&quot;post__image post__image--center&quot; src=&quot;/media/posts/27/sokoban_kenney.png&quot; alt=&quot;&quot; width=&quot;768&quot; height=&quot;431&quot;&gt;&lt;/p&gt;
&lt;/figure&gt;
&lt;p&gt;E por hoje é isso. Não se esquece de comentar e compartilhar o post pra dar uma força pra gente!&lt;/p&gt;
&lt;p&gt;O &lt;em&gt;Pull Request&lt;/em&gt; deste capítulo você encontra no meu Github através &lt;a href=&quot;https://github.com/Terrario/sokoban/pull/1&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;deste link&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;O link para o próximo post é este &lt;a href=&quot;/devlog-sokoban-jogador-movimento/&quot;&gt;aqui&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Até a próxima 👋&lt;/p&gt;</content:encoded><category>c</category><category>devlog</category><category>jogos</category><category>raylib</category><category>sokoban</category></item><item><title>Ambiente de desenvolvimento Rust</title><link>https://codamos.com.br/ambiente-de-desenvolvimento-rust/</link><guid isPermaLink="true">https://codamos.com.br/ambiente-de-desenvolvimento-rust/</guid><description>Atenção: este texto foi traduzido, editado e adaptado por @nawarian . Você encontra o texto original, escrito em 2017 em inglês, no blog parceiro Hoverbear.org através deste link . Conteúdos do post C</description><pubDate>Mon, 24 Jan 2022 21:12:21 GMT</pubDate><content:encoded>&lt;p class=&quot;msg msg--highlight  msg--info&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Atenção:&lt;/strong&gt; este texto foi traduzido, editado e adaptado por &lt;a class=&quot;sc-gGBfsJ ezSIMS&quot; href=&quot;https://twitter.com/nawarian&quot; title=&quot;https://twitter.com/nawarian&quot; data-renderer-mark=&quot;true&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;@nawarian&lt;/a&gt;. Você encontra o texto original, escrito em 2017 em inglês, no blog parceiro Hoverbear.org através &lt;a href=&quot;https://hoverbear.org/blog/setting-up-a-rust-devenv/&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;deste link&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;post__toc&quot;&gt;
&lt;h3&gt;Conteúdos do post&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#setting-up-rust-via-rustup&quot;&gt;Configurando Rust utilizando o Rustup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#valuable-tools&quot;&gt;Ferramentas úteis&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#rust-clippy&quot;&gt;rust-clippy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#rustfmt&quot;&gt;rustfmt&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#racer&quot;&gt;racer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#rls&quot;&gt;rls&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fq6uocb9ft&quot;&gt;Configurando o VS Code para código em Rust&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#extension-rust&quot;&gt;Extensão: Rust&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#extension-rls-vscode&quot;&gt;Extensão: rls_vscode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#extension-better-toml&quot;&gt;Extensão: Better TOML&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#extension-lldb-debugger&quot;&gt;Extensão: Depurador LLDB&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fq6uocb9fu&quot;&gt;Como depurar código em Rust&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#on-the-command-line&quot;&gt;Na linha de comando&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#with-vs-code&quot;&gt;No VS Code&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fq6uocb9fv&quot;&gt;Compilando para diferentes alvos (targets)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#closing-thoughts&quot;&gt;Conclusão&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p&gt;Neste artigo eu vou te mostrar uma forma de preparar seu ambiente para desenvolver em Rust. Há formas diferentes, principalmente quando se trata do editor de texto, então sinta-se livre pra pular o que não for relevante pra si. Nós vamos focar em:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Configurar Rust usando o Rustup&lt;/li&gt;
&lt;li&gt;Utilitários como &lt;code&gt;clippy&lt;/code&gt; e &lt;code&gt;rustfmt&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Configurar o VS Code para trabalhar com Rust&lt;/li&gt;
&lt;li&gt;Depurar na linha de comando e no VS Code&lt;/li&gt;
&lt;li&gt;Utilizar diferentes alvos (&lt;em&gt;target&lt;/em&gt;s) de compilação&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Tudo o que eu explico aqui funciona tanto no Linux quanto no MacOS, no Windows pode ser que você precise se adaptar um pouco, já que eu não tenho um sistema Windows para testar este artigo.&lt;/p&gt;
&lt;p&gt;Para executar as instruções deste artigo você precisará do pacote &lt;code&gt;build-essentials&lt;/code&gt; caso utilize Ubuntu ou Debian, &lt;code&gt;base-devel&lt;/code&gt; para a distro Arch ou &lt;code&gt;XCode&lt;/code&gt; para MacOS.&lt;/p&gt;
&lt;h2 id=&quot;setting-up-rust-via-rustup&quot;&gt;Configurando Rust utilizando o Rustup&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://rustup.rs/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Rustup&lt;/a&gt; é um projeto oficial do Rust que nos permite instalar, gerenciar e atualizar várias ferramentas Rust. Para instalar o rustup, rode o seguinte comando:&lt;/p&gt;
&lt;pre class=&quot;language-bash z-code&quot; data-lang=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;curl&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; https://sh.rustup.rs&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;/span&gt;sSf&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-pipe z-shell&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sh&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Depois de baixar, Rustup vai nos fazer algumas perguntas para configurar o ambiente. Vamos apenas aceitar as configurações padrão aqui:&lt;/p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Current installation options:

   default host triple: x86_64-apple-darwin
     default toolchain: stable
  modify PATH variable: yes

1) Proceed with installation (default)
2) Customize installation
3) Cancel installation
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;E logo depois a ferramenta vai nos propor executar o seguinte comando para atualizar o nosso shell:&lt;/p&gt;
&lt;pre class=&quot;language-bash z-code&quot; data-lang=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-support z-function z-source z-shell&quot;&gt;source&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;HOME&lt;/span&gt;&lt;/span&gt;/.cargo/env&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A partir deste momento, podemos executar &lt;code&gt;cargo&lt;/code&gt; e &lt;code&gt;rustc&lt;/code&gt; para confirmar que temos tanto o compilador Rust quanto a ferramenta Cargo instaladas. A ferramenta &lt;code&gt;rustup&lt;/code&gt; também deveria estar instalada agora.&lt;/p&gt;
&lt;p&gt;É recomendado instalar o código fonte do Rust e a documentação também, para que possamos utilizar o modo offline ou para auto completar código.&lt;/p&gt;
&lt;pre class=&quot;language-bash z-code&quot; data-lang=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;rustup&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; component add rust-src&lt;/span&gt;
&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;rustup&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; component add rust-docs&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Em algum momento da vida, nós vamos querer atualizar a nossa instalação. O seguinte comando vai nos ajudar a atualizar as ferramentas e componentes do Rust.&lt;/p&gt;
&lt;pre class=&quot;language-bash z-code&quot; data-lang=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;rustup&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; update&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pode ser também que você encontre algum projeto ou tutorial que utilize a build &lt;em&gt;nightly&lt;/em&gt; (beta) do Rust. Você pode facilmente instalar a versão &lt;em&gt;nightly&lt;/em&gt; juntamente da build principal.&lt;/p&gt;
&lt;pre class=&quot;language-bash z-code&quot; data-lang=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;rustup&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; toolchain install nightly&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Você pode alterar qual o ferramental padrão no seu sistema (entre &lt;em&gt;nightly&lt;/em&gt; e &lt;em&gt;stable&lt;/em&gt;) utilizando os comandos &lt;code&gt;rustup default stable&lt;/code&gt; ou &lt;code&gt;rustup default nightly&lt;/code&gt;, mas a recomendação é manter a build &lt;em&gt;stable&lt;/em&gt; e escrever &lt;em&gt;overrides&lt;/em&gt; para projetos que utilizem a build &lt;em&gt;nightly&lt;/em&gt;. Você pode criar este override navegando até o projeto que quer usar &lt;em&gt;nightly&lt;/em&gt; e rodando o seguinte comando:&lt;/p&gt;
&lt;pre class=&quot;language-bash z-code&quot; data-lang=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;rustup&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; override set nightly&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Por agora isso é tudo o que precisamos saber sobre Rustup.&lt;/p&gt;
&lt;h2 id=&quot;valuable-tools&quot;&gt;Ferramentas úteis&lt;/h2&gt;
&lt;p&gt;Vamos falar sobre quatro ferramentas muito úteis para trabalhar com Rust:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https://github.com/Manishearth/rust-clippy&quot;&gt;&lt;code&gt;rust-clippy&lt;/code&gt;&lt;/a&gt; - Um &lt;em&gt;linter&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https://github.com/rust-lang-nursery/rustfmt&quot;&gt;&lt;code&gt;rustfmt&lt;/code&gt;&lt;/a&gt; - formatador de código.&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https://github.com/phildawes/racer&quot;&gt;&lt;code&gt;racer&lt;/code&gt;&lt;/a&gt; - auto completar código.&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https://github.com/rust-lang-nursery/rls&quot;&gt;&lt;code&gt;rls&lt;/code&gt;&lt;/a&gt; - servidor de linguagem (para usar com VIM, VS Code...)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;rust-clippy&quot;&gt;&lt;code&gt;rust-clippy&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Pra que serve isso?&lt;/strong&gt; O compilador Rust já é bem restritivo. &lt;code&gt;clippy&lt;/code&gt; vai além e nos ajuda a evitar algumas más práticas. Isto pode ajudar a evitar problemas inesperados no nosso código.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;clippy&lt;/code&gt; depende de &lt;em&gt;nightly&lt;/em&gt; para rodar. Nós já instalamos &lt;em&gt;nightly&lt;/em&gt; quando rodamos &lt;code&gt;rustup toolchain install nightly&lt;/code&gt;, então não teremos problema nenhum.&lt;/p&gt;
&lt;p&gt;Vamos instalar o clippy através do &lt;em&gt;nightly&lt;/em&gt; com o seguinte comando:&lt;/p&gt;
&lt;pre class=&quot;language-bash z-code&quot; data-lang=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;cargo&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; +nightly install clippy&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Agora vamos testar a nossa ferramenta. Rode &lt;code&gt;cargo init --bin test &amp;amp;&amp;amp; cd test&lt;/code&gt; e modifique o arquivo &lt;code&gt;src/main.rs&lt;/code&gt; pra que fique com o seguinte conteúdo:&lt;/p&gt;
&lt;pre class=&quot;language-rust z-code&quot; data-lang=&quot;rust&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-rust&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;z-entity z-name z-function z-rust&quot;&gt;main&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; Clippy reclama de statements que não fazem nada,&lt;br&gt;    // como este &quot;true&quot; abandonado
&lt;/span&gt;    &lt;span class=&quot;z-constant z-language z-rust&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Vamos rodar &lt;code&gt;clippy&lt;/code&gt; com o seguinte comando:&lt;/p&gt;
&lt;pre class=&quot;language-bash z-code&quot; data-lang=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;cargo&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; +nightly clippy&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Isto deveria gerar um alerta (&lt;em&gt;warning&lt;/em&gt;) do &lt;code&gt;clippy&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;warning = &quot;statement with no effect&quot;
 --&amp;gt; src/main.rs:2:5
  |
2 |     true;
  |     ^^^^^
  |
  = note: #[warn(no_effect)] on by default
  = help: for further information visit https://github.com/Manishearth/rust-clippy/wiki#no_effect
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Excelente! Você pode ver todas as regras que &lt;code&gt;clippy&lt;/code&gt; consegue detectar &lt;a href=&quot;https://github.com/Manishearth/rust-clippy#lints&quot; target=&quot;_blank&quot; rel=&quot;nofollow ugc noopener noreferrer&quot;&gt;aqui&lt;/a&gt;. Você pode configurar várias regras no arquivo &lt;code&gt;clippy.toml&lt;/code&gt; de acordo com as opções listadas na wiki.&lt;/p&gt;
&lt;p&gt;Para desabilitar algumas regras (ou torná-las avisos em vez de erros) você pode adicionar as flags &lt;code&gt;deny&lt;/code&gt;, &lt;code&gt;warn&lt;/code&gt;, ou &lt;code&gt;allow&lt;/code&gt; nos atributos da sua &lt;em&gt;crate&lt;/em&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-rust z-code&quot; data-lang=&quot;rust&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-annotation z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-annotation z-rust&quot;&gt;#!&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-variable z-annotation z-rust&quot;&gt;cfg_attr&lt;/span&gt;&lt;span class=&quot;z-meta z-annotation z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-annotation z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;feature &lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&quot;&lt;/span&gt;cargo-clippy&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;z-meta z-function-call z-rust&quot;&gt;&lt;span class=&quot;z-variable z-function z-rust&quot;&gt;deny&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function-call z-rust&quot;&gt;empty_enum&lt;/span&gt;&lt;span class=&quot;z-meta z-function-call z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-annotation z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;z-meta z-annotation z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-annotation z-rust&quot;&gt;#!&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-variable z-annotation z-rust&quot;&gt;cfg_attr&lt;/span&gt;&lt;span class=&quot;z-meta z-annotation z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-annotation z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;feature &lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&quot;&lt;/span&gt;cargo-clippy&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;z-meta z-function-call z-rust&quot;&gt;&lt;span class=&quot;z-variable z-function z-rust&quot;&gt;warn&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function-call z-rust&quot;&gt;indexing_slicing&lt;/span&gt;&lt;span class=&quot;z-meta z-function-call z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-annotation z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;z-meta z-annotation z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-annotation z-rust&quot;&gt;#!&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-variable z-annotation z-rust&quot;&gt;cfg_attr&lt;/span&gt;&lt;span class=&quot;z-meta z-annotation z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-annotation z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;feature &lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&quot;&lt;/span&gt;cargo-clippy&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;z-meta z-function-call z-rust&quot;&gt;&lt;span class=&quot;z-variable z-function z-rust&quot;&gt;allow&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function-call z-rust&quot;&gt;print_with_newline&lt;/span&gt;&lt;span class=&quot;z-meta z-function-call z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-annotation z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;rustfmt&quot;&gt;&lt;code&gt;rustfmt&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Pra que serve isso? &lt;/strong&gt;Um estilo consistente, padrão e automatizado no projeto (e entre vários projetos) pode ser útil durante revisões de código, para atrair novas contribuições e evitar discussões supérfluas.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;rustfmt&lt;/code&gt; é uma ferramenta de formatação de código similar ao &lt;code&gt;gofmt&lt;/code&gt;. Ao contrário do &lt;code&gt;clippy&lt;/code&gt;, ela roda sem poblemas com a build &lt;em&gt;stable&lt;/em&gt; do Rust. Vamos instalar o rustfmt:&lt;/p&gt;
&lt;pre class=&quot;language-rust z-code&quot; data-lang=&quot;rust&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;cargo install rustfmt
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A partir daqui podemos rodar &lt;code&gt;cargo fmt&lt;/code&gt; para reformatar o repositório. Este comando roda &lt;code&gt;rustfmt&lt;/code&gt; no modo &lt;em&gt;replace &lt;/em&gt;(substituição) que cria arquivos de backup com a extensão &lt;code&gt;.bk&lt;/code&gt;. Se o projeto utiliza algum tipo de controle de versão (como o Git) você talvez não deseje este comportamento. Neste caso, podemos escrever o seguinte num arquivo &lt;code&gt;rustfmt.toml&lt;/code&gt; para evitar a criação de arquivos &lt;code&gt;.bk&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-toml z-code&quot; data-lang=&quot;toml&quot;&gt;&lt;code class=&quot;language-toml&quot; data-lang=&quot;toml&quot;&gt;&lt;span class=&quot;z-source z-toml&quot;&gt;&lt;span class=&quot;z-meta z-tag z-key z-toml&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-toml&quot;&gt;write_mode&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;z-punctuation z-definition z-key-value z-toml&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;z-string z-quoted z-double z-basic z-toml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-toml&quot;&gt;&quot;&lt;/span&gt;overwrite&lt;span class=&quot;z-punctuation z-definition z-string z-end z-toml&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;O arquivo &lt;code&gt;rustfmt.toml&lt;/code&gt; nos permite configurar várias opções listadas pelo comando &lt;code&gt;rustfmt --config-help&lt;/code&gt;. Agora vamos editar o arquivo &lt;code&gt;main.rs&lt;/code&gt; e bagunçar um pouco o estilo dele:&lt;/p&gt;
&lt;pre class=&quot;language-rust z-code&quot; data-lang=&quot;rust&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-rust&quot;&gt;fn&lt;/span&gt;       &lt;span class=&quot;z-entity z-name z-function z-rust&quot;&gt;main&lt;/span&gt;&lt;/span&gt;    &lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;z-constant z-language z-rust&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Se você rodar &lt;code&gt;cargo fmt&lt;/code&gt; agora vai notar que main.rs está formatado corretamente de novo.&lt;/p&gt;
&lt;p class=&quot;msg msg--info&quot;&gt;&lt;code&gt;rustfmt&lt;/code&gt; ainda não está 100% pronto e pode acontecer de bagunçar o seu código de vez  em quando.&lt;/p&gt;
&lt;h3 id=&quot;racer&quot;&gt;&lt;code&gt;racer&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Pra que serve isso? &lt;/strong&gt;Racer nos ajuda a evitar procurar referências rápidas na documentação e nos ajuda a descobrir novas funcionalidades conforme escrevemos código em Rust.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;racer&lt;/code&gt; é uma ferramenta para autocompletar código que é utilizada por vários add-ons de editores de código juntamente do &lt;code&gt;rls&lt;/code&gt;, que vamos instalar em seguida.&lt;/p&gt;
&lt;p&gt;Anteriormente, nós rodamos &lt;code&gt;rustup component add rust-src&lt;/code&gt;. Este foi o primeiro passo para instalar o racer. Vamos agora instalar a ferramenta em si:&lt;/p&gt;
&lt;pre class=&quot;language-bash z-code&quot; data-lang=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;cargo&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; install racer&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nós precisamos definir uma variável de ambiente para que &lt;code&gt;racer&lt;/code&gt; saiba onde buscar o código fonte do Rust. No seu &lt;code&gt;~/.bashrc&lt;/code&gt; (ou &lt;code&gt;~/.zshrc&lt;/code&gt;) adicione o seguinte:&lt;/p&gt;
&lt;pre class=&quot;language-bash z-code&quot; data-lang=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; Mac&lt;/span&gt;
&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-shell&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;RUST_SRC_PATH&lt;/span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-expansion z-parameter z-begin z-shell&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;HOME&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-expansion z-parameter z-end z-shell&quot;&gt;}&lt;/span&gt;&lt;/span&gt;/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/src/rust/src&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;&lt;br&gt;#&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; Linux&lt;/span&gt;
&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-shell&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;RUST_SRC_PATH&lt;/span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-expansion z-parameter z-begin z-shell&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;HOME&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-expansion z-parameter z-end z-shell&quot;&gt;}&lt;/span&gt;&lt;/span&gt;/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Se você não usa MacOS ou Linux, vai precisar precisar definir a variável de ambiente de acordo com o que é mostrado pelo comando &lt;code&gt;rustup show&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Você pode testar se &lt;code&gt;racer&lt;/code&gt; está funcionando com o seguinte comando:&lt;/p&gt;
&lt;pre class=&quot;language-bash z-code&quot; data-lang=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;racer&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; complete std::io::B&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Você deveria ver várias sugestões para o comando acima. A partir de agora, &lt;code&gt;racer&lt;/code&gt; já está preparado para ser utilizado pelo seu editor de texto ou com o &lt;code&gt;rls&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;rls&quot;&gt;&lt;code&gt;rls&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Pra que serve isso? &lt;/strong&gt;Para criar uma experiência de desenvolvimento mais agradável e ampliar as funcionalidades do &lt;code&gt;racer&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;rls&lt;/code&gt; é um &lt;a href=&quot;http://langserver.org/&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;servidor de linguagem (&lt;em&gt;language server&lt;/em&gt;)&lt;/a&gt; especializado em Rust. Ele traz consigo funcionalidades como auto completar código, &lt;em&gt;ir-para&lt;/em&gt; definições e refatorações.&lt;/p&gt;
&lt;p&gt;Para instalar &lt;code&gt;rls&lt;/code&gt; nós precisamos dizer ao Rustup para utilizar uma &lt;em&gt;toolchain&lt;/em&gt; específica. MacOS utiliza a &lt;code&gt;nightly-x86_64-apple-darwin&lt;/code&gt; e Linux utiliza a &lt;code&gt;nightly-x86_64-unknown-linux-gnu&lt;/code&gt;. Se você não usa VS Code, pode pular este passo.&lt;/p&gt;
&lt;pre class=&quot;language-bash z-code&quot; data-lang=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;rustup&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; component add rls&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;/span&gt;toolchain&lt;/span&gt; nightly-x86_64-apple-darwin&lt;/span&gt;
&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;rustup&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; component add rust-analysis&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;/span&gt;toolchain&lt;/span&gt; nightly-x86_64-apple-darwin&lt;/span&gt;
&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;rustup&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; component add rust-src&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;/span&gt;toolchain&lt;/span&gt; nightly-x86_64-apple-darwin&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Em seguida, precisamos definir outras duas variáveis de ambiente: &lt;code&gt;DYLD_LIBRARY_PATH&lt;/code&gt; e &lt;code&gt;RLS_ROOT&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-bash z-code&quot; data-lang=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; Mac&lt;/span&gt;
&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-shell&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;DYLD_LIBRARY_PATH&lt;/span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-expansion z-parameter z-begin z-shell&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;HOME&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-expansion z-parameter z-end z-shell&quot;&gt;}&lt;/span&gt;&lt;/span&gt;/.rustup/toolchains/stable-x86_64-apple-darwin/lib&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-shell&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;RLS_ROOT&lt;/span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-expansion z-parameter z-begin z-shell&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;HOME&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-expansion z-parameter z-end z-shell&quot;&gt;}&lt;/span&gt;&lt;/span&gt;/git/rust/rls&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;&lt;br&gt;#&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; Linux&lt;/span&gt;
&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-shell&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;DYLD_LIBRARY_PATH&lt;/span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-expansion z-parameter z-begin z-shell&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;HOME&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-expansion z-parameter z-end z-shell&quot;&gt;}&lt;/span&gt;&lt;/span&gt;/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-shell&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;RLS_ROOT&lt;/span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-expansion z-parameter z-begin z-shell&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;HOME&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-expansion z-parameter z-end z-shell&quot;&gt;}&lt;/span&gt;&lt;/span&gt;/git/rust/rls&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Agora estamos prontos! Nós vamos testar e usar o rls mais tarde, quando configurarmos o VS Code.&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1fq6uocb9ft&quot;&gt;Configurando o VS Code para código em Rust&lt;/h2&gt;
&lt;p&gt;Eu usei o VS Code para Rust por vários meses e achei bem delicinha. Como qualquer editor de textos, há várias configurações a serem ajustadas. Vamos focar nas mais relevantes.&lt;/p&gt;
&lt;p class=&quot;msg msg--highlight &quot;&gt;Você pode usar outro editor, e tá tudo bem. Vai em frente! Eu ainda uso o &lt;code&gt;vim&lt;/code&gt; para editar coisas rápidas e alguns colegas meus gostam bastante de seus &lt;code&gt;emacs&lt;/code&gt;. Diversidade faz bem, use o que é bom pra ti e deixe os outros usarem o que for melhor para eles.&lt;/p&gt;
&lt;p&gt;Primeiro, vamos baixar o VS Code. Basta entrar no &lt;a href=&quot;https://code.visualstudio.com/&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;site oficial&lt;/a&gt; e baixar o instalador.&lt;/p&gt;
&lt;p&gt;Para poder rodar o comando &lt;code&gt;code&lt;/code&gt; na CLI nós precisamos abrir o VS Code e abrir a paleta de comandos (&lt;em&gt;Command Palette&lt;/em&gt;) com o atalho &lt;code&gt;Shift + Command + P&lt;/code&gt; (MacOS) ou &lt;code&gt;Shift + Control + P&lt;/code&gt; (&lt;em&gt;Linux&lt;/em&gt;). Aqui, escreva &lt;code&gt;shell command&lt;/code&gt; e procure pela opção &lt;code&gt;Shell Command: Install &apos;code&apos; command in PATH&lt;/code&gt;. Após selecionar esta opção, qualquer nova sessão de terminal deverá ter o comando &lt;code&gt;code&lt;/code&gt; preparado.&lt;/p&gt;
&lt;h3 id=&quot;extension-rust&quot;&gt;Extensão: Rust&lt;/h3&gt;
&lt;p&gt;A extensão &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=rust-lang.rust&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;&lt;em&gt;Rust&lt;/em&gt;&lt;/a&gt; traz alguns utilitários para fazer o &lt;em&gt;build&lt;/em&gt;, formatar código e outras coisas úteis.&lt;/p&gt;
&lt;h3 id=&quot;extension-rls-vscode&quot;&gt;Extensão: &lt;code&gt;rls_vscode&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Nós vamos precisar do &lt;code&gt;node&lt;/code&gt; instalado, você pode utilizar seu gerenciador de pacotes para isso. No MacOS, &lt;code&gt;brew&lt;/code&gt; já resolve o problema.&lt;/p&gt;
&lt;p&gt;Com o node já instalado, vamos instalar a extensão &lt;code&gt;rls_vscode&lt;/code&gt;. Mas já que esta extensão ainda não foi lançada, nós vamos precisar fazer um pouco de trabalho manual. Vamos clonar e instalar as dependências do repositório rls_vscode;&lt;/p&gt;
&lt;pre class=&quot;language-bash z-code&quot; data-lang=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;git&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; clone https://github.com/jonathandturner/rls_vscode.git&lt;/span&gt;
&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-support z-function z-cd z-shell&quot;&gt;cd&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; rls_vscode&lt;/span&gt;
&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;npm&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; install&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;O próximo passo é fazer o &lt;em&gt;build&lt;/em&gt; da extensão, que podemos fazer diretamente utilizando o VS Code. Rode o comando &lt;code&gt;code .&lt;/code&gt; dentro do repositório que acabamos de clonar para abrir o VS Code naquele diretório. Já dentro do VS Code, aperte o botão de &lt;em&gt;Build&lt;/em&gt; perto da opção &lt;em&gt;Launch Extension&lt;/em&gt; no painel da esquerda. Uma nova janela do VS Code vai abrir, mas você pode fechá-la imediatamente.&lt;/p&gt;
&lt;p&gt;Agora que nós compilamos a extensão, vamos criar um link simbólico (&lt;em&gt;symlink&lt;/em&gt;) para instalar no VS Code. Se você estiver usando o VS Code Insiders, o diretório é &lt;code&gt;.vscode-insiders&lt;/code&gt; em vez de &lt;code&gt;.vscode&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-bash z-code&quot; data-lang=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;ln&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;/span&gt;s&lt;/span&gt; &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-expansion z-parameter z-begin z-shell&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;HOME&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-expansion z-parameter z-end z-shell&quot;&gt;}&lt;/span&gt;&lt;/span&gt;/git/rust/rls_vscode/ &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-expansion z-parameter z-begin z-shell&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;HOME&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-expansion z-parameter z-end z-shell&quot;&gt;}&lt;/span&gt;&lt;/span&gt;/.vscode/extensions/rls_vscode&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Depois você pode atualizar a extensão com utilizando um processo parecido. É recomendado atualizar a extensão com frequência porque várias atualizações estão sendo lançadas.&lt;/p&gt;
&lt;p&gt;Agora pode fechar e abrir o VS Code de novo. Ao abrir qualquer projeto Rust você deverá ver uma barra azul na parte de baixo da tela dizendo &quot;RLS analysis: Starting up&quot; e, alguns minutos depois, &quot;RLS analysis: Done&quot;.&lt;/p&gt;
&lt;p class=&quot;msg msg--info&quot;&gt;Se você reiniciar a sua máquina você vai precisar abrir um terminal antes de abrir o VS Code, ou usar o terminal integrado do VS Code e logo após reiniciar o programa. Há algumas formas de corrigir isto, mas dá muito trabalho. Talvez num futuro próximo a gente veja alguma configuração do VS Code que melhore esta situação.&lt;/p&gt;
&lt;h3 id=&quot;extension-better-toml&quot;&gt;Extensão: Better TOML&lt;/h3&gt;
&lt;p&gt;O ecossistema Rust usa bastante arquivos TOML para gerenciar configuração. A extensão &apos;&lt;em&gt;Rusty code&lt;/em&gt;&apos; já traz algum suporte ao formato TOML, mas a extensão &apos;&lt;em&gt;Better TOML&lt;/em&gt;&apos; é bem melhor e vale a pena ter no seu VS Code.&lt;/p&gt;
&lt;h3 id=&quot;extension-lldb-debugger&quot;&gt;Extensão: Depurador LLDB&lt;/h3&gt;
&lt;p&gt;A extensão &apos;&lt;em&gt;LLDB Debugger&apos;&lt;/em&gt; (Low Level Debugger Debugger) nos permite depurar aplicações Rust dentro do VS Code. Você vai precisar também da biblioteca &lt;code&gt;six&lt;/code&gt; do Python, que você pode instalar com o comando &lt;code&gt;pip install six&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1fq6uocb9fu&quot;&gt;Como depurar código em Rust&lt;/h2&gt;
&lt;p&gt;Vamos criar uma aplicação basiquinha pra testar como a depuração funciona antes de fazer qualquer teste mais complicado. Rode o comando &lt;code&gt;cargo init --bin example&lt;/code&gt; e coloque o seguinte conteúdo no arquivo &lt;code&gt;src/main.rs&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-rust z-code&quot; data-lang=&quot;rust&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-enum z-rust&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-rust&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;z-storage z-type z-enum z-rust&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;z-entity z-name z-enum z-rust&quot;&gt;Direction&lt;/span&gt; &lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;/span&gt; North&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; South&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; East&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; West &lt;/span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-rust&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;z-storage z-type z-function z-rust&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;z-entity z-name z-function z-rust&quot;&gt;is_north&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-variable z-parameter z-rust&quot;&gt;dir&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;:&lt;/span&gt; Direction&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt; &lt;span class=&quot;z-meta z-function z-return-type z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;bool&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;z-keyword z-control z-rust&quot;&gt;match&lt;/span&gt; dir &lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;z-meta z-path z-rust&quot;&gt;Direction&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;North &lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;z-constant z-language z-rust&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;z-constant z-language z-rust&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-rust&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;z-entity z-name z-function z-rust&quot;&gt;main&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; two &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-keyword z-operator z-arithmetic z-rust&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-support z-macro z-rust&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;z-constant z-other z-placeholder z-rust&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; two&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; points &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;z-meta z-path z-rust&quot;&gt;Direction&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;South&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; compass &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;z-support z-function z-rust&quot;&gt;is_north&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;points&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-support z-macro z-rust&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;z-constant z-other z-placeholder z-rust&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; compass&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Com isso a gente já consegue praticar a depuração. Bora debugar!&lt;/p&gt;
&lt;h3 id=&quot;on-the-command-line&quot;&gt;Na linha de comando&lt;/h3&gt;
&lt;p&gt;Antes de qualquer coisa, a gente precisa rodar o debugger. Vamos primeiro compilar com &lt;code&gt;cargo build&lt;/code&gt; e depois rodar o nosso programa através do depurador &lt;code&gt;rust-lldb&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-bash z-code&quot; data-lang=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;cargo&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; build&lt;/span&gt;
&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;rust-lldb&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; ./target/debug/example&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Daí em diante a gente pode interagir com o depurador como normalmente faríamos usando o LLDB. Ah, sim, também existe a alternativa &lt;code&gt;rust-gdb&lt;/code&gt; se você quiser se aventurar.&lt;/p&gt;
&lt;p&gt;Por exemplo:&lt;/p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;(lldb) breakpoint set -f main.rs -l 3
Breakpoint 1: where = example`example::is_north + 10 at main.rs:3, address = 0x0000000100000ffa
(lldb) process launch
Process 8376 launched: &apos;/Users/hoverbear/git/rust/example/target/debug/example&apos; (x86_64)
2
Process 8376 stopped
* thread #1: tid = 0x2c222, 0x0000000100000ffa example`example::is_north(dir=South) + 10 at main.rs:3, queue = &apos;com.apple.main-thread&apos;, stop reason = breakpoint 1.1
    frame #0: 0x0000000100000ffa example`example::is_north(dir=South) + 10 at main.rs:3
   1   	pub enum Direction { North, South, East, West }
   2
-&amp;gt; 3   	fn is_north(dir: Direction) -&amp;gt; bool {
   4   	    match dir {
   5   	        Direction::North =&amp;gt; true,
   6   	        _ =&amp;gt; false,
   7   	    }
(lldb) print dir
(example::Direction) $0 = South
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;with-vs-code&quot;&gt;No VS Code&lt;/h3&gt;
&lt;p&gt;Depois de instalar a extensão &lt;em&gt;&apos;LLDB Debugger&lt;/em&gt;&apos; você pode definir um &lt;em&gt;breakpoint&lt;/em&gt; ao clicar à esquerda dos números de linha, você deverá ver um ponto vermelho indicando que colocou um &lt;em&gt;breakpoint&lt;/em&gt;. Mas para depurar mesmo a aplicação, a gente precisa configurar o VS Code direito.&lt;/p&gt;
&lt;p&gt;Adicione o seguinte no arquivo &lt;code&gt;.vscode/launch.json&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-json z-code&quot; data-lang=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-begin z-json&quot;&gt;{&lt;/span&gt;
    &lt;/span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&quot;&lt;/span&gt;version&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&quot;&lt;/span&gt;0.2.0&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;/span&gt;
    &lt;/span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&quot;&lt;/span&gt;configurations&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-sequence z-begin z-json&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-begin z-json&quot;&gt;{&lt;/span&gt;
            &lt;/span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&quot;&lt;/span&gt;type&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&quot;&lt;/span&gt;lldb&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&quot;&lt;/span&gt;request&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&quot;&lt;/span&gt;launch&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&quot;&lt;/span&gt;name&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&quot;&lt;/span&gt;Debug&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&quot;&lt;/span&gt;program&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&quot;&lt;/span&gt;${workspaceRoot}/target/debug/example&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&quot;&lt;/span&gt;args&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;z-punctuation z-section z-sequence z-begin z-json&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-sequence z-end z-json&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&quot;&lt;/span&gt;cwd&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&quot;&lt;/span&gt;${workspaceRoot}&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&quot;&lt;/span&gt;preLaunchTask&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&quot;&lt;/span&gt;cargo&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&quot;&lt;/span&gt;sourceLanguages&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;z-punctuation z-section z-sequence z-begin z-json&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&quot;&lt;/span&gt;rust&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-sequence z-end z-json&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;z-punctuation z-section z-mapping z-end z-json&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;z-punctuation z-section z-sequence z-end z-json&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;z-punctuation z-section z-mapping z-end z-json&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;E depois adicione um arquivo &lt;code&gt;.vscode/tasks.json&lt;/code&gt; com o seguinte conteúdo:&lt;/p&gt;
&lt;pre class=&quot;language-json z-code&quot; data-lang=&quot;json&quot;&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-begin z-json&quot;&gt;{&lt;/span&gt;
    &lt;/span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&quot;&lt;/span&gt;version&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&quot;&lt;/span&gt;0.1.0&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;/span&gt;
    &lt;/span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&quot;&lt;/span&gt;command&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&quot;&lt;/span&gt;cargo&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;/span&gt;
    &lt;/span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&quot;&lt;/span&gt;isShellCommand&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;/span&gt;
    &lt;/span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&quot;&lt;/span&gt;args&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-sequence z-begin z-json&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&quot;&lt;/span&gt;build&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-sequence z-end z-json&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;/span&gt;
    &lt;/span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&quot;&lt;/span&gt;showOutput&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&quot;&lt;/span&gt;always&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;z-punctuation z-section z-mapping z-end z-json&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Depois, vamos colocar um &lt;em&gt;breakpoint&lt;/em&gt; no código. Daí é só clicar no ícone do insetinho (quarto ícone de cima para baixo, no painel esquerdo) e apertar o botão &lt;em&gt;Play&lt;/em&gt;. Você deverá ver algo assim:&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/26/rust-debugger-vs-code.png&quot; alt=&quot;Depurador do VS Code, depurando um código Rust.&quot; width=&quot;1920&quot; height=&quot;1200&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Depurador do VS Code, depurando um código Rust.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;mcetoc_1fq6uocb9fv&quot;&gt;Compilando para diferentes alvos (&lt;em&gt;targets&lt;/em&gt;)&lt;/h2&gt;
&lt;p&gt;Até aqui a gente só compilou programas para a arquitetura &lt;code&gt;x86_64-apple-darwin&lt;/code&gt;. Se estivéssemos usando Linux, nós teríamos compilado para &lt;code&gt;x86_64-unknown-linux-gnu&lt;/code&gt;. Vamos mudar um pouquinho e compilar para javascript: &lt;code&gt;asmjs-unknown-emscripten&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Primeiro, precisamos instalar o pacote &lt;code&gt;emscripten&lt;/code&gt;. No Mac você pode fazer isso com &lt;code&gt;brew install emscripten&lt;/code&gt;. Algumas distros Linux também oferecem o pacote &lt;code&gt;emscripten&lt;/code&gt;, mas você pode encontrar um manual de instalação &lt;a href=&quot;https://emscripten.org/docs/getting_started/downloads.html&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;aqui&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Depois, vamos instalar o alvo (&lt;em&gt;target&lt;/em&gt;) usando o &lt;code&gt;rustup&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-bash z-code&quot; data-lang=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;rustup&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; target add asmjs-unknown-emscripten&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Se você estiver usando Mac, provavelmente vai precisar adicionar as seguintes linhas no arquivo &lt;code&gt;~/.emscripten&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-bash z-code&quot; data-lang=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;LLVM_ROOT&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; = &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&quot;&lt;/span&gt;/usr/local/opt/emscripten/libexec/llvm/bin&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;LLVM_ROOT = os.path.expanduser(os.getenv(&apos;LLVM&apos;) or &apos;/usr/bin&apos;) # directory&lt;/span&gt;
&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;BINARYEN_ROOT = os.path.expanduser(os.getenv(&apos;BINARYEN&apos;) or &apos;/usr/bin&apos;) # directory&lt;/span&gt;

&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; Avoid annoying popups about Java.&lt;/span&gt;
&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;JAVA = &apos;java&apos;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Agora nós já podemos compilar o nosso código em asm.js e rodar direto com o interpretador node:&lt;/p&gt;
&lt;pre class=&quot;language-bash z-code&quot; data-lang=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;cargo&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; build&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;/span&gt;target&lt;/span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-option z-shell&quot;&gt;=&lt;/span&gt;asmjs-unknown-emscripten&lt;/span&gt;
&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;node&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; target/asmjs-unknown-emscripten/debug/example.js&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A saída deverá ser a seguinte:&lt;/p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;2
false
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Compilar para outros sistemas e arquiteturas funciona de forma semelhante. A parte mais chatinha é instalar o ferramental, como nós acabamos de fazer para o &lt;code&gt;emscripten&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;closing-thoughts&quot;&gt;Conclusão&lt;/h2&gt;
&lt;p&gt;Agora nós já temos um ambiente de desenvolvimento Rust preparado para compilar programas tanto na arquitetura do computador local, quanto para asm.js. O editor VS Code está preparado para depurar código e tem algumas funcionalidades bacanudas como autocompletar e navegar no código. Além disso, instalamos algumas ferramentas utilíssimas como o &lt;code&gt;clippy&lt;/code&gt; para nos ajudar a detectar erros.&lt;/p&gt;
&lt;p&gt;Algumas das ferramentas que instalamos ainda estão em alpha, ou não funcionam como gostaríamos. Mas este é só o começo! E se você tiver interesse, pode sempre contribuir com estes projetos. De tempos em tempos você pode atualizar a sua caixa de ferramentas e com certeza vai notar várias melhorias.&lt;/p&gt;
&lt;p&gt;Agora você não tem nenhuma desculpa pra não se divertir programando em Rust! Vai procurar um repositório interessante e faz seu primeiro Pull Request! E se não achar nada, dá uma olhada no &lt;a href=&quot;https://www.reddit.com/r/rust/&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;r/rust&lt;/a&gt; pra sacar sobre quais projetos as pessoas estão conversando, procure por issues marcadas como &lt;code&gt;E - Easy&lt;/code&gt; no &lt;code&gt;rustc&lt;/code&gt;, ou pegue pra desenvolver algo pequeno no projeto &lt;code&gt;rust-rosetta&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now, we don&apos;t have any excuses &lt;em&gt;not&lt;/em&gt; to have fun with Rust! Why not find something that looks interesting and try to make your first PR? Can&apos;t find something? Check out &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https://www.reddit.com/r/rust/&quot;&gt;/r/rust&lt;/a&gt; and look at the projects people are talking about, look at the &lt;code&gt;E - Easy&lt;/code&gt; issues on &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https://github.com/rust-lang/rust/labels/E-easy&quot;&gt;&lt;code&gt;rustc&lt;/code&gt;&lt;/a&gt;, or tackle something small from &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https://github.com/Hoverbear/rust-rosetta&quot;&gt;&lt;code&gt;rust-rosetta&lt;/code&gt;&lt;/a&gt;!&lt;/p&gt;
&lt;p class=&quot;msg msg--highlight &quot;&gt;Obrigado &lt;a href=&quot;http://asquera.de/&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;Asquera&lt;/a&gt;, por me arranjar tempo para escrever este artigo! O mesmo texto também está presente &lt;a href=&quot;http://asquera.de/blog/2017-03-03/setting-up-a-rust-devenv/&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;aqui.&lt;/a&gt;&lt;/p&gt;</content:encoded><category>gringo</category><category>rust</category></item><item><title>Uma jornada rumo aos iterators</title><link>https://codamos.com.br/basico-sobre-iterators-rust/</link><guid isPermaLink="true">https://codamos.com.br/basico-sobre-iterators-rust/</guid><description>Atenção: este texto foi traduzido, editado e adaptado por @nawarian . Você encontra o texto original, escrito em 2015 em inglês, no blog parceiro Hoverbear.org através deste link . Uma das minhas func</description><pubDate>Tue, 11 Jan 2022 13:09:10 GMT</pubDate><content:encoded>&lt;p class=&quot;msg msg--info&quot;&gt;&lt;strong data-renderer-mark=&quot;true&quot;&gt;Atenção:&lt;/strong&gt; este texto foi traduzido, editado e adaptado por &lt;a class=&quot;sc-gGBfsJ ezSIMS&quot; href=&quot;https://twitter.com/nawarian&quot; title=&quot;https://twitter.com/nawarian&quot; data-renderer-mark=&quot;true&quot; rel=&quot;nofollow&quot;&gt;@nawarian&lt;/a&gt;. Você encontra o texto original, escrito em 2015 em inglês, no blog parceiro Hoverbear.org através &lt;a href=&quot;https://hoverbear.org/blog/a-journey-into-iterators/&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;deste link&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Uma das minhas funcionalidades favoritas em Rust são os &lt;em&gt;iterators&lt;/em&gt;. Eles são uma forma rápida, segura e preguiçosa (&lt;em&gt;lazy&lt;/em&gt;) de trabalhar com estruturas de dados, &lt;em&gt;streams&lt;/em&gt; e outras aplicações mais criativas.&lt;/p&gt;
&lt;p class=&quot;msg msg--highlight &quot;&gt;Você pode brincar com iterators utilizando o website &lt;a href=&quot;http://play.rust-lang.org/&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;http://play.rust-lang.org/&lt;/a&gt; enquanto navega &lt;a href=&quot;http://doc.rust-lang.org/core/iter/index.html&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;aqui&lt;/a&gt;. Este artigo não substitui a documentação oficial ou a experiência de executar os códigos por si.&lt;/p&gt;
&lt;h2 id=&quot;our-first-iterator&quot;&gt;Nosso primeiro &lt;em&gt;iterator&lt;/em&gt;&lt;/h2&gt;
&lt;p&gt;Um é pouco, mas dois é bom. Vamos pegar uma lista de valores e dobrá-los!&lt;/p&gt;
&lt;pre class=&quot;language-rust z-code&quot; data-lang=&quot;rust&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-rust&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;z-entity z-name z-function z-rust&quot;&gt;main&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; Primeiro temos uma lista de valores
&lt;/span&gt;    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; entrada &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; Crie um iterator sobre estes valores
&lt;/span&gt;    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; iterator &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; input&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;iter&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; Especifique o que fazer ao iterar
&lt;/span&gt;    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; mapeado &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; iterator&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-variable z-parameter z-rust&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;x &lt;span class=&quot;z-keyword z-operator z-arithmetic z-rust&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; Faça alguma coisa com a saída
&lt;/span&gt;    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; saida &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; mapped&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;collect&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-generic z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-begin z-rust&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-support z-type z-rust&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-begin z-rust&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-storage z-type z-rust&quot;&gt;usize&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-end z-rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-end z-rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-support z-macro z-rust&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;z-constant z-other z-placeholder z-rust&quot;&gt;{:?}&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; saida&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Já neste exemplo simples, podemos observar algumas coisas interessantes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.iter()&lt;/code&gt; pode ser usado com vários tipos diferentes.&lt;/li&gt;
&lt;li&gt;Precisamos declarar um valor &lt;strong&gt;e só depois&lt;/strong&gt; criar um iterator para ele. Do contrário o valor não vai viver o suficiente para ser iterado. (Iterators são preguiçosos (&lt;em&gt;lazy&lt;/em&gt;) e nem sempre são donos de seus valores).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.collect::&amp;lt;Vec&amp;lt;usize&amp;gt;&amp;gt;()&lt;/code&gt; itera a lista completamente e guarda seus valores num tipo de coleção que especificarmos. (Se você quiser escrever a sua própria estrutura de dados, dá uma olhada &lt;a rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot; href=&quot;http://doc.rust-lang.org/std/iter/trait.FromIterator.html#tymethod.from_iter&quot;&gt;aqui&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Um &lt;em&gt;iterator&lt;/em&gt; pode ser utilizado e encadeado! Você não precisa necessariamente chamar &lt;code&gt;.collect()&lt;/code&gt; depois de uma chamada ao &lt;code&gt;.map()&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;n-at-a-time&quot;&gt;&lt;code&gt;n&lt;/code&gt; de cada vez&lt;/h2&gt;
&lt;p&gt;Você pode acessar o próximo elemento de um &lt;em&gt;iterator&lt;/em&gt; com &lt;code&gt;.next()&lt;/code&gt;. Se você quiser pegar somente uma porção, pode utilizar &lt;code&gt;.take(n)&lt;/code&gt; para criar um novo &lt;em&gt;iterator&lt;/em&gt; que percorre os próximos &lt;code&gt;n&lt;/code&gt; elementos.&lt;/p&gt;
&lt;p&gt;Quer jogar fora alguns dados? Use &lt;code&gt;.skip(n)&lt;/code&gt; para pular &lt;code&gt;n&lt;/code&gt; elementos.&lt;/p&gt;
&lt;pre class=&quot;language-rust z-code&quot; data-lang=&quot;rust&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-rust&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;z-entity z-name z-function z-rust&quot;&gt;main&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; valores &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;z-storage z-modifier z-rust&quot;&gt;mut&lt;/span&gt; iter &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; valores&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;iter&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-support z-macro z-rust&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;z-constant z-other z-placeholder z-rust&quot;&gt;{:?}&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; iter&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-support z-macro z-rust&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;z-constant z-other z-placeholder z-rust&quot;&gt;{:?}&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; iter&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;skip&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;take&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;collect&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-generic z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-begin z-rust&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-support z-type z-rust&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-begin z-rust&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-end z-rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-end z-rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; Saída:
&lt;/span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; Some(1)
&lt;/span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; [4, 5]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;observing-laziness&quot;&gt;Observando o comportamento preguiçoso (&lt;em&gt;lazy&lt;/em&gt;)&lt;/h2&gt;
&lt;p&gt;Eu comentei que &lt;em&gt;iterators&lt;/em&gt; são preguiçosos, mas o primeiro exemplo não demonstrou este comportamento. Vamos utilizar &lt;code&gt;.inspect()&lt;/code&gt; para observar como Rust se comporta.&lt;/p&gt;
&lt;pre class=&quot;language-rust z-code&quot; data-lang=&quot;rust&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-rust&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;z-entity z-name z-function z-rust&quot;&gt;main&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; entrada &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; iterator &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; input&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;iter&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; mapeado &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; iterator
        &lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;inspect&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-variable z-parameter z-rust&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-support z-macro z-rust&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&quot;&lt;/span&gt;Antes do map:&lt;span class=&quot;z-constant z-character z-escape z-rust&quot;&gt;\t&lt;/span&gt;&lt;span class=&quot;z-constant z-other z-placeholder z-rust&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; x&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-variable z-parameter z-rust&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;x &lt;span class=&quot;z-keyword z-operator z-arithmetic z-rust&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;10&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; Isto vai ser entrada...
&lt;/span&gt;        &lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;inspect&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-variable z-parameter z-rust&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-support z-macro z-rust&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&quot;&lt;/span&gt;Primeiro map:&lt;span class=&quot;z-constant z-character z-escape z-rust&quot;&gt;\t&lt;/span&gt;&lt;span class=&quot;z-constant z-other z-placeholder z-rust&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; x&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-rust&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;x &lt;span class=&quot;z-keyword z-operator z-arithmetic z-rust&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;5&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;   &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; ... disto.
&lt;/span&gt;        &lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;inspect&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-variable z-parameter z-rust&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-support z-macro z-rust&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&quot;&lt;/span&gt;Segundo map:&lt;span class=&quot;z-constant z-character z-escape z-rust&quot;&gt;\t&lt;/span&gt;&lt;span class=&quot;z-constant z-other z-placeholder z-rust&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; x&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    mapeado&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;collect&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-generic z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-begin z-rust&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-support z-type z-rust&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-begin z-rust&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-storage z-type z-rust&quot;&gt;usize&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-end z-rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-end z-rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A saída é:&lt;/p&gt;
&lt;pre class=&quot;language-rust z-code&quot; data-lang=&quot;rust&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;Antes do map&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;:&lt;/span&gt;    &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;1&lt;/span&gt;
Primeiro map&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;10&lt;/span&gt;
Segundo map&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;15&lt;/span&gt;
Antes do map&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;:&lt;/span&gt;    &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;2&lt;/span&gt;
Primeiro map&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;20&lt;/span&gt;
Segundo map&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;25&lt;/span&gt;
Antes do map&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;:&lt;/span&gt;    &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;3&lt;/span&gt;
Primeiro map&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;30&lt;/span&gt;
Segundo map&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;35&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Como você pôde perceber, as funções &lt;em&gt;map&lt;/em&gt; apenas executam quando o &lt;em&gt;iterator &lt;/em&gt;avança. (Do contrário nós veríamos &lt;code&gt;1&lt;/code&gt;, &lt;code&gt;2&lt;/code&gt;, &lt;code&gt;3&lt;/code&gt;, &lt;code&gt;10&lt;/code&gt;, ...)&lt;/p&gt;
&lt;p class=&quot;msg msg--highlight &quot;&gt;Note como &lt;code&gt;.inspect()&lt;/code&gt; passa para seu &lt;em&gt;callback&lt;/em&gt; um &lt;code&gt;&amp;amp;x&lt;/code&gt; em vez de &lt;code&gt;&amp;amp;mut&lt;/code&gt; ou o valor em si. Isto evita mutações e assegura que sua inspeção não vai bagunçar a pipeline de dados.&lt;/p&gt;
&lt;p&gt;Isto gera uns efeitos colaterais bem bacanas como, por exemplo,&lt;em&gt; iterators&lt;/em&gt; infinitos ou cíclicos.&lt;/p&gt;
&lt;pre class=&quot;language-rust z-code&quot; data-lang=&quot;rust&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-rust&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;z-entity z-name z-function z-rust&quot;&gt;main&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; entrada &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; Diz ao &lt;em&gt;iterator&lt;/em&gt; para realizar ciclos em si mesmo
&lt;/span&gt;    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; ciclico &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; entrada&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;iter&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;cycle&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; saida &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; ciclico&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;take&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;9&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;collect&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-generic z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-begin z-rust&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-support z-type z-rust&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-begin z-rust&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-storage z-type z-rust&quot;&gt;usize&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-end z-rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-end z-rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-support z-macro z-rust&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;z-constant z-other z-placeholder z-rust&quot;&gt;{:?}&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; saida&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; Saída [1, 2, 3, 1, 2, 3, 1, 2, 3]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;something-in-common&quot;&gt;Algo em comum&lt;/h2&gt;
&lt;p&gt;Não fique aí achando que &lt;code&gt;[1, 2, 3]&lt;/code&gt; e outros &lt;em&gt;slices&lt;/em&gt; são as únicas coisas das quais você pode criar &lt;em&gt;iterators&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Muitas estruturas de dados dão implementam esta &lt;em&gt;trait&lt;/em&gt;: podemos utilizar &lt;em&gt;Vectors&lt;/em&gt; e &lt;em&gt;DecDeques&lt;/em&gt;! Vejamos algumas coisas que implementam &lt;code&gt;.iter()&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-rust z-code&quot; data-lang=&quot;rust&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-keyword z-other z-rust&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;z-meta z-path z-rust&quot;&gt;std&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;collections&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;VecDeque&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-rust&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;z-entity z-name z-function z-rust&quot;&gt;main&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; Crie um Vector de valores
&lt;/span&gt;    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; entrada &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;z-support z-macro z-rust&quot;&gt;vec!&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; iterator &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; entrada&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;iter&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; mapeado &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; iterator&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-variable z-parameter z-rust&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;z-keyword z-control z-rust&quot;&gt;return&lt;/span&gt; x &lt;span class=&quot;z-keyword z-operator z-arithmetic z-rust&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; Coletar o resultado num &lt;em&gt;RingBuf&lt;/em&gt;.
&lt;/span&gt;    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;z-meta z-group z-rust&quot;&gt;saida&lt;/span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; mapeado&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;collect&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-generic z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-begin z-rust&quot;&gt;&amp;lt;&lt;/span&gt;VecDeque&lt;span class=&quot;z-punctuation z-definition z-generic z-begin z-rust&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-end z-rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-end z-rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-support z-macro z-rust&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;z-constant z-other z-placeholder z-rust&quot;&gt;{:?}&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; saida&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; Saída [2, 4, 6]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Viu como fizemos o &lt;em&gt;collect&lt;/em&gt; num &lt;em&gt;VecDeque&lt;/em&gt;? Isto só é possível porque ele implementa &lt;code&gt;FromIterator&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Você deve estar pensando &lt;em&gt;&quot;Ah rá! Aposto que você não consegue usar um HashMap ou uma árvore ou coisa do tipo, Hoverbear!&quot;&lt;/em&gt;. Errado! É possível, sim!&lt;/p&gt;
&lt;pre class=&quot;language-rust z-code&quot; data-lang=&quot;rust&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-keyword z-other z-rust&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;z-meta z-path z-rust&quot;&gt;std&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;collections&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;HashMap&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-rust&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;z-entity z-name z-function z-rust&quot;&gt;main&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; Inicializar um &lt;em&gt;map&lt;/em&gt; de entrada
&lt;/span&gt;    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;z-storage z-modifier z-rust&quot;&gt;mut&lt;/span&gt; entrada &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;z-meta z-path z-rust&quot;&gt;HashMap&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-generic z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-begin z-rust&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-storage z-type z-rust&quot;&gt;u64&lt;/span&gt;, &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;u64&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-end z-rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;new&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    entrada&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;insert&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;10&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    entrada&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;insert&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;20&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    entrada&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;insert&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;30&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; Continue...
&lt;/span&gt;    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; iterator &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; entrada&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;iter&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; mapeado &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; iterator&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&amp;amp;&lt;span class=&quot;z-variable z-parameter z-rust&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &amp;amp;&lt;span class=&quot;z-variable z-parameter z-rust&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;z-keyword z-control z-rust&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;key&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; value &lt;span class=&quot;z-keyword z-operator z-arithmetic z-rust&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; saida &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; mapeado&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;collect&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-generic z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-begin z-rust&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-support z-type z-rust&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-begin z-rust&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-end z-rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-end z-rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-support z-macro z-rust&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;z-constant z-other z-placeholder z-rust&quot;&gt;{:?}&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; output&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; [(1, 100), (3, 300), (2, 200)]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Quando iteramos um &lt;em&gt;HashMap&lt;/em&gt; a função &lt;code&gt;.map()&lt;/code&gt; muda para aceitar uma tupla, e &lt;code&gt;.collect()&lt;/code&gt; aceita tuplas. E é claro, você também pode fazer um &lt;em&gt;collect &lt;/em&gt;de volta para um &lt;em&gt;HashMap&lt;/em&gt; (ou qualquer outra coisa).&lt;/p&gt;
&lt;p&gt;Você notou como a ordem mudou? Isto acontece porque &lt;em&gt;HashMaps&lt;/em&gt; não são necessariamente ordenados. Lembre-se sempre disso!&lt;/p&gt;
&lt;p class=&quot;msg msg--highlight &quot;&gt;Tente mudar o código para converter um &lt;code&gt;Vec&amp;lt;(u64, u64)&amp;gt;&lt;/code&gt; num &lt;code&gt;HashMap&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;writing-an-iterator&quot;&gt;Escrevendo um &lt;em&gt;iterator&lt;/em&gt;&lt;/h2&gt;
&lt;p&gt;Tá, nós conseguimos experimentar algumas das coisas que podem implementar &lt;em&gt;iterators&lt;/em&gt;. Mas a gente também pode fazer um nosso! Que tal um &lt;em&gt;iterator&lt;/em&gt; que conta alguma coisa infinitamente?&lt;/p&gt;
&lt;pre class=&quot;language-rust z-code&quot; data-lang=&quot;rust&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-struct z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-struct z-rust&quot;&gt;struct&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;z-meta z-struct z-rust&quot;&gt;&lt;span class=&quot;z-entity z-name z-struct z-rust&quot;&gt;CountUp&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;z-meta z-struct z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;z-variable z-other z-member z-rust&quot;&gt;current&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-type z-rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;usize&lt;/span&gt;,
&lt;/span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;z-meta z-impl z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-impl z-rust&quot;&gt;impl&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;z-meta z-impl z-rust&quot;&gt;Iterator &lt;span class=&quot;z-keyword z-other z-rust&quot;&gt;for&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-impl z-rust&quot;&gt; &lt;span class=&quot;z-entity z-name z-impl z-rust&quot;&gt;CountUp&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;z-meta z-impl z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;z-storage z-type z-type z-rust&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;z-entity z-name z-type z-rust&quot;&gt;Item&lt;/span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;usize&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; A única fn que a gente precisa implementar num iterator básico
&lt;/span&gt;    &lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-rust&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;z-entity z-name z-function z-rust&quot;&gt;next&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-storage z-modifier z-rust&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;z-variable z-parameter z-rust&quot;&gt;self&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt; &lt;span class=&quot;z-meta z-function z-return-type z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;z-meta z-generic z-rust&quot;&gt;&lt;span class=&quot;z-support z-type z-rust&quot;&gt;Option&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-begin z-rust&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-storage z-type z-rust&quot;&gt;usize&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-end z-rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;z-variable z-language z-rust&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;current &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;z-support z-type z-rust&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-variable z-language z-rust&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;current&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-rust&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;z-entity z-name z-function z-rust&quot;&gt;main&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; iterator &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; CountUp &lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;/span&gt; current&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; Este é um iterator infinito, vamos pegar só alguns itens
&lt;/span&gt;    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; saida &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; iterator&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;take&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;20&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;collect&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-generic z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-begin z-rust&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-support z-type z-rust&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-begin z-rust&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-end z-rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-end z-rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-support z-macro z-rust&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;z-constant z-other z-placeholder z-rust&quot;&gt;{:?}&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; saida&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; Saída [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nós não precisamos chamar &lt;code&gt;.iter()&lt;/code&gt; aqui. Faz sentido, porque nós já estamos implementando um &lt;em&gt;iterator&lt;/em&gt; e não transformando alguma coisa num &lt;em&gt;iterator&lt;/em&gt; como fizemos antes.&lt;/p&gt;
&lt;p class=&quot;post__lead msg msg--highlight &quot;&gt;Tente mudar os valores de &lt;code&gt;current&lt;/code&gt; e &lt;code&gt;.take()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Viu como nós podemos usar &lt;code&gt;.take()&lt;/code&gt; e outras funções sem ter de implementar cada uma separadamente para nosso novo &lt;em&gt;iterator&lt;/em&gt;? Se você olhar &lt;a href=&quot;http://doc.rust-lang.org/core/iter/index.html#traits&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;a documentação&lt;/a&gt; do módulo &lt;code&gt;iter&lt;/code&gt;, verá que há várias traits como &lt;code&gt;Iterator&lt;/code&gt; ou &lt;code&gt;RandomAccessIterator&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1fp4ho0p7v7&quot;&gt;Intervalos com o operador Range&lt;/h2&gt;
&lt;p&gt;Através dos exemplos abaixo você verá o uso da sintaxe &lt;code&gt;x..y&lt;/code&gt;, que cria um intervalo (&lt;em&gt;range&lt;/em&gt;). Intervalos implementam &lt;code&gt;Iterator&lt;/code&gt; então não é necessário chamar &lt;code&gt;.iter()&lt;/code&gt; neles. Você também pode usar &lt;code&gt;(0..100).step_by(2)&lt;/code&gt; se quiser realizar pular alguns elementos a cada iteração.&lt;/p&gt;
&lt;p&gt;Note que intervalos são abertos, não inclusivos.&lt;/p&gt;
&lt;pre class=&quot;language-rust z-code&quot; data-lang=&quot;rust&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;z-keyword z-operator z-range z-rust&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;z-keyword z-operator z-comparison z-rust&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;z-keyword z-operator z-range z-rust&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;6&lt;/span&gt; &lt;span class=&quot;z-keyword z-operator z-comparison z-rust&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Também é possível utilizar intervalos como índices de coleção:&lt;/p&gt;
&lt;pre class=&quot;language-rust z-code&quot; data-lang=&quot;rust&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-rust&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;z-entity z-name z-function z-rust&quot;&gt;main&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; intervalo &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;z-keyword z-operator z-range z-rust&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;10&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;collect&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-generic z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-begin z-rust&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-support z-type z-rust&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-begin z-rust&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-storage z-type z-rust&quot;&gt;usize&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-end z-rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-end z-rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-support z-macro z-rust&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;z-constant z-other z-placeholder z-rust&quot;&gt;{:?}&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;z-keyword z-operator z-bitwise z-rust&quot;&gt;&amp;amp;intervalo&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-keyword z-operator z-range z-rust&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-support z-macro z-rust&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;z-constant z-other z-placeholder z-rust&quot;&gt;{:?}&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;z-keyword z-operator z-bitwise z-rust&quot;&gt;&amp;amp;intervalo&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;z-keyword z-operator z-range z-rust&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-support z-macro z-rust&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;z-constant z-other z-placeholder z-rust&quot;&gt;{:?}&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;z-keyword z-operator z-bitwise z-rust&quot;&gt;&amp;amp;intervalo&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;z-keyword z-operator z-range z-rust&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; Saída:
&lt;/span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; [0, 1, 2, 3, 4]
&lt;/span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; [2, 3, 4]
&lt;/span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; [7, 8, 9]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;msg msg--highlight &quot;&gt;Saquei: utilizar &lt;code&gt;.step_by()&lt;/code&gt; não funciona desse jeito já que não implementa &lt;code&gt;Idx&lt;/code&gt;, mas &lt;code&gt;Range&lt;/code&gt; implementa.&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1fp4ho0p7v8&quot;&gt;Encadear e compactar &lt;em&gt;iterators&lt;/em&gt;&lt;/h2&gt;
&lt;p&gt;Juntar &lt;em&gt;iterators&lt;/em&gt; de formas diferentes nos permite escrever códigos muito expressivos.&lt;/p&gt;
&lt;pre class=&quot;language-rust z-code&quot; data-lang=&quot;rust&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-rust&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;z-entity z-name z-function z-rust&quot;&gt;main&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; Demonstrando encadeamento
&lt;/span&gt;    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; primeiro &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;z-keyword z-operator z-range z-rust&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; segundo &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;z-keyword z-operator z-range z-rust&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; encadeado &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; primeiro&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;chain&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;segundo&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-support z-macro z-rust&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&quot;&lt;/span&gt;Encadeado: &lt;span class=&quot;z-constant z-other z-placeholder z-rust&quot;&gt;{:?}&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; encadeado&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;collect&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-generic z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-begin z-rust&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-support z-type z-rust&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-begin z-rust&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-end z-rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-end z-rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; Demonstrando compactação
&lt;/span&gt;    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; primeiro &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;z-keyword z-operator z-range z-rust&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; segundo &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;z-keyword z-operator z-range z-rust&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; compactado &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; primeiro&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;zip&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;segundo&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-support z-macro z-rust&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&quot;&lt;/span&gt;Compactado: &lt;span class=&quot;z-constant z-other z-placeholder z-rust&quot;&gt;{:?}&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; compactado&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;collect&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-generic z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-begin z-rust&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-support z-type z-rust&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-begin z-rust&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-end z-rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-end z-rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; Chained: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
&lt;/span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; Zipped: [(0, 5), (1, 6), (2, 7), (3, 8), (4, 9)]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;.zip()&lt;/code&gt; te permite juntar &lt;em&gt;iterators. &lt;/em&gt;Já o &lt;code&gt;.chain()&lt;/code&gt; cria um &lt;em&gt;iterator&lt;/em&gt; &quot;extendido&quot;.&lt;/p&gt;
&lt;p&gt;Sim, também existe o &lt;code&gt;.unzip().&lt;/code&gt;&lt;/p&gt;
&lt;p class=&quot;msg msg--highlight &quot;&gt;Tente usar &lt;code&gt;.zip()&lt;/code&gt; com dois &lt;em&gt;slices&lt;/em&gt; do tipo &lt;code&gt;&lt;em&gt;usize&lt;/em&gt;&lt;/code&gt; e depois fazer um &lt;code&gt;.collect()&lt;/code&gt; dessas tuplas para criar um &lt;em&gt;HashMap&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id=&quot;getting-inquisistive&quot;&gt;Vamos dar poder à curiosidade&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;.count()&lt;/code&gt;, &lt;code&gt;.max_by()&lt;/code&gt;, &lt;code&gt;.min_by()&lt;/code&gt;, &lt;code&gt;.all()&lt;/code&gt; e &lt;code&gt;.any()&lt;/code&gt; são formas comuns de verificar o que há dentro de um &lt;em&gt;iterator&lt;/em&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-rust z-code&quot; data-lang=&quot;rust&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-annotation z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-annotation z-rust&quot;&gt;#!&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-variable z-annotation z-rust&quot;&gt;feature&lt;/span&gt;&lt;span class=&quot;z-meta z-annotation z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-annotation z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;core&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-annotation z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; Isto só funciona com rust &lt;em&gt;nightly&lt;/em&gt; no momento em que o artigo foi escrito
&lt;/span&gt;&lt;span class=&quot;z-meta z-annotation z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-annotation z-rust&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-variable z-annotation z-rust&quot;&gt;derive&lt;/span&gt;&lt;span class=&quot;z-meta z-annotation z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-annotation z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;Eq&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; PartialEq&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; Debug&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-annotation z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;z-meta z-enum z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-enum z-rust&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;z-entity z-name z-enum z-rust&quot;&gt;EspecieDeUrso&lt;/span&gt; &lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;/span&gt; Marrom&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; Preto&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; Polar&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; Pardo &lt;/span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;z-meta z-annotation z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-annotation z-rust&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-variable z-annotation z-rust&quot;&gt;derive&lt;/span&gt;&lt;span class=&quot;z-meta z-annotation z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-annotation z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;Debug&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-annotation z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;z-meta z-struct z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-struct z-rust&quot;&gt;struct&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;z-meta z-struct z-rust&quot;&gt;&lt;span class=&quot;z-entity z-name z-struct z-rust&quot;&gt;Urso&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;z-meta z-struct z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;z-variable z-other z-member z-rust&quot;&gt;especie&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-type z-rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;z-meta z-enum z-rust&quot;&gt;&lt;span class=&quot;z-entity z-name z-enum z-rust&quot;&gt;EspecieDeUrso&lt;/span&gt;&lt;/span&gt;,
    &lt;span class=&quot;z-variable z-other z-member z-rust&quot;&gt;idade&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-type z-rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;usize&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-rust&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;z-entity z-name z-function z-rust&quot;&gt;main&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; ursos &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;z-meta z-struct z-rust&quot;&gt;&lt;span class=&quot;z-entity z-name z-struct z-rust&quot;&gt;Urso&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;z-meta z-struct z-rust&quot;&gt;&lt;span class=&quot;z-variable z-other z-member z-rust&quot;&gt;especie&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;z-meta z-enum z-rust&quot;&gt;&lt;span class=&quot;z-entity z-name z-enum z-rust&quot;&gt;EspecieDeUrso&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;Marrom&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; idade&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;z-meta z-struct z-rust&quot;&gt;&lt;span class=&quot;z-entity z-name z-struct z-rust&quot;&gt;Urso&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;z-meta z-struct z-rust&quot;&gt;&lt;span class=&quot;z-variable z-other z-member z-rust&quot;&gt;especie&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;z-meta z-enum z-rust&quot;&gt;&lt;span class=&quot;z-entity z-name z-enum z-rust&quot;&gt;EspecieDeUrso&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;Preto&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; idade&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;12&lt;/span&gt; &lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;z-meta z-struct z-rust&quot;&gt;&lt;span class=&quot;z-entity z-name z-struct z-rust&quot;&gt;Urso&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;z-meta z-struct z-rust&quot;&gt;&lt;span class=&quot;z-variable z-other z-member z-rust&quot;&gt;especie&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;z-meta z-enum z-rust&quot;&gt;&lt;span class=&quot;z-entity z-name z-enum z-rust&quot;&gt;EspecieDeUrso&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;Polar&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; idade&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;15&lt;/span&gt; &lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;z-meta z-struct z-rust&quot;&gt;&lt;span class=&quot;z-entity z-name z-struct z-rust&quot;&gt;Urso&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;z-meta z-struct z-rust&quot;&gt;&lt;span class=&quot;z-variable z-other z-member z-rust&quot;&gt;especie&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;z-meta z-enum z-rust&quot;&gt;&lt;span class=&quot;z-entity z-name z-enum z-rust&quot;&gt;EspecieDeUrso&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;Pardo&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; idade&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;16&lt;/span&gt; &lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; Max/Min de uma lista.
&lt;/span&gt;    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; mais_velho &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; ursos&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;iter&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;max_by&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-rust&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;x&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;idade&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; mais_novo &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; ursos&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;iter&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;min_by&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-rust&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;x&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.idade&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-support z-macro z-rust&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&quot;&lt;/span&gt;Mais velho: &lt;span class=&quot;z-constant z-other z-placeholder z-rust&quot;&gt;{:?}&lt;/span&gt;&lt;span class=&quot;z-constant z-character z-escape z-rust&quot;&gt;\n&lt;/span&gt;Mais novo: &lt;span class=&quot;z-constant z-other z-placeholder z-rust&quot;&gt;{:?}&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; mais_velho&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; mais_novo&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
&lt;br&gt;    &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; Algum / Todos
&lt;/span&gt;    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; tem_urso_polar &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; ursos&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;iter&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-rust&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;/span&gt;
        x&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;especie &lt;span class=&quot;z-keyword z-operator z-comparison z-rust&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;z-meta z-enum z-rust&quot;&gt;&lt;span class=&quot;z-entity z-name z-enum z-rust&quot;&gt;EspecieDeUrso&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;Polar
    &lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; todos_menores_de_idade &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; ursos&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;iter&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-rust&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;/span&gt;
        x&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.idade&lt;/span&gt; &lt;span class=&quot;z-keyword z-operator z-comparison z-rust&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;18&lt;/span&gt;
    &lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-support z-macro z-rust&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&quot;&lt;/span&gt;Pelo menos um urso polar?: &lt;span class=&quot;z-constant z-other z-placeholder z-rust&quot;&gt;{:?}&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; tem_urso_polar&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-support z-macro z-rust&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&quot;&lt;/span&gt;Todos são menores de idade? (&amp;lt;18): &lt;span class=&quot;z-constant z-other z-placeholder z-rust&quot;&gt;{:?}&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; todos_menores_de_idade&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; Saída:
&lt;/span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; Mais velho: Some(Urso { especie: Pardo, idade: 16 })
&lt;/span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; Mais novo: Some(Urso { especie: Marrom, idade: 5 })
&lt;/span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; Pelo menos um urso polar?: true
&lt;/span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; Todos são menores de idade? (&amp;lt;18): true
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;msg msg--highlight &quot;&gt;Tente utilizar o mesmo &lt;em&gt;iterator&lt;/em&gt; em todas as chamadas no exemplo acima. &lt;code&gt;.any()&lt;/code&gt; (algum) é o único que empresta (&lt;em&gt;borrow&lt;/em&gt;) de forma mutável e não funciona igual aos outros. Isto porque esta função talvez não consuma o &lt;em&gt;iterator&lt;/em&gt; por completo.&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1fp4ho0p7v9&quot;&gt;Filter, Map, Redu... não... Fold!&lt;/h2&gt;
&lt;p&gt;Se você, assim como eu, tem costume de programar em Javascript você provavelmente conhece a sagrada trindade &lt;code&gt;.filter()&lt;/code&gt;, &lt;code&gt;.map()&lt;/code&gt; e &lt;code&gt;.reduce()&lt;/code&gt;. Estas funções também estão disponíveis em Rust, mas &lt;code&gt;.reduce()&lt;/code&gt; é chamado de &lt;code&gt;.fold()&lt;/code&gt; (e eu meio que prefiro esse nome).&lt;/p&gt;
&lt;p&gt;Um exemplo:&lt;/p&gt;
&lt;pre class=&quot;language-rust z-code&quot; data-lang=&quot;rust&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-rust&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;z-entity z-name z-function z-rust&quot;&gt;main&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; entrada &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-keyword z-operator z-range z-rust&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; saida &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; entrada
        &lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-variable z-parameter z-rust&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;item &lt;span class=&quot;z-keyword z-operator z-arithmetic z-rust&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;z-keyword z-operator z-comparison z-rust&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; Apenas pares
&lt;/span&gt;        &lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-rust&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;item &lt;span class=&quot;z-keyword z-operator z-arithmetic z-rust&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; Multiplicar por dois.
&lt;/span&gt;        &lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;fold&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-rust&quot;&gt;acumulador&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;z-variable z-parameter z-rust&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-rust&quot;&gt;acumulador&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-rust&quot;&gt;+&lt;/span&gt; item&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-support z-macro z-rust&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;z-constant z-other z-placeholder z-rust&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; saida&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;O snippet acima poderia ser simplificado para:&lt;/p&gt;
&lt;pre class=&quot;language-rust z-code&quot; data-lang=&quot;rust&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-rust&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;z-entity z-name z-function z-rust&quot;&gt;main&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; entrada &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-keyword z-operator z-range z-rust&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; saida &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; entrada
        &lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;fold&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-rust&quot;&gt;acc&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;z-variable z-parameter z-rust&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;z-keyword z-control z-rust&quot;&gt;if&lt;/span&gt; b &lt;span class=&quot;z-keyword z-operator z-arithmetic z-rust&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;z-keyword z-operator z-comparison z-rust&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;/span&gt;
                acc &lt;span class=&quot;z-keyword z-operator z-arithmetic z-rust&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;item&lt;span class=&quot;z-keyword z-operator z-arithmetic z-rust&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;z-keyword z-control z-rust&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;/span&gt;
                acc
            &lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-support z-macro z-rust&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;z-constant z-other z-placeholder z-rust&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; saida&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Estas três funções tornam Rust um tanto flexível quanto expressivo.&lt;/p&gt;
&lt;h2 id=&quot;split-scan&quot;&gt;Split &amp;amp; Scan&lt;/h2&gt;
&lt;p&gt;Também tem o &lt;code&gt;scan&lt;/code&gt; caso você precise de uma variação de &lt;em&gt;fold&lt;/em&gt; que faz um &lt;em&gt;yield&lt;/em&gt; do resultado a cada iteração. Isto é bem útil se você precisa de um certo valor acumulado e quiser verificar este valor a cada iteração.&lt;/p&gt;
&lt;p&gt;Dividir um &lt;em&gt;iterator&lt;/em&gt; em duas partes também é possível. Você pode usar uma função de agrupamento que retorna um &lt;em&gt;boolean&lt;/em&gt; com &lt;code&gt;partition&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Vamos usar esses dois conceitos para:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;dividir um &lt;em&gt;slice&lt;/em&gt; grandão;&lt;/li&gt;
&lt;li&gt;agrupá-lo entre pares e ímpares;&lt;/li&gt;
&lt;li&gt;somar os grupos progressivamente; e&lt;/li&gt;
&lt;li&gt;verificar que o pares são sempre menores que a soma dos ímpares, já que pares começam com 0.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;language-rust z-code&quot; data-lang=&quot;rust&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-rust&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;z-entity z-name z-function z-rust&quot;&gt;main&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; lista &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;z-keyword z-operator z-range z-rust&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(par&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; impar&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-meta z-generic z-rust&quot;&gt;&lt;span class=&quot;z-support z-type z-rust&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-begin z-rust&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-end z-rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;z-meta z-generic z-rust&quot;&gt;&lt;span class=&quot;z-support z-type z-rust&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-begin z-rust&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-end z-rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; lista&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;partition&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-variable z-parameter z-rust&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;n &lt;span class=&quot;z-keyword z-operator z-arithmetic z-rust&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;z-keyword z-operator z-comparison z-rust&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; par_scanner &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; par&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;iter&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;scan&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-rust&quot;&gt;acc&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-variable z-parameter z-rust&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-rust&quot;&gt;*&lt;/span&gt;acc &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;+=&lt;/span&gt; x&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;z-support z-type z-rust&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-keyword z-operator z-arithmetic z-rust&quot;&gt;*&lt;/span&gt;acc&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; impar_scanner  &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; impar&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;iter&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;scan&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-rust&quot;&gt;acc&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-variable z-parameter z-rust&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-rust&quot;&gt;*&lt;/span&gt;acc &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;+=&lt;/span&gt; x&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;z-support z-type z-rust&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-keyword z-operator z-arithmetic z-rust&quot;&gt;*&lt;/span&gt;acc&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; par_sempre_menor &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; par_scanner&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;zip&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;impar_scanner&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-variable z-parameter z-rust&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;z-variable z-parameter z-rust&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;e &lt;span class=&quot;z-keyword z-operator z-comparison z-rust&quot;&gt;&amp;lt;=&lt;/span&gt; o&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-support z-macro z-rust&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&quot;&lt;/span&gt;Par sempre menor: &lt;span class=&quot;z-constant z-other z-placeholder z-rust&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; par_sempre_menor&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; Saída:
&lt;/span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; Par sempre menor: true
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Scan&lt;/em&gt; pode ser utilizado para gerar dados como médias móveis. Isto é útil quando se lê arquivos, dados e sensores. Particionar dados é uma tarefa comum quando se estiver organizando dados.&lt;/p&gt;
&lt;p&gt;Outra operação comum é agrupar elementos com base num valor específico. Se você estiver buscando algo como o &lt;code&gt;_.groupBy()&lt;/code&gt; do Lodash, calma lá. Considerando que &lt;em&gt;Rust&lt;/em&gt; possui &lt;code&gt;BTreeMap&lt;/code&gt;, &lt;code&gt;HashMap&lt;/code&gt;, &lt;code&gt;VecMap&lt;/code&gt; e outros tipos de dados, o nosso método de agrupamento precisa ser genérico.&lt;/p&gt;
&lt;p&gt;Vamos ver um exemplo simples. Vamos escrever um &lt;em&gt;iterator&lt;/em&gt; infinito que repete o intervalo de 0 a 5. No seu código esse &lt;em&gt;iterator&lt;/em&gt; poderia utilizar structs ou tuplas, mas por agora, vamos utilizar somente inteiros.&lt;/p&gt;
&lt;p&gt;Vamos agrupá-los em três categorias: zeros, cincos e todo o resto.&lt;/p&gt;
&lt;pre class=&quot;language-rust z-code&quot; data-lang=&quot;rust&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-keyword z-other z-rust&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;z-meta z-path z-rust&quot;&gt;std&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;collections&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;HashMap&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;z-meta z-annotation z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-annotation z-rust&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-variable z-annotation z-rust&quot;&gt;derive&lt;/span&gt;&lt;span class=&quot;z-meta z-annotation z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-annotation z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;Debug&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; PartialEq&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; Eq&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; Hash&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-annotation z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;z-meta z-enum z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-enum z-rust&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;z-entity z-name z-enum z-rust&quot;&gt;Tipo&lt;/span&gt; &lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;/span&gt; Zero&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; Cinco&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; Outro &lt;/span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-rust&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;z-entity z-name z-function z-rust&quot;&gt;main&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; valores &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;z-keyword z-operator z-range z-rust&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; [0, 1, 2, 4, 5]
&lt;/span&gt;    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; ciclico &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; values&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;cycle&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; Agrupar em um HashMap
&lt;/span&gt;    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; agrupado &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; ciclico&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;take&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;20&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-rust&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;br&gt;        // Retorna uma tupla
&lt;/span&gt;        &lt;span class=&quot;z-keyword z-control z-rust&quot;&gt;match&lt;/span&gt; x &lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;/span&gt;
            x &lt;span class=&quot;z-keyword z-control z-rust&quot;&gt;if&lt;/span&gt; x &lt;span class=&quot;z-keyword z-operator z-comparison z-rust&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;span class=&quot;z-meta z-enum z-rust&quot;&gt;&lt;span class=&quot;z-entity z-name z-enum z-rust&quot;&gt;Tipo&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;Cinco&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt;
            x &lt;span class=&quot;z-keyword z-control z-rust&quot;&gt;if&lt;/span&gt; x &lt;span class=&quot;z-keyword z-operator z-comparison z-rust&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;span class=&quot;z-meta z-enum z-rust&quot;&gt;&lt;span class=&quot;z-entity z-name z-enum z-rust&quot;&gt;Tipo&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;Zero&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt;
            x &lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;span class=&quot;z-meta z-enum z-rust&quot;&gt;&lt;span class=&quot;z-entity z-name z-enum z-rust&quot;&gt;Tipo&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;Outro&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; x&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; Acumule os valores
&lt;/span&gt;    &lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;fold&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;HashMap&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-generic z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-begin z-rust&quot;&gt;&amp;lt;&lt;/span&gt;Tipo, &lt;span class=&quot;z-support z-type z-rust&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-begin z-rust&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-end z-rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-generic z-end z-rust&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;/span&gt;&lt;/span&gt;new&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-rust&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;z-variable z-parameter z-rust&quot;&gt;acc&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-variable z-parameter z-rust&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;z-variable z-parameter z-rust&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;|&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;z-meta z-function z-closure z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;/span&gt;
        acc&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;k&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;or_insert&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-support z-macro z-rust&quot;&gt;vec!&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;x&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
        acc
    &lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-support z-macro z-rust&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;z-constant z-other z-placeholder z-rust&quot;&gt;{:?}&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; agrupado&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; Saída: {Zero: [0, 0, 0, 0], Cinco: [5, 5, 5], Outro: [1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1]}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;msg msg--highlight &quot;&gt;É meio que inútil guardar todos os valores replicados. Tente mudar o exemplo acima para retornar o número de ocorrências em vez de valores. Se quiser ir ainda mais longe, tente utilizar este método num valor mais complexo como uma &lt;code&gt;struct&lt;/code&gt;, você também pode mudar quais chaves são utilizadas.&lt;/p&gt;
&lt;h2 id=&quot;flanked&quot;&gt;Flanqueado&lt;/h2&gt;
&lt;p&gt;A trait &lt;code&gt;DoubleEndedIterator&lt;/code&gt; é útil em alguns casos. Por exemplo, quando você precisa dos comportamentos de uma fila e pilha ao mesmo tempo.&lt;/p&gt;
&lt;pre class=&quot;language-rust z-code&quot; data-lang=&quot;rust&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-rust&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;z-entity z-name z-function z-rust&quot;&gt;main&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;z-storage z-modifier z-rust&quot;&gt;mut&lt;/span&gt; valores &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;z-keyword z-operator z-range z-rust&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-support z-macro z-rust&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;z-constant z-other z-placeholder z-rust&quot;&gt;{:?}&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; valores&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-support z-macro z-rust&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;z-constant z-other z-placeholder z-rust&quot;&gt;{:?}&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; valores&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;next_back&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-support z-macro z-rust&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;z-constant z-other z-placeholder z-rust&quot;&gt;{:?}&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; valores&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;z-support z-macro z-rust&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;z-constant z-other z-placeholder z-rust&quot;&gt;{:?}&lt;/span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;/span&gt; valores&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;next_back&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; Some(0)
&lt;/span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; Some(9)
&lt;/span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; Some(1)
&lt;/span&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;//&lt;/span&gt; Some(8)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id=&quot;mcetoc_1fp4ho0p7va&quot;&gt;Agora vai brincar!&lt;/h1&gt;
&lt;p&gt;Agora tá na hora de você fazer uma pausa, preparar um cházinho e abrir o &lt;a href=&quot;https://play.rust-lang.org/&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;Playground&lt;/a&gt;. Tente mudar um dos exemplos acima, brinque com algumas outras coisas dos links de documentação abaixo e, no mais, divirta-se.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;http://doc.rust-lang.org/1.0.0-beta.3/std/collections/&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;&lt;em&gt;std::collections&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://doc.rust-lang.org/1.0.0-beta.3/std/iter/index.html&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;std::iter&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Se você travar, não se preocupe! Procure na internet se o erro não fizer sentido nenhum pra ti. Rust também tem uma comunidade muito ativa nos domínios &lt;code&gt;*.rust-lang.org&lt;/code&gt; assim como no GitHub e no Stack Exchange. Sinta-se convidad@ a me enviar um email ou dar um alô no &lt;a href=&quot;https://chat.mibbit.com/?server=irc.mozilla.org&amp;amp;channel=%23rust&quot; rel=&quot;nofollow&quot;&gt;IRC&lt;/a&gt; também.&lt;/p&gt;
&lt;p&gt;O que a gente viu é só a superfície... um mundo imenso nos aguarda.&lt;/p&gt;</content:encoded><category>rust</category><category>gringo</category></item><item><title>Entregar / Mostrar / Perguntar: uma estratégia moderna para lidar com seus branches</title><link>https://codamos.com.br/entregar-mostrar-perguntar-branch-git/</link><guid isPermaLink="true">https://codamos.com.br/entregar-mostrar-perguntar-branch-git/</guid><description>Atenção: este texto foi traduzido, editado e adaptado por @nawarian . Você encontra o texto original em inglês no blog do MartinFowler através deste link . Entregar/Mostrar/Perguntar é uma estratégia </description><pubDate>Fri, 07 Jan 2022 19:10:35 GMT</pubDate><content:encoded>&lt;p class=&quot;msg msg--info&quot;&gt;&lt;strong&gt;Atenção:&lt;/strong&gt; este texto foi traduzido, editado e adaptado por &lt;a href=&quot;https://twitter.com/nawarian&quot; target=&quot;_blank&quot; rel=&quot;nofollow ugc noopener noreferrer&quot;&gt;@nawarian&lt;/a&gt;. Você encontra o texto original em inglês no blog do MartinFowler através &lt;a href=&quot;https://martinfowler.com/articles/ship-show-ask.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow ugc noopener noreferrer&quot;&gt;deste link&lt;/a&gt;.&lt;/p&gt;
&lt;p class=&quot;post__lead&quot;&gt;Entregar/Mostrar/Perguntar é uma estratégia de ramificação (&lt;em&gt;branching&lt;/em&gt;) que combina as funcionalidades de &lt;em&gt;Pull Requests&lt;/em&gt; com a habilidade de entregar alterações de software continuamente. As mudanças são categorizadas como &lt;strong&gt;&lt;em&gt;Entregar&lt;/em&gt;&lt;/strong&gt; (fazer &lt;em&gt;merge &lt;/em&gt;imediatamente sem revisão), &lt;em&gt;&lt;strong&gt;Mostrar&lt;/strong&gt; &lt;/em&gt;(abrir um &lt;em&gt;pull request&lt;/em&gt; para revisão mas fazer um &lt;em&gt;merge&lt;/em&gt; imediatamente) ou &lt;strong&gt;&lt;em&gt;Perguntar&lt;/em&gt;&lt;/strong&gt; (abrir um pull request para discussão antes de fazer o merge).&lt;/p&gt;
&lt;div class=&quot;post__toc&quot;&gt;
&lt;h3&gt;Conteúdo do post&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1foqrv7rc2i6&quot;&gt;Como fazer integração contínua sem Pull Requests?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1foqj4g511p&quot;&gt;Introduzindo o Entregar / Mostrar / Perguntar&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1foqj4g511q&quot;&gt;Entregar&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1foqj4g511r&quot;&gt;Mostrar&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1foqj4g511s&quot;&gt;Perguntar&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1foqrv7rc2i7&quot;&gt;Regras&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1foqrv7rc2i8&quot;&gt;Conversa&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1foqrv7rc2i9&quot;&gt;Equilíbrio&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1foqrv7rc2ia&quot;&gt;Meu time deve adotar esta abordagem?&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1foqrv7rc2ib&quot;&gt;Se você entrega na maioria das vezes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1foqrv7rc2ic&quot;&gt;Se você pergunta na maioria das vezes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1foqrv7rc2id&quot;&gt;Conclusão&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1foqrv7rc2ie&quot;&gt;Agradecimentos&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1foqj4g5125&quot;&gt;Notas de rodapé&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paperBody deep&quot;&gt;
&lt;section id=&quot;HowDoYouDoContinuousIntegrationWithPullRequests&quot;&gt;
&lt;h2 id=&quot;mcetoc_1foqrv7rc2i6&quot;&gt;Como fazer integração contínua sem Pull Requests?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://martinfowler.com/bliki/PullRequest.html&quot; rel=&quot;nofollow ugc&quot;&gt;Pull Requests&lt;/a&gt; foram adotados por muitos times de desenvolvimento de software. Algumas pessoas os amam, e outras desejam alcançar a tão sonhada &lt;a href=&quot;https://martinfowler.com/articles/continuousIntegration.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow ugc noopener noreferrer&quot;&gt;Integração Contínua&lt;/a&gt; - onde você nunca cria branches e seu time integra suas mudanças o tempo todo.&lt;/p&gt;
&lt;p&gt;Em vários aspectos, Pull Requests são ferramentas fantásticas. Ferramentas de versionamento oferecem funcionalidades de revisão de código maravilhosas. Há vários provedores &lt;em&gt;SaaS&lt;/em&gt; que oferecem serviços que podem rodar em seus pull requests - desde rodar testes e verificar qualidade de código até fazer o &lt;em&gt;deploy &lt;/em&gt;de ambientes de homologação.&lt;/p&gt;
&lt;p&gt;Mas a adoção de Pull Requests como a principal forma de contribuir com código criou alguns problemas. Nós perdemos um pouco da mentalidade &quot;Pronto pra lançar&quot; que tínhamos quando fazíamos Integração Contínua. Funcionalidades em desenvolvimento ficam fora de cena até ficarem prontas para integração, e assim caímos nas &lt;a href=&quot;https://martinfowler.com/articles/branching-patterns.html#Low-frequencyIntegration&quot; target=&quot;_blank&quot; rel=&quot;nofollow ugc noopener noreferrer&quot;&gt;armadilhas da integração de baixa frequência&lt;/a&gt; que a Integração Contínua procura resolver.&lt;/p&gt;
&lt;p&gt;As vezes Pull Requests ficam parados, ou nós mesmos ficamos sem muita ideia de o que fazer enquanto esperamos por uma revisão. As vezes eles ficam inchados por mudanças não relacionadas e pequenas melhorias que a gente faz pensando &quot;ah, já que eu tô aqui mesmo...&quot;&lt;/p&gt;
&lt;p&gt;Nós também ficamos cansados com o número de Pull Requests que precisamos revisar, e paramos de falar sobre código. Nós paramos de prestar atenção e clicamos em &quot;Aprovar&quot; ou mandamos o famoso &lt;a href=&quot;https://www.abbreviationfinder.org/pt/acronyms/lgtm.html&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;LGTM&lt;/a&gt; sem muito senso crítico.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;IntroducingShipShowAsk&quot;&gt;
&lt;h2 id=&quot;mcetoc_1foqj4g511p&quot;&gt;Introduzindo o Entregar / Mostrar / Perguntar&lt;/h2&gt;
&lt;p&gt;Existe uma abordagem de ramificação (branching) que eu utilizei com meus times. Funcionou muito bem, então eu gostaria de compartilhar contigo.&lt;/p&gt;
&lt;p&gt;Toda vez que você fizer uma alteração, você precisa escolher três opções: Entregar, Mostrar ou Perguntar.&lt;/p&gt;
&lt;section id=&quot;Ship&quot;&gt;
&lt;h3 id=&quot;mcetoc_1foqj4g511q&quot;&gt;Entregar&lt;/h3&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/24/entregar.png&quot; alt=&quot;Figura 1: Alteração vai direto para o branch principal&quot; width=&quot;1515&quot; height=&quot;455&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Figura 1: Alteração vai direto para o branch principal&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/section&gt;
&lt;section id=&quot;Ship&quot;&gt;
&lt;div id=&quot;Ship.png&quot; class=&quot;figure &quot;&gt;
&lt;p class=&quot;photoCaption&quot;&gt;Esta estratégia se assemelha muito com Integração Contínua: se você quer fazer uma alteração, faz diretamente no seu &lt;a href=&quot;https://martinfowler.com/articles/branching-patterns.html#mainline&quot; target=&quot;_blank&quot; rel=&quot;nofollow ugc noopener noreferrer&quot;&gt;branch principal&lt;/a&gt;. Ao fazer isto você não precisa esperar alguém fazer o deploy das suas alterações para o ambiente de produção e nem pede revisão de código. Tudo sem muito alarde: faça a alteração utilizando todas as técnicas de Integração Contínua que tornam este procedimento seguro.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Isto funciona muito bem quando:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Eu adiciono uma funcionalidade utilizando uma técnica bem estabelecida&lt;/li&gt;
&lt;li&gt;Eu corrijo um bug simples / pequeno&lt;/li&gt;
&lt;li&gt;Eu atualizo documentação&lt;/li&gt;
&lt;li&gt;Eu fiz alguma melhoria no meu código baseado em feedback&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;Show&quot;&gt;
&lt;h3 id=&quot;mcetoc_1foqj4g511r&quot;&gt;Mostrar&lt;/h3&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/24/mostrar.png&quot; alt=&quot;Figura 2: Abra um Pull Request para receber feedback, mas faça o merge imediatamente&quot; width=&quot;1547&quot; height=&quot;550&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Figura 2: Abra um Pull Request para receber feedback, mas faça o merge imediatamente&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/section&gt;
&lt;section id=&quot;Show&quot;&gt;
&lt;div id=&quot;Show.png&quot; class=&quot;figure &quot;&gt;
&lt;p class=&quot;photoCaption&quot;&gt;Aqui é onde nós adotamos a mentalidade de Integração Contínua e ao mesmo tempo aproveitamos as coisas boas que Pull Requests nos dão. Você faz a mudança num branch, abre um Pull Request e faz um merge sem esperar ninguém. Você só espera pelos testes automatizados (testes, cobertura de código, ambiente de homologação, etc.), mas não espera pelo feedback de ninguém para prosseguir com o deploy da sua alteração.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Desta forma você entrega as suas alterações rapidamente enquanto cria o espaço para feedback e conversa. O seu time recebe notificações dos Pull Requests e podem revisar o que você fez. Eles podem então dar feedback na sua abordagem ou código, fazer perguntas e aprender através das suas alterações.&lt;/p&gt;
&lt;p&gt;Isto funciona bem quando:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Eu quero feedback sobre como este código poderia ser melhor&lt;/li&gt;
&lt;li&gt;Eu gostaria de mostrar uma nova abordagem ou padrão que utilizei&lt;/li&gt;
&lt;li&gt;Eu refatorei X e quero que meu time fique ciente desta alteração&lt;/li&gt;
&lt;li&gt;Eu quero compartilhar com meu time a solução para um bug interessante&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;Ask&quot;&gt;
&lt;h3 id=&quot;mcetoc_1foqj4g511s&quot;&gt;Perguntar&lt;/h3&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/24/perguntar.png&quot; alt=&quot;Figura 3: Abrir um Pull Request para receber feedback e esperar para fazer um merge&quot; width=&quot;1547&quot; height=&quot;550&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Figura 3: Abrir um Pull Request para receber feedback e esperar para fazer um merge&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/section&gt;
&lt;section id=&quot;Ask&quot;&gt;
&lt;div id=&quot;Ask.png&quot; class=&quot;figure &quot;&gt;
&lt;p class=&quot;photoCaption&quot;&gt;Esta é a estratégia que muitos de vocês já estão acostumados. Nós fazemos nossas alterações num branch, abrimos um Pull Request e esperamos pelo feedback dos colegas antes de fazer o merge. Talvez não tenhamos certeza de que utilizamos a abordagem correta. Talvez tenha algo no código que não gostamos muito mas não sabemos como melhorar. Talvez você tenha experimentado algo novo e gostaria de ver o que seus colegas acham.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Ferramentas de revisão de código modernas dão espaço para este tipo de conversa e você pode até colocar o time inteiro para revisar e discutir um Pull Request juntos.&lt;/p&gt;
&lt;p&gt;Isto funciona bem quando:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Eu não tenho certeza de que minhas mudanças vão funcionar&lt;/li&gt;
&lt;li&gt;Eu quero saber como meus colegas se sentem sobre esta nova abordagem&lt;/li&gt;
&lt;li&gt;Eu preciso de ajuda pra melhorar meu código&lt;/li&gt;
&lt;li&gt;Eu já encerrei o expediente hoje e vou fazer o merge amanhã&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;TheRules&quot;&gt;
&lt;h2 id=&quot;mcetoc_1foqrv7rc2i7&quot;&gt;Regras&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Revisão de código ou &quot;Aprovação&quot; não devem ser requisitos para um Pull Request ser integrado no branch principal&lt;/li&gt;
&lt;li&gt;Autores fazem o merge de seus próprios Pull Requests. Desta forma, estas pessoas controlam se as alterações são do tipo &lt;em&gt;Mostrar&lt;/em&gt; ou &lt;em&gt;Perguntar&lt;/em&gt;, e decidem quando as mudanças vão para produção&lt;/li&gt;
&lt;li&gt;É possível utilizar todas as técnicas de Integração Contínua e &lt;a href=&quot;https://martinfowler.com/bliki/ContinuousDelivery.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow ugc noopener noreferrer&quot;&gt;Entrega Contínua&lt;/a&gt; que ajudam a manter o branch principal pronto para ser lançado para produção. &lt;a href=&quot;https://martinfowler.com/bliki/FeatureToggle.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow ugc noopener noreferrer&quot;&gt;Feature Toggles&lt;/a&gt; são um exemplo.&lt;/li&gt;
&lt;li&gt;Ramificações (branches) não devem existir por muito tempo, e devemos fazer um &lt;em&gt;rebase&lt;/em&gt; com o branch principal com frequência&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id=&quot;TheConversation&quot;&gt;
&lt;h2 id=&quot;mcetoc_1foqrv7rc2i8&quot;&gt;Conversa&lt;/h2&gt;
&lt;p&gt;Enquanto Pull Requests podem ser uma forma muito útil de falar sobre alterações de código, eles trazem consigo algumas armadilhas. A armadilha mais sedutora é a ideia de que eles podem substituir outras formas de discussão.&lt;/p&gt;
&lt;p&gt;Um problema comum com ramificações é que autores decidem utilizar uma abordagem sem a discutir com ninguém. Quando o Pull Request finalmente é aberto, o tempo já foi investido numa implementação que pode não ser a melhor. Revisores são influenciados pela solução já adotada e têm dificuldade em sugerir abordagens diferentes. Quanto mais mudanças e mais velho for o branch, maior o problema. Converse com seu time antes de começar, para que você colete mais e melhores ideias e possa previnir retrabalho.&lt;/p&gt;
&lt;p&gt;Lembre-se de que Pull Requests não são a única forma de &lt;em&gt;Mostrar&lt;/em&gt; ou &lt;em&gt;Perguntar&lt;/em&gt;. Faça uma ligação ou vá até a mesa de alguém. Mostre seu trabalho o quanto antes e frequentemente. Peça ajuda e feedback o quanto antes e frequentemente. Trabalhe nas tarefas em conjunto com seus colegas.&lt;/p&gt;
&lt;p&gt;Não abrir um Pull Request não é uma boa razão para evitar conversar sobre o código. É importante que seus colegas mantenham uma boa cultura de feedback e conversem entre si sobre o que acham e aprendem.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;TheBalance&quot;&gt;
&lt;h2 id=&quot;mcetoc_1foqrv7rc2i9&quot;&gt;Equilíbrio&lt;/h2&gt;
&lt;p&gt;Dadas essas três opções, quais eu deveria escolher com maior frequência?&lt;/p&gt;
&lt;p&gt;Depende. Eu acho que cada time tem seu equilíbrio em cada momento.&lt;/p&gt;
&lt;p&gt;Quando você está entregando funcionalidades utilizando uma abordagem já consolidada, você vai &lt;em&gt;Entregar&lt;/em&gt; mais. Quando você confia no time e todos compartilham dos mesmos padrões de qualidade, você também fará mais &lt;em&gt;Entregas.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Mas se vocês ainda estiverem se conhecendo ou fazendo algo completamente novo, então a necessidade de conversa é maior. Vocês irão &lt;em&gt;Mostrar&lt;/em&gt; e &lt;em&gt;Perguntar&lt;/em&gt; com mais frequência. Um iniciante talvez &lt;em&gt;Mostre&lt;/em&gt; e &lt;em&gt;Pergunte&lt;/em&gt; mais, enquanto um sênior &lt;em&gt;Entrega&lt;/em&gt; muito mais, mas de vez em quando &lt;em&gt;Mostra&lt;/em&gt; uma nova técnica ou uma refatoração que todo mundo deveria tentar.&lt;/p&gt;
&lt;p&gt;Alguns times não têm muita flexibilidade. Algumas indústrias são altamente reguladas e o processo de aprovação ou revisão de código são obrigatórios para cada alteração de código. Há várias formas de implementar isso - com ou sem ramificações - que eu não vou comentar aqui.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;ShouldMyTeamAdoptThisApproach&quot;&gt;
&lt;h2 id=&quot;mcetoc_1foqrv7rc2ia&quot;&gt;Meu time deve adotar esta abordagem?&lt;/h2&gt;
&lt;p&gt;Vocês já adotaram.&lt;/p&gt;
&lt;p&gt;Pense bem em como seu time funciona e você vai reparar que você já está lidando com &lt;em&gt;Entregar/Mostrar/Perguntar.&lt;/em&gt; A maioria dos times normalmente cai em &lt;em&gt;Entregar na maioria das vezes&lt;/em&gt; ou &lt;em&gt;Perguntar na maioria das vezes&lt;/em&gt;.&lt;/p&gt;
&lt;section id=&quot;IfYouMostlyShip&quot;&gt;
&lt;h3 id=&quot;mcetoc_1foqrv7rc2ib&quot;&gt;Se você &lt;em&gt;entrega&lt;/em&gt; na maioria das vezes&lt;/h3&gt;
&lt;p&gt;Se você raramente cria um branch e todos os commits vão direto para o branch principal, você &lt;em&gt;Entrega na maioria das vezes.&lt;/em&gt; Se este é o seu caso, pense como &lt;em&gt;Mostrar&lt;/em&gt; um pouco mais pode te ajudar.&lt;/p&gt;
&lt;p&gt;Um grande motivo pelo qual os modelos de Pull Request se tornaram tão populares é que eles dão suporte a times que trabalham de forma remota e assíncrona. &lt;em&gt;Mostrar&lt;/em&gt; explicitamente as partes interessantes do seu trabalho aos outros pode ajudá-los a aprender e sentirem-se parte da conversa, especialmente quando se trabalha de forma remota e em fuso horários diferentes.&lt;/p&gt;
&lt;p&gt;Eu também notei (especialmente em times que não conversam o suficiente &lt;span class=&quot;foot-ref&quot;&gt;&lt;a href=&quot;#nota-de-rodape-1&quot;&gt;[1]&lt;/a&gt;&lt;/span&gt;) que fazer sempre o merge para o branch principal pode significar que algumas mudanças problemáticas podem passar desapercebidas por algumas semanas. Quando isto acontece é difícil ter uma conversa útil sobre elas porque os detalhes e contextos já se perderam no tempo. Encorajar colegas a &lt;em&gt;Mostrar&lt;/em&gt; significa que vocês vão conversar mais sobre o código comumente.&lt;/p&gt;
&lt;/section&gt;
&lt;section id=&quot;IfYouMostlyAsk&quot;&gt;
&lt;h3 id=&quot;mcetoc_1foqrv7rc2ic&quot;&gt;Se você &lt;em&gt;pergunta na maioria das vezes&lt;/em&gt;&lt;/h3&gt;
&lt;p&gt;Se seu time abre Pull Requests para a maioria das alterações, vocês &lt;em&gt;Perguntam na maioria das vezes.&lt;/em&gt; Se por um lado Pull Requests são uma ferramenta útil para qualidade e feedback, por outro lado eles podem criar um problema de escalabilidade. O inevitável sobre pedir aprovação é que isso leva tempo. Se muitas mudanças estão na fila do feedback, a qualidade do feedback diminui ou a velocidade diminui. Tente &lt;em&gt;Mostrar&lt;/em&gt; com mais frequência para que você tire proveito do melhor dos dois mundos.&lt;/p&gt;
&lt;p&gt;O motivo pelo qual vocês dependem muito de &lt;em&gt;Perguntar&lt;/em&gt; pode ser falta de confiança. &lt;em&gt;&quot;Todas mudanças precisam ser aprovadas&quot;&lt;/em&gt; ou &lt;em&gt;&quot;Todo Pull Request precisa de 2 revisores&quot;&lt;/em&gt; são práticas comuns, mas demonstram falta de confiança no time de desenvolvimento.&lt;/p&gt;
&lt;p&gt;Isto é problemático porque a aprovação é apenas um band-aid - ela não vai corrigir seu problema de confiança. &lt;em&gt;Mostre&lt;/em&gt; um pouco mais para tirar um pouco da pressão do ciclo de desenvolvimento e dê maior atenção a atividades que aumentam a confiança no time como treinamentos, discussões em time ou programação em pares. Toda vez que uma pessoa &lt;em&gt;Mostra&lt;/em&gt; em vez de &lt;em&gt;Perguntar&lt;/em&gt; é uma oportunidade para elas construírem confiança com o time.&lt;/p&gt;
&lt;p&gt;Outro motivo para depender muito de aprovação pode ser que seu time não se sinta seguro em enviar mudanças diretamente para o branch principal. Neste caso o que você precisa é aprender sobre como implementar técnicas que mantenham o seu branch principal sempre pronto para lançamento. Enquanto isso, &lt;em&gt;Mostrar&lt;/em&gt; mais pode ajudar a diminuir a barreira para lançar mudanças de forma segura para produção. Reduzir esta barreira vai servir de incentivo para seus colegas - se você encontrar formas de tornar suas alterações mais seguras, elas podem ir para produção mais cedo.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id=&quot;Conclusion&quot;&gt;
&lt;h2 id=&quot;mcetoc_1foqrv7rc2id&quot;&gt;Conclusão&lt;/h2&gt;
&lt;p&gt;Então o que é &lt;em&gt;Entregar/Mostrar/Perguntar?&lt;/em&gt; Em suma, são duas coisas:&lt;/p&gt;
&lt;p&gt;Primeiro – um truque para te ajudar a obter o melhor de dois mundos - fazer o merge do seu próprio pull request sem aguardar feedback e dar atenção ao feedback quando este chegar.&lt;/p&gt;
&lt;p&gt;Segundo – uma forma mais inclusiva e dinâmica de lidar com estratégias de ramificação. &lt;em&gt;Entregar/Mostrar/Perguntar&lt;/em&gt; nos lembra que a abordagem de cada time normalmente fica em algum lugar entre &lt;em&gt;Entregar sempre&lt;/em&gt; e&lt;em&gt; Perguntar sempre&lt;/em&gt;. Isto nos encoraja a pensar sobre cada alteração independentemente e nos perguntar-mos: eu deveria &lt;em&gt;Entregar, Mostrar ou Perguntar&lt;/em&gt;?&lt;/p&gt;
&lt;/section&gt;
&lt;hr class=&quot;bodySep&quot;&gt;&lt;/div&gt;
&lt;div class=&quot;appendix&quot;&gt;
&lt;section id=&quot;Acknowledgements&quot;&gt;
&lt;h2 id=&quot;mcetoc_1foqrv7rc2ie&quot;&gt;Agradecimentos&lt;/h2&gt;
&lt;p&gt;Obrigado a todos que ajudaram com feedback detalhado na preparação deste texto: Martin Fowler, Brian Gunthrie, Federico Blancato, Stephen Creswell e Paul Hammant.&lt;/p&gt;
&lt;p&gt;Agradeço também ao Matthew Harward, Kief Morris, Giuseppe Pereira, Marcos Vinícius da Silva, Birgitta Böckeler, Prashanth R, Premanand Chandrasekaran, João Paulo Moraes e Mark Taylor, que discutiram o rascunho deste texto numa &lt;em&gt;mailing list&lt;/em&gt; interna da ThoughtWorks.&lt;/p&gt;
&lt;/section&gt;
&lt;div class=&quot;footnote-list&quot;&gt;
&lt;h2 id=&quot;mcetoc_1foqj4g5125&quot;&gt;Notas de rodapé&lt;/h2&gt;
&lt;div id=&quot;footnote-pairing&quot; class=&quot;footnote-list-item&quot;&gt;
&lt;p id=&quot;nota-de-rodape-1&quot;&gt;1: &lt;a href=&quot;https://martinfowler.com/bliki/PairProgramming.html&quot;&gt;Pair Programming&lt;/a&gt; ou programação em pares é uma técnica efetiva para encorajar comunicação contínua num time&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded><category>git</category><category>gringo</category><category>tecnica</category></item><item><title>Como funciona o JavaScript: por dentro do motor V8 e 5 dicas de como otimizar seu código</title><link>https://codamos.com.br/como-funciona-javascript-motor-v8/</link><guid isPermaLink="true">https://codamos.com.br/como-funciona-javascript-motor-v8/</guid><description>Atenção: este texto foi traduzido, editado e adaptado por @nawarian . Você encontra o texto original em inglês no blog do nosso parceiro SessionStack através deste link . Há algumas semanas, começamos</description><pubDate>Wed, 05 Jan 2022 10:51:16 GMT</pubDate><content:encoded>&lt;p class=&quot;msg msg--info&quot; data-selectable-paragraph=&quot;&quot;&gt;&lt;strong&gt;Atenção:&lt;/strong&gt; este texto foi traduzido, editado e adaptado por &lt;a href=&quot;https://twitter.com/nawarian&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;@nawarian&lt;/a&gt;. Você encontra o texto original em inglês no blog do nosso parceiro SessionStack através &lt;a href=&quot;https://bit.ly/3qTGac2&quot; target=&quot;_blank&quot; rel=&quot;nofollow sponsored noopener noreferrer&quot;&gt;deste link&lt;/a&gt;.&lt;/p&gt;
&lt;p data-selectable-paragraph=&quot;&quot;&gt;Há algumas semanas, começamos uma série que se aprofunda em JavaScript e como ele realmente funciona: pensamos que, conhecendo as peças elementares deste quebra-cabeças, você será capaz de escrever melhor seus códigos e aplicativos.&lt;/p&gt;
&lt;p id=&quot;92cf&quot; data-selectable-paragraph=&quot;&quot;&gt;&lt;a href=&quot;https://bit.ly/3pYkkoU&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;O primeiro post da série&lt;/a&gt; deu uma visão geral do motor, do tempo de execução e da pilha (&lt;em&gt;stack&lt;/em&gt;). Este segundo post se aprofunda nas partes internas do motor JavaScript V8 do Google. Também trazemos algumas dicas rápidas sobre como escrever JavaScript melhor - as melhores práticas que nossa equipe de desenvolvimento na &lt;a href=&quot;https://bit.ly/3eQNJuD&quot; target=&quot;_blank&quot; rel=&quot;nofollow ugc noopener noreferrer&quot;&gt;SessionStack&lt;/a&gt; segue ao construir o produto.&lt;/p&gt;
&lt;h2 id=&quot;e7ca&quot; class=&quot;ib ic dv cd id ie if ig ih ii ij ik il im in io ip iq ir is it iu iv iw ix iy es&quot; data-selectable-paragraph=&quot;&quot;&gt;Visão Geral&lt;/h2&gt;
&lt;p data-selectable-paragraph=&quot;&quot;&gt;O motor JavaScript é um programa (ou interpretador) que executa código JavaScript. Este motor pode ser implementado como um interpretador padrão ou um compilador &lt;em&gt;Just in Time&lt;/em&gt; que transforma JavaScript em um tipo de &lt;em&gt;bytecode&lt;/em&gt;.&lt;/p&gt;
&lt;p id=&quot;893d&quot; data-selectable-paragraph=&quot;&quot;&gt;Aqui vai uma lista de projetos populares que implementam um motor JavaScript:&lt;/p&gt;
&lt;ul class=&quot;&quot;&gt;
&lt;li id=&quot;a2d0&quot; class=&quot;hc hd dv he b hf hg hh hi hj hk hl hm hn ho hp hq hr hs ht hu hv hw hx hy hz jf jg jh es&quot; data-selectable-paragraph=&quot;&quot;&gt;&lt;a class=&quot;cj ia&quot; href=&quot;https://en.wikipedia.org/wiki/V8_(JavaScript_engine)&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;&lt;strong class=&quot;he je&quot;&gt;V8&lt;/strong&gt;&lt;/a&gt; — de código aberto, desenvolvido pelo Google, escrito em C++&lt;/li&gt;
&lt;li id=&quot;5fe1&quot; class=&quot;hc hd dv he b hf ji hh hi hj jj hl hm hn jk hp hq hr jl ht hu hv jm hx hy hz jf jg jh es&quot; data-selectable-paragraph=&quot;&quot;&gt;&lt;a class=&quot;cj ia&quot; href=&quot;https://en.wikipedia.org/wiki/Rhino_(JavaScript_engine)&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;Rhino&lt;/a&gt; — de código aberto, gerenciado pela Mozilla Foundation, escrito em Java&lt;/li&gt;
&lt;li id=&quot;5246&quot; class=&quot;hc hd dv he b hf ji hh hi hj jj hl hm hn jk hp hq hr jl ht hu hv jm hx hy hz jf jg jh es&quot; data-selectable-paragraph=&quot;&quot;&gt;&lt;a class=&quot;cj ia&quot; href=&quot;https://en.wikipedia.org/wiki/SpiderMonkey_(JavaScript_engine)&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;&lt;strong class=&quot;he je&quot;&gt;SpiderMonkey&lt;/strong&gt;&lt;/a&gt; — foi o primeiro motor JavaScript e rodava no navegador Netscape Navigator, e hoje em dia roda no Firefox&lt;/li&gt;
&lt;li id=&quot;9a60&quot; class=&quot;hc hd dv he b hf ji hh hi hj jj hl hm hn jk hp hq hr jl ht hu hv jm hx hy hz jf jg jh es&quot; data-selectable-paragraph=&quot;&quot;&gt;&lt;a class=&quot;cj ia&quot; href=&quot;https://en.wikipedia.org/wiki/JavaScriptCore&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;&lt;strong class=&quot;he je&quot;&gt;JavaScriptCore&lt;/strong&gt;&lt;/a&gt; — de código aberto, desenvolvido pela Apple para o navegador Safari e conhecido como Nitro&lt;/li&gt;
&lt;li id=&quot;09a5&quot; class=&quot;hc hd dv he b hf ji hh hi hj jj hl hm hn jk hp hq hr jl ht hu hv jm hx hy hz jf jg jh es&quot; data-selectable-paragraph=&quot;&quot;&gt;&lt;a class=&quot;cj ia&quot; href=&quot;https://en.wikipedia.org/wiki/KJS_(KDE)&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;&lt;strong class=&quot;he je&quot;&gt;KJS&lt;/strong&gt;&lt;/a&gt; — motor do KDE desenvolvido por Harri Porten para o navegador Konqueror&lt;/li&gt;
&lt;li id=&quot;7bd8&quot; class=&quot;hc hd dv he b hf ji hh hi hj jj hl hm hn jk hp hq hr jl ht hu hv jm hx hy hz jf jg jh es&quot; data-selectable-paragraph=&quot;&quot;&gt;&lt;a class=&quot;cj ia&quot; href=&quot;https://en.wikipedia.org/wiki/Chakra_(JScript_engine)&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;&lt;strong class=&quot;he je&quot;&gt;Chakra&lt;/strong&gt; (JScript9)&lt;/a&gt; — Internet Explorer&lt;/li&gt;
&lt;li id=&quot;897e&quot; class=&quot;hc hd dv he b hf ji hh hi hj jj hl hm hn jk hp hq hr jl ht hu hv jm hx hy hz jf jg jh es&quot; data-selectable-paragraph=&quot;&quot;&gt;&lt;a class=&quot;cj ia&quot; href=&quot;https://en.wikipedia.org/wiki/Chakra_(JavaScript_engine)&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;&lt;strong class=&quot;he je&quot;&gt;Chakra&lt;/strong&gt; (JavaScript)&lt;/a&gt; — Microsoft Edge&lt;/li&gt;
&lt;li id=&quot;722b&quot; class=&quot;hc hd dv he b hf ji hh hi hj jj hl hm hn jk hp hq hr jl ht hu hv jm hx hy hz jf jg jh es&quot; data-selectable-paragraph=&quot;&quot;&gt;&lt;a class=&quot;cj ia&quot; href=&quot;https://en.wikipedia.org/wiki/Nashorn_(JavaScript_engine)&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;&lt;strong class=&quot;he je&quot;&gt;Nashorn&lt;/strong&gt;&lt;/a&gt; — de código aberto e parte do OpenJDK, escrito por Oracle Java Languages and Tool Group&lt;/li&gt;
&lt;li id=&quot;f655&quot; class=&quot;hc hd dv he b hf ji hh hi hj jj hl hm hn jk hp hq hr jl ht hu hv jm hx hy hz jf jg jh es&quot; data-selectable-paragraph=&quot;&quot;&gt;&lt;a class=&quot;cj ia&quot; href=&quot;https://en.wikipedia.org/wiki/JerryScript&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;&lt;strong class=&quot;he je&quot;&gt;JerryScript&lt;/strong&gt;&lt;/a&gt; — motor leve para Internet das Coisas (IoT)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-selectable-paragraph=&quot;&quot;&gt;Por que o motor V8 foi criado?&lt;/h2&gt;
&lt;p data-selectable-paragraph=&quot;&quot;&gt;O motor V8, criado pelo Google, é de código aberto, escrito em C++ e é utilizado pelo navegador Google Chrome. Diferente dos outros motores, V8 também é utilizado pelo ambiente Node.JS.&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/22/1_AKKvE3QmN_ZQmEzSj16oXg.png&quot; alt=&quot;Logo do motor V8&quot; width=&quot;1400&quot; height=&quot;1400&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Logo do motor V8&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-selectable-paragraph=&quot;&quot;&gt;O motor V8 foi desenhado para aumentar a performance da execução de JavaScript em navegadores web. V8 traduz código JavaScript em código de máquina de forma eficiente em vez de utilizar um interpretador.&lt;/p&gt;
&lt;p data-selectable-paragraph=&quot;&quot;&gt;Ele compila código JavaScript em código de máquina utilizando uma técnica chamada &lt;em&gt;JIT (Just-in-Time)&lt;/em&gt;, técnica também utilizada por outros motores JavaScript modernos como o SpiderMonkey ou Rhino (Mozilla). A principal diferença é que o motor V8 não gera nenhum &lt;em&gt;bytecode&lt;/em&gt; ou código intermediário.&lt;/p&gt;
&lt;h2 data-selectable-paragraph=&quot;&quot;&gt;V8 tinha dois compiladores&lt;/h2&gt;
&lt;p data-selectable-paragraph=&quot;&quot;&gt;Antes da versão 5.9 do motor V8 ser lançada (no começo de 2017), o motor utilizava dois compiladores:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;full-codegen — um compilador simples e rápido que produz código de máquina simples e relativamente lento.&lt;/li&gt;
&lt;li&gt;Crankshaft — um compilador de otimizações mais complexo (Just-In-Time) que produz código ultra otimizado.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;O motor V8 também utiliza diferentes threads internamente:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A thread principal (&lt;em&gt;main thread&lt;/em&gt;) faz o que você poderia esperar: pega o seu código JavaScript, compila e executa&lt;/li&gt;
&lt;li&gt;Há também uma thread separada somente para compilação, desta forma a thread principal consegue continuar executando enquanto a anterior otimiza o código&lt;/li&gt;
&lt;li&gt;Uma thread de análise (&lt;em&gt;profiler&lt;/em&gt;) que indica quais métodos são mais utilizados para que Crankshaft possa os otimizar&lt;/li&gt;
&lt;li&gt;Algumas threads para Garbage Collection&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-selectable-paragraph=&quot;&quot;&gt;Quando V8 roda um código JavaScript, o &lt;strong&gt;full-codegen&lt;/strong&gt; é utilizado primeiro para transformar código Javascript em código de máquina sem nenhuma transformação. Isto permite que o motor execute código de máquina &lt;strong&gt;muito rápido&lt;/strong&gt;. Note que V8 não utiliza um bytecode ou representação intermediária, portanto um interpretador não é necessário.&lt;/p&gt;
&lt;p id=&quot;ed80&quot; data-selectable-paragraph=&quot;&quot;&gt;Quando o código já tiver rodado por algum tempo, a thread de análise terá coletado informações o suficiente para dizer quais métodos deveriam ser otimizados.&lt;/p&gt;
&lt;p id=&quot;0b0c&quot; class=&quot;hc hd dv he b hf hg hh hi hj hk hl hm hn ho hp hq hr hs ht hu hv hw hx hy hz dn es&quot; data-selectable-paragraph=&quot;&quot;&gt;Daí otimizações no motor &lt;strong&gt;Crankshaft&lt;/strong&gt; começam a executar em outra thread. Este motor transforma a Árvore de Sintaxe Abstrata (Abstract Syntax Tree, AST) em uma representação estática de atribuição única (static single-assignment, SSA) de alto nível chamada &lt;strong&gt;Hydrogen&lt;/strong&gt; e tenta otimizar este grafo. A maior parte das otimizações acontecem aqui.&lt;/p&gt;
&lt;h2 id=&quot;e273&quot; class=&quot;ib ic dv cd id ie if ig ih ii ij ik il im in io ip iq ir is it iu iv iw ix iy es&quot; data-selectable-paragraph=&quot;&quot;&gt;Código embutido&lt;/h2&gt;
&lt;p data-selectable-paragraph=&quot;&quot;&gt;A primeira otimização é embutir o máximo de código possível de forma antecipada.&lt;/p&gt;
&lt;p data-selectable-paragraph=&quot;&quot;&gt;Veja o snippet abaixo com três funções:&lt;/p&gt;
&lt;p&gt;&lt;img class=&quot;post__image post__image--center&quot; src=&quot;/media/posts/22/js_code-2.png&quot; alt=&quot;&quot; width=&quot;1040&quot; height=&quot;996&quot;&gt;&lt;/p&gt;
&lt;p&gt;Embutir código é o processo de substituir uma chamada de função pelo corpo daquela função chamada. Este passo permite que as otimizações seguintes tenham melhor efeito. O código acima embutido fica assim:&lt;/p&gt;
&lt;p&gt;&lt;img class=&quot;post__image post__image--center&quot; src=&quot;/media/posts/22/js_code_inlined-2.png&quot; alt=&quot;&quot; width=&quot;1040&quot; height=&quot;636&quot;&gt;&lt;/p&gt;
&lt;h2 data-selectable-paragraph=&quot;&quot;&gt;Classes escondidas&lt;/h2&gt;
&lt;p&gt;JavaScript é uma linguagem baseada em protótipos: &lt;strong&gt;não existem classes&lt;/strong&gt; e objetos são criados utilizando um processo de clone. JavaScript também é uma linguagem de programação dinâmica e por isso podemos facilmente adicionar ou remover propriedades de um objeto depois de instanciado.&lt;/p&gt;
&lt;p&gt;A maioria dos interpretadores JavaScript utilizam estruturas parecidas com dicionários (baseadas em &lt;a href=&quot;https://pt.wikipedia.org/wiki/Fun%C3%A7%C3%A3o_hash&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;funções hash&lt;/a&gt;) para gravar a localização dos valores das propriedades em memória. Esta estrutura faz com que obter o valor de uma propriedade em JavaScript seja mais lento do que em linguagens de programação não dinâmicas como Java ou C#.&lt;/p&gt;
&lt;p&gt;Em Java, todas as propriedades de objeto são definidas por um layout fixo antes da compilação e não podem ser adicionadas ou removidas de forma dinâmica em tempo de execução (bom, o C# tem o tipo &lt;a class=&quot;cj ia&quot; href=&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/dynamic&quot; rel=&quot;noopener ugc nofollow&quot; target=&quot;_blank&quot;&gt;dynamic&lt;/a&gt;, mas esta é outra história).&lt;/p&gt;
&lt;p&gt;O resultado é que os valores das propriedades (ou ponteiros para estas propriedades) podem ser armazenados como um buffer contínuo na memória com uma distância fixa entre si. O tamanho desta distância pode ser facilmente determinado pelo tipo da propriedade e isto não é possível com JavaScript já que o tipo de uma propriedade pode mudar em tempo de execução.&lt;/p&gt;
&lt;p data-selectable-paragraph=&quot;&quot;&gt;Já que utilizar dicionários para encontrar propriedades de um objeto em memória é ineficiente, o motor V8 utiliza um método diferente: &lt;strong&gt;classes escondidas&lt;/strong&gt;. Estas classes escondidas funcionam de forma semelhante a estes objetos de layout fixo (classes) em linguagens como Java, só que criados em tempo de execução. Vamos ver como se parecem essas classes:&lt;/p&gt;
&lt;pre class=&quot;jo jp jq jr js kn gi bs&quot;&gt;&lt;span id=&quot;5ece&quot; class=&quot;es ib ic dv ko b kp kq kr s ks&quot; data-selectable-paragraph=&quot;&quot;&gt;function Point(x, y) {&lt;br&gt;    this.x = x;&lt;br&gt;    this.y = y;&lt;br&gt;}&lt;br&gt;&lt;br&gt;&lt;/span&gt;&lt;span id=&quot;283c&quot; class=&quot;es ib ic dv ko b kp kt ku kv kw kx kr s ks&quot; data-selectable-paragraph=&quot;&quot;&gt;var p1 = new Point(1, 2);&lt;/span&gt;&lt;/pre&gt;
&lt;p data-selectable-paragraph=&quot;&quot;&gt;Assim que &lt;code&gt;new Point(1, 2)&lt;/code&gt; é executado, o motor V8 cria uma classe escondida chamada &lt;em&gt;C0&lt;/em&gt;.&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/22/1_pVnIrMZiB9iAz5sW28AixA.png&quot; alt=&quot;Um objeto do tipo Point gera uma classe escondida chamada C0.&quot; width=&quot;1024&quot; height=&quot;768&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Um objeto do tipo &lt;em&gt;Point&lt;/em&gt; gera uma classe escondida chamada &lt;em&gt;C0&lt;/em&gt;.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-selectable-paragraph=&quot;&quot;&gt;Nenhuma propriedade foi definida ainda, então &lt;em&gt;C0&lt;/em&gt; está vazia.&lt;/p&gt;
&lt;p id=&quot;a8b0&quot; data-selectable-paragraph=&quot;&quot;&gt;Assim que o primeiro comando &lt;code&gt;this.x = x&lt;/code&gt; executar (dentro da função &lt;em&gt;Point&lt;/em&gt;), V8 vai criar uma nova classe escondida chamada &lt;em&gt;C1&lt;/em&gt;, que é baseada em &lt;em&gt;C0&lt;/em&gt;. &lt;em&gt;C1&lt;/em&gt; descreve o local em memória (relativo ao ponteiro do objeto) onde a propriedade x pode ser encontrada.&lt;/p&gt;
&lt;p data-selectable-paragraph=&quot;&quot;&gt;Neste caso, &quot;&lt;em&gt;x&lt;/em&gt;&quot; é encontrada no &lt;a href=&quot;http://en.wikipedia.org/wiki/Offset_%28computer_science%29&quot; target=&quot;_blank&quot; rel=&quot;nofollow ugc noopener noreferrer&quot;&gt;deslocamento&lt;/a&gt; (offset) 0 - portanto quando se observar um objeto na memória como um buffer contínuo, o primeiro deslocamento se refere à propriedade &quot;&lt;em&gt;x&quot;&lt;/em&gt;.&lt;/p&gt;
&lt;p data-selectable-paragraph=&quot;&quot;&gt;V8 também atualiza &lt;em&gt;C0&lt;/em&gt; com uma &quot;&lt;em&gt;transição de classe&lt;/em&gt;&quot; que diz que se a propriedade &lt;em&gt;&quot;x&quot;&lt;/em&gt; for adicionada a um objeto &lt;em&gt;Point&lt;/em&gt;, a classe escondida deverá ser trocada de &lt;em&gt;C0&lt;/em&gt; para &lt;em&gt;C1&lt;/em&gt;. A classe escondida no objeto &lt;em&gt;Point&lt;/em&gt; abaixo agora é &lt;em&gt;C1&lt;/em&gt;.&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/22/1_QsVUE3snZD9abYXccg6Sgw.png&quot; alt=&quot;Toda vez que uma nova propriedade for adiciona a um objeto, a antiga classe escondida é atualizada com um caminho de transição para a nova classe escondida. Transições de classes são importante porque elas permitem classes escondidas a serem compartilhadas entre objetos que são criados de forma semelhante. Se dois objetos compartilham a mesma classe escondida e a mesma propriedade é adicionada para os dois objetos, transições vão permitir que os dois objetos recebam a mesma nova classe escondida e todo o código otimizado que ela traz consigo.&quot; width=&quot;1024&quot; height=&quot;768&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Toda vez que uma nova propriedade for adiciona a um objeto, a antiga classe escondida é atualizada com um caminho de transição para a nova classe escondida. Transições de classes são importante porque elas permitem classes escondidas a serem compartilhadas entre objetos que são criados de forma semelhante. Se dois objetos compartilham a mesma classe escondida e a mesma propriedade é adicionada para os dois objetos, transições vão permitir que os dois objetos recebam a mesma nova classe escondida e todo o código otimizado que ela traz consigo.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-selectable-paragraph=&quot;&quot;&gt;Este processo se repete quando o comando &lt;code&gt;this.y = y&lt;/code&gt; é executado (dentro da função &lt;em&gt;Point&lt;/em&gt;, depois que &lt;code&gt;this.x = x&lt;/code&gt; executa).&lt;/p&gt;
&lt;p id=&quot;6259&quot; data-selectable-paragraph=&quot;&quot;&gt;Uma nova classe escondida chamada &lt;em&gt;C2&lt;/em&gt; é criada, uma transição de classe é adicionada à &lt;em&gt;C1&lt;/em&gt; dizendo que se uma propriedade &lt;em&gt;y&lt;/em&gt; for adicionada ao objeto &lt;em&gt;Point&lt;/em&gt; (que já possui uma propriedade &lt;em&gt;x&lt;/em&gt;) então a classe escondida deverá mudar para &lt;em&gt;C2&lt;/em&gt; e a classe escondida do objeto &lt;em&gt;p1&lt;/em&gt; passa a ser &lt;em&gt;C2&lt;/em&gt;.&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/22/1_spJ8v7GWivxZZzTAzqVPtA.png&quot; alt=&quot;Um objeto do tipo Point que inicialmente possui uma classe escondida C0 e transita para as classes C1 e C2 assim que as propriedades x e y são adicionadas.&quot; width=&quot;1024&quot; height=&quot;768&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Um objeto do tipo &lt;em&gt;Point&lt;/em&gt; que inicialmente possui uma classe escondida &lt;em&gt;C0&lt;/em&gt; e transita para as classes &lt;em&gt;C1&lt;/em&gt; e &lt;em&gt;C2&lt;/em&gt; assim que as propriedades &lt;em&gt;x&lt;/em&gt; e &lt;em&gt;y&lt;/em&gt; são adicionadas.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-selectable-paragraph=&quot;&quot;&gt;Transformações de classes escondidas dependem da ordem em que as propriedades são adicionadas a um objeto. Vejamos o código abaixo:&lt;/p&gt;
&lt;pre class=&quot;jo jp jq jr js kn gi bs&quot;&gt;&lt;span id=&quot;ff18&quot; class=&quot;es ib ic dv ko b kp kq kr s ks&quot; data-selectable-paragraph=&quot;&quot;&gt;function Point(x, y) {&lt;br&gt;    this.x = x;&lt;br&gt;    this.y = y;&lt;br&gt;}&lt;br&gt;&lt;br&gt;&lt;/span&gt;&lt;span id=&quot;4633&quot; class=&quot;es ib ic dv ko b kp kt ku kv kw kx kr s ks&quot; data-selectable-paragraph=&quot;&quot;&gt;var p1 = new Point(1, 2);&lt;br&gt;p1.a = 5;&lt;br&gt;p1.b = 6;&lt;br&gt;&lt;br&gt;&lt;/span&gt;&lt;span id=&quot;af52&quot; class=&quot;es ib ic dv ko b kp kt ku kv kw kx kr s ks&quot; data-selectable-paragraph=&quot;&quot;&gt;var p2 = new Point(3, 4);&lt;br&gt;p2.b = 7;&lt;br&gt;p2.a = 8;&lt;/span&gt;&lt;/pre&gt;
&lt;p data-selectable-paragraph=&quot;&quot;&gt;É natural pensar que os objetos &lt;em&gt;p1&lt;/em&gt; e &lt;em&gt;p2&lt;/em&gt; utilizariam as mesmas classes escondidas e transições, mas não é isso o que acontece. Para &lt;em&gt;p1&lt;/em&gt;, a propriedade &lt;em&gt;a&lt;/em&gt; é inserida primeiro e depois inserimos a propriedade &lt;em&gt;b&lt;/em&gt;. Para o objeto &lt;em&gt;p2&lt;/em&gt;, a propriedade &lt;em&gt;b&lt;/em&gt; é inserida primeiro e só então a propriedade &lt;em&gt;a&lt;/em&gt; é inserida. Desta forma &lt;em&gt;p1&lt;/em&gt; e &lt;em&gt;p2&lt;/em&gt; geram classes escondidas e transições diferentes, já que suas propriedades foram inseridas em ordem diferente.&lt;/p&gt;
&lt;p class=&quot;msg msg--highlight &quot; data-selectable-paragraph=&quot;&quot;&gt;Neste caso é muito melhor inicializar propriedades dinâmicas na mesma ordem para que as mesmas classes escondidas sejam reutilizadas.&lt;/p&gt;
&lt;h2 id=&quot;47e8&quot; class=&quot;ib ic dv cd id ie if ig ih ii ij ik il im in io ip iq ir is it iu iv iw ix iy es&quot; data-selectable-paragraph=&quot;&quot;&gt;Inline caching&lt;/h2&gt;
&lt;p&gt;O motor V8 utiliza ainda uma outra técnica de otimização para linguagens dinamicamente tipadas chamada &lt;em&gt;Inline Caching&lt;/em&gt;. &lt;em&gt;Inline Caching &lt;/em&gt;assume que chamadas repetidas ao mesmo objeto costumam ocorrer com o mesmo tipo de objeto. Você pode ler mais sobre isso &lt;a href=&quot;https://github.com/sq/JSIL/wiki/Optimizing-dynamic-JavaScript-with-inline-caches&quot; target=&quot;_blank&quot; rel=&quot;nofollow ugc noopener noreferrer&quot;&gt;aqui&lt;/a&gt;.&lt;/p&gt;
&lt;p id=&quot;fcf5&quot; class=&quot;hc hd dv he b hf hg hh hi hj hk hl hm hn ho hp hq hr hs ht hu hv hw hx hy hz dn es&quot; data-selectable-paragraph=&quot;&quot;&gt;Como isso funciona? O motor V8 mantem um cache dos tipos de objetos passados por parâmetro em chamadas de método recentes e usa esta informação pra assumir qual o tipo do objeto que será passado no futuro. Se o motor V8 for capaz de assumir corretamente o tipo do objeto que será passado, ele pode pular o processo de entender como acessar as propriedades de um objeto e, em vez disso, usar a informação armazenada das classes escondidas dos últimos objetos utilizados como parâmetro.&lt;/p&gt;
&lt;p data-selectable-paragraph=&quot;&quot;&gt;Como os conceitos de classe escondida e &lt;em&gt;inline caching &lt;/em&gt;se relacionam?&lt;/p&gt;
&lt;p data-selectable-paragraph=&quot;&quot;&gt;Sempre que um método é chamado num objeto específico, o motor V8 precisa identificar a classe escondida para entender como acessar suas propriedades em memória. Depois de duas chamadas ao mesmo método passando a mesma classe escondida, V8 passar a pular o processo de identificar a classe escondida e adiciona um ponteiro para a propriedade do objeto em si. Para todas as chamadas futuras a este método, o motor V8 assume que a classe escondida não mudou, e pula diretamente para o endereço de memória da propriedade específica utilizando deslocamentos (offsets) das últimas chamadas.&lt;/p&gt;
&lt;p data-selectable-paragraph=&quot;&quot;&gt;Isso aumenta em muito a velocidade de execução.&lt;/p&gt;
&lt;p data-selectable-paragraph=&quot;&quot;&gt;&lt;em&gt;Inline caching&lt;/em&gt; é outra razão pela qual é tão importante que objetos compartilhem as mesmas classes escondidas.&lt;/p&gt;
&lt;p data-selectable-paragraph=&quot;&quot;&gt;Se você criar dois objetos do mesmo tipo com classes escondidas diferentes (como fizemos anteriormente), o motor V8 não será capaz de realizar o &lt;em&gt;inline caching&lt;/em&gt; porque mesmo que os dois objetos sejam do mesmo tipo, as classes escondidas destes objetos possuem deslocamentos (offsets) diferentes para suas propriedades.&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/22/1_iHfI6MQ-YKQvWvo51J-P0w.png&quot; alt=&quot;Os dois objetos são basicamente os mesmos, mas as propriedades a e b foram criadas em ordem diferentes.&quot; width=&quot;1024&quot; height=&quot;768&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Os dois objetos são basicamente os mesmos, mas as propriedades &lt;em&gt;a&lt;/em&gt; e &lt;em&gt;b&lt;/em&gt; foram criadas em ordem diferentes.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 data-selectable-paragraph=&quot;&quot;&gt;Compilação para código de máquina&lt;/h2&gt;
&lt;p data-selectable-paragraph=&quot;&quot;&gt;Assim que o grafo &lt;em&gt;Hydrogen&lt;/em&gt; é otimizado, &lt;em&gt;Crankshaft&lt;/em&gt; o traduz para uma representação de baixo nível chamada &lt;em&gt;Lithium&lt;/em&gt;. A maior parte da implementação de &lt;em&gt;Lithium&lt;/em&gt; é específica para a arquitetura do computador em que roda. A alocação de registradores acontece neste nível.&lt;/p&gt;
&lt;p id=&quot;eed5&quot; data-selectable-paragraph=&quot;&quot;&gt;Por fim, &lt;em&gt;Lithium&lt;/em&gt; é compilado para código de máquina. E então um outro processo chamado Substituição na Pilha (on-stack replacement, OSR) acontece.&lt;/p&gt;
&lt;p data-selectable-paragraph=&quot;&quot;&gt;Antes de começarmos a compilar e otimizar um método lento, nós provavelmente estávamos executando este método. O motor V8 não vai simplesmente esquecer a implementação lenta e começar a utilizar a implementação otimizada. Em vez disso, o motor transforma todo o contexto que temos (pilha, registradores) para que possamos mudar de implementação em tempo de execução.&lt;/p&gt;
&lt;p data-selectable-paragraph=&quot;&quot;&gt;Esta é uma tarefa complexa, dado que dentre outras otimizações, o motor V8 já embutiu código anteriormente. V8 não é o único motor capaz de utilizar a técnica de OSR.&lt;/p&gt;
&lt;p id=&quot;6461&quot; class=&quot;hc hd dv he b hf hg hh hi hj hk hl hm hn ho hp hq hr hs ht hu hv hw hx hy hz dn es&quot; data-selectable-paragraph=&quot;&quot;&gt;Há alguns mecanismos de segurança para reverter uma otimizações caso alguma suposição que o motor vez não seja mais verdadeira.&lt;/p&gt;
&lt;h2 data-selectable-paragraph=&quot;&quot;&gt;Coleta de lixo&lt;/h2&gt;
&lt;p data-selectable-paragraph=&quot;&quot;&gt;Para a coleta de lixo (garbage collection), o motor V8 utiliza o tradicional método &quot;marque e limpe&quot;.&lt;/p&gt;
&lt;p data-selectable-paragraph=&quot;&quot;&gt;&lt;em&gt;A fase de demarcar bloqueia a execução do JavaScript.&lt;/em&gt;&lt;/p&gt;
&lt;p data-selectable-paragraph=&quot;&quot;&gt;Para controlar os custos da coleta de lixo e tornar a execução mais estável, o motor V8 utiliza marcação incremental: em vez de iterar toda a &lt;em&gt;heap&lt;/em&gt; e tentar marcar tudo quanto é objeto, o motor itera apenas uma parte da &lt;em&gt;heap&lt;/em&gt; e depois volta a executar o código JavaScript. A próxima coleta de lixo continua de onde a última iteração da &lt;em&gt;heap&lt;/em&gt; parou.&lt;/p&gt;
&lt;p data-selectable-paragraph=&quot;&quot;&gt;Isso permite pequenas pausas durante a execução normal. Como mencionado antes, a faze de limpar o que foi marcado acontece em threads distintas.&lt;/p&gt;
&lt;h2 data-selectable-paragraph=&quot;&quot;&gt;Ignition e TurboFan&lt;/h2&gt;
&lt;p&gt;Com o release da V8 5.9 no começo 2017, uma estratégia de execução foi introduzida ao motor. Esta nova estratégia alcança ainda maiores melhorias em performance e menor utilização de memória em aplicações JavaScript &lt;strong&gt;reais&lt;/strong&gt;.&lt;/p&gt;
&lt;p id=&quot;d204&quot; class=&quot;hc hd dv he b hf iz hh hi hj ja hl hm hn jb hp hq hr jc ht hu hv jd hx hy hz dn es&quot; data-selectable-paragraph=&quot;&quot;&gt;A nova estratégia de execução é baseada no novo &lt;a href=&quot;https://github.com/v8/v8/wiki/Interpreter&quot; target=&quot;_blank&quot; rel=&quot;nofollow ugc noopener noreferrer&quot;&gt;interpretador do motor V8, Ignition&lt;/a&gt;, e o novo compilador de otimizações &lt;a class=&quot;cj ia&quot; href=&quot;https://github.com/v8/v8/wiki/TurboFan&quot; rel=&quot;noopener ugc nofollow&quot; target=&quot;_blank&quot;&gt;TurboFan&lt;/a&gt;.&lt;/p&gt;
&lt;p id=&quot;047e&quot; class=&quot;hc hd dv he b hf hg hh hi hj hk hl hm hn ho hp hq hr hs ht hu hv hw hx hy hz dn es&quot; data-selectable-paragraph=&quot;&quot;&gt;&lt;a href=&quot;https://v8project.blogspot.bg/2017/05/launching-ignition-and-turbofan.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow ugc noopener noreferrer&quot;&gt;Você pode ver o post sobre este tópico, escrito pelo time que desenvolve o motor V8 neste link.&lt;/a&gt;&lt;/p&gt;
&lt;p data-selectable-paragraph=&quot;&quot;&gt;Desde a versão 5.9 do motor V8, &lt;strong&gt;full-codegen&lt;/strong&gt; e &lt;strong&gt;Crankshaft&lt;/strong&gt; (tecnologias utilizadas no motor V8 desde 2010) não foram mais usadas pelo motor para execução de JavaScript já que o time V8 não consegue facilmente adicionar as novas funcionalidades da linguagem JavaScript e manter as otimizações necessárias para estas funcionalidades.&lt;/p&gt;
&lt;p data-selectable-paragraph=&quot;&quot;&gt;Isto significa que o motor V8 manterá uma arquitetura muito mais simples e de fácil manutenção daqui pra frente.&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/22/0_pohqKvj9psTPRlOv.png&quot; alt=&quot;Benchmarks executados em navegadores Web e no Node.JS.&quot; width=&quot;640&quot; height=&quot;395&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Benchmarks executados em navegadores Web e no Node.JS.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-selectable-paragraph=&quot;&quot;&gt;Estas melhorias são só o começo. A nova estratégia &lt;strong&gt;Ignition&lt;em&gt; &lt;/em&gt;&lt;/strong&gt;e &lt;strong&gt;TurboFan&lt;/strong&gt; moldaram o caminho para outras otimizações que vão melhorar ainda mais a performance do JavaScript e diminuir o consumo de recursos do motor V8 no navegador Chrome e no ambiente Node.JS pelos próximos anos.&lt;/p&gt;
&lt;p data-selectable-paragraph=&quot;&quot;&gt;Por fim, aqui vão algumas dicas e truques sobre como escrever JavaScript otimizado. Você pode derivar estas dicas do texto que leu, mas aqui vai um resumo pra você:&lt;/p&gt;
&lt;h2 data-selectable-paragraph=&quot;&quot;&gt;5 Dicas para escrever JavaScript otimizado&lt;/h2&gt;
&lt;ol class=&quot;&quot;&gt;
&lt;li data-selectable-paragraph=&quot;&quot;&gt;&lt;strong&gt;Ordem das propriedades dos objetos:&lt;/strong&gt; sempre instancie as propriedades de seus objetos na mesma ordem para que classes escondidas, e posteriormente código otimizado, possam ser compartilhados.&lt;/li&gt;
&lt;li data-selectable-paragraph=&quot;&quot;&gt;&lt;strong&gt;Propriedades dinâmicas:&lt;/strong&gt; adicionar propriedades à um objeto após instanciação vai forçar a classe escondida a mudar e diminuir a performance de qualquer método que esteja otimizado para a classe escondida anterior. Em vez disso, adicione todas as propriedades de um objeto em seu construtor.&lt;/li&gt;
&lt;li id=&quot;8e17&quot; class=&quot;hc hd dv he b hf ji hh hi hj jj hl hm hn jk hp hq hr jl ht hu hv jm hx hy hz li jg jh es&quot; data-selectable-paragraph=&quot;&quot;&gt;&lt;strong&gt;Métodos:&lt;/strong&gt; um código que execute o mesmo método várias vezes executa mais rápido do que um código que rode vários métodos diferentes apenas uma vez, por causa do &lt;em&gt;inline caching&lt;/em&gt;.&lt;/li&gt;
&lt;li id=&quot;4684&quot; class=&quot;hc hd dv he b hf ji hh hi hj jj hl hm hn jk hp hq hr jl ht hu hv jm hx hy hz li jg jh es&quot; data-selectable-paragraph=&quot;&quot;&gt;&lt;strong&gt;Arrays:&lt;/strong&gt; evite arrays em que as chaves não sejam números em sequência. Arrays não sequenciais são tratados como uma &lt;strong&gt;hash table&lt;/strong&gt;. Elementos nestes arrays são mais difíceis de acessar. É bom também evitar pré alocar arrays grandes. É melhor aumentar o tamanho do array conforme for necessário. Por fim, não remova elementos em arrays. Remover elementos torna os arrays descontínuos (os transforma em &lt;strong&gt;hash tables&lt;/strong&gt;).&lt;/li&gt;
&lt;li data-selectable-paragraph=&quot;&quot;&gt;&lt;strong&gt;Valores inteiros:&lt;/strong&gt; o motor V8 representa objetos e números utilizando 32 bits. Um desses bits é utilizado como flag para entender se aquele espaço de memória é um objeto (flag = 1) ou um inteiro (flag = 0). Este inteiro então só pode possuir 31 bits e é chamado de Inteiro Pequeno (Small Integer, SMI). Se um valor numérico for maior do que os 31 bits conseguem representar, o motor V8 vai encapsular este número, transformando-o em um double e criando um novo objeto para alocar o número dentro. Tente utilizar números de 31 bits sempre que possível para evitar estas operações de encapsulamento.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-selectable-paragraph=&quot;&quot;&gt;Nós da SessionStack tentamos seguir estas melhores praticas quando escrevemos código JavaScript super otimizado. O motivo pelo qual buscamos estas práticas é que assim que você integrar SessionStack no seu aplicativo em produção, ele grava tudo: mudanças no DOM, interações de usuários, erros de JavaScript, stack traces, chamadas de rede que falharam e mensagens de depuração. Com SessionStack você pode reproduzir problemas da sua aplicação como se fossem vídeos e ver tudo o que aconteceu com seu usuário. E tudo isso precisa acontecer sem causar nenhum impacto na sua aplicação.&lt;br&gt;Nós temos um plano gratuito que te permite &lt;a href=&quot;https://bit.ly/3EYRnNw&quot; target=&quot;_blank&quot; rel=&quot;nofollow ugc noopener noreferrer&quot;&gt;começar de graça&lt;/a&gt;.&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/22/1_kEQmoMuNBDfZKNSBh0tvRA.png&quot; alt=&quot;Ilustração de como o software SessionStack permite reproduzir vídeos da sessão de seus usuários.&quot; width=&quot;1031&quot; height=&quot;573&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Ilustração de como o software SessionStack permite reproduzir vídeos da sessão de seus usuários.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;9cdf&quot; class=&quot;ib ic dv cd id ie if ig ih ii ij ik il im in io ip iq ir is it iu iv iw ix iy es&quot; data-selectable-paragraph=&quot;&quot;&gt;Fontes&lt;/h2&gt;
&lt;ul class=&quot;&quot;&gt;
&lt;li id=&quot;1625&quot; class=&quot;hc hd dv he b hf iz hh hi hj ja hl hm hn jb hp hq hr jc ht hu hv jd hx hy hz jf jg jh es&quot; data-selectable-paragraph=&quot;&quot;&gt;&lt;a class=&quot;cj ia&quot; href=&quot;https://docs.google.com/document/u/1/d/1hOaE7vbwdLLXWj3C8hTnnkpE0qSa2P--dtDvwXXEeD0/pub&quot; rel=&quot;noopener ugc nofollow&quot; target=&quot;_blank&quot;&gt;https://docs.google.com/document/u/1/d/1hOaE7vbwdLLXWj3C8hTnnkpE0qSa2P--dtDvwXXEeD0/pub&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;76b2&quot; class=&quot;hc hd dv he b hf ji hh hi hj jj hl hm hn jk hp hq hr jl ht hu hv jm hx hy hz jf jg jh es&quot; data-selectable-paragraph=&quot;&quot;&gt;&lt;a class=&quot;cj ia&quot; href=&quot;https://github.com/thlorenz/v8-perf&quot; rel=&quot;noopener ugc nofollow&quot; target=&quot;_blank&quot;&gt;https://github.com/thlorenz/v8-perf&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;b6aa&quot; class=&quot;hc hd dv he b hf ji hh hi hj jj hl hm hn jk hp hq hr jl ht hu hv jm hx hy hz jf jg jh es&quot; data-selectable-paragraph=&quot;&quot;&gt;&lt;a class=&quot;cj ia&quot; href=&quot;http://code.google.com/p/v8/wiki/UsingGit&quot; rel=&quot;noopener ugc nofollow&quot; target=&quot;_blank&quot;&gt;http://code.google.com/p/v8/wiki/UsingGit&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;0300&quot; class=&quot;hc hd dv he b hf ji hh hi hj jj hl hm hn jk hp hq hr jl ht hu hv jm hx hy hz jf jg jh es&quot; data-selectable-paragraph=&quot;&quot;&gt;&lt;a class=&quot;cj ia&quot; href=&quot;http://mrale.ph/v8/resources.html&quot; rel=&quot;noopener ugc nofollow&quot; target=&quot;_blank&quot;&gt;http://mrale.ph/v8/resources.html&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;e386&quot; class=&quot;hc hd dv he b hf ji hh hi hj jj hl hm hn jk hp hq hr jl ht hu hv jm hx hy hz jf jg jh es&quot; data-selectable-paragraph=&quot;&quot;&gt;&lt;a class=&quot;cj ia&quot; href=&quot;https://www.youtube.com/watch?v=UJPdhx5zTaw&quot; rel=&quot;noopener ugc nofollow&quot; target=&quot;_blank&quot;&gt;https://www.youtube.com/watch?v=UJPdhx5zTaw&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;bf00&quot; class=&quot;hc hd dv he b hf ji hh hi hj jj hl hm hn jk hp hq hr jl ht hu hv jm hx hy hz jf jg jh es&quot; data-selectable-paragraph=&quot;&quot;&gt;&lt;a class=&quot;cj ia&quot; href=&quot;https://www.youtube.com/watch?v=hWhMKalEicY&quot; rel=&quot;noopener ugc nofollow&quot; target=&quot;_blank&quot;&gt;https://www.youtube.com/watch?v=hWhMKalEicY&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>gringo</category><category>javascript</category></item><item><title>Devlog #00: Emulador NES (nintendinho), arquitetura</title><link>https://codamos.com.br/devlog-emulador-nes-arquitetura/</link><guid isPermaLink="true">https://codamos.com.br/devlog-emulador-nes-arquitetura/</guid><description>Atenção! Para que este DevLog avance eu preciso da sua ajuda não financeira : Dê retuíte neste post e compartilhe com colegas e quem mais se interessar. Somente após 50 RTs eu vou escrever o próximo p</description><pubDate>Fri, 31 Dec 2021 16:27:32 GMT</pubDate><content:encoded>&lt;p class=&quot;msg msg--highlight &quot;&gt;&lt;strong&gt;Atenção!&lt;/strong&gt; Para que este DevLog avance &lt;strong&gt;eu preciso da sua ajuda não financeira&lt;/strong&gt;: Dê &lt;a href=&quot;https://twitter.com/nawarian/status/1478343680293539845&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;retuíte neste post&lt;/a&gt; e compartilhe com colegas e quem mais se interessar. &lt;strong&gt;Somente após 50 RTs eu vou escrever o próximo post&lt;/strong&gt;. Esta é uma forma fácil e barata de você nos ajudar o projeto codamos.com.br a crescer ao mesmo tempo que ganha um conteúdo exclusivo e de qualidade em português.&lt;/p&gt;
&lt;div class=&quot;post__toc&quot;&gt;
&lt;h3&gt;Conteúdo deste post&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo8kvr6t17q&quot;&gt;Objetivo deste projeto&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo8kvr6t17r&quot;&gt;Ferramentas utilizadas no projeto&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo8kvr6t17s&quot;&gt;Visão geral: arquitetura do NES&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo8kvr6t17t&quot;&gt;BUS ou barramento&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo8kvr6t17u&quot;&gt;CPU: central processing unit ou unidade central de processamento&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo8kvr6t17v&quot;&gt;PPU: picture processing unit ou unidade de processamento de imagens&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo8kvr6t180&quot;&gt;APU: audio processing unit ou unidade de processamento de áudio&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo8kvr6t181&quot;&gt;Visão geral da arquitetura&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo8kvr6t182&quot;&gt;Próximos passos&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p&gt;Há alguns bons meses eu decidi que vou escrever meu próprio emulador NES (Nintendinho 8-bits). O desafio parece interessante o suficiente e vai me manter ocupado por um tempo razoável.&lt;/p&gt;
&lt;p&gt;De lá pra cá eu estudei e aprendi bastante coisa sobre a plataforma NES. Visitando materiais como a wiki do &lt;a href=&quot;https://www.nesdev.org/&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;NESDev.com&lt;/a&gt;, a incrível série de vídeos do &lt;a href=&quot;https://www.youtube.com/playlist?list=PLrOv9FMX8xJHqMvSGB_9G9nZZ_4IgteYf&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;One Lone Coder&lt;/a&gt; e outros emuladores de código aberto.&lt;/p&gt;
&lt;p&gt;Espero que desta vez eu consiga atingir maior sucesso e não abandone o projeto. Este Devlog vai me ajudar a tomar nota do meu progresso e não abandonar o projeto, ao mesmo tempo eu devo lançar mais conteúdo interessante pra vocês.&lt;/p&gt;
&lt;p&gt;Eu pretendo também utilizar as ideias do &lt;a href=&quot;/tdl-aprendizado-por-testes/&quot;&gt;Aprendizado Guiado por Testes&lt;/a&gt;: Introduzir, descobrir, testar, aprender, repetir. Portanto todo capítulo deste DevLog deve seguir mais ou menos esta estrutura.&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1fo8kvr6t17q&quot;&gt;Objetivo deste projeto&lt;/h2&gt;
&lt;p&gt;O objetivo maior deste emulador é conseguir rodar a ROM do jogo Super Mario Bros.. Esta ROM deverá executar com vídeo, áudio e controles.&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1fo8kvr6t17r&quot;&gt;Ferramentas utilizadas no projeto&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Linguagem: C, padrão C99&lt;/li&gt;
&lt;li&gt;Compilador: clang&lt;/li&gt;
&lt;li&gt;Biblioteca de GUI: raylib&lt;/li&gt;
&lt;li&gt;Ferramenta de build: Make&lt;/li&gt;
&lt;li&gt;Integração Contínua: Github Actions&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Eu quero MUITO desenvolver o emulador NES em PHP, mas a princípio não faz muito sentido: eu precisaria fazer muita coisa específica em PHP para desenvolver o básico que outras linguagens já oferecem. Então para esta versão, PHP não é a minha ferramenta.&lt;/p&gt;
&lt;p&gt;Eu tenho estudado Rust e C nestes últimos 2 anos e acho que já atingi um nível de proficiência decente com as duas linguagens. A minha escolha aqui vai ser a linguagem C pela simplicidade da sintaxe. Como estou rodando um MacOS, o compilador mais confortável pra mim será o &lt;em&gt;clang&lt;/em&gt;, mas pretendo utilizar o padrão C99 para evitar incompatibilidades.&lt;/p&gt;
&lt;p&gt;Como engine gráfica eu poderia então utilizar o OpenGL ou SDL. Como eu quero evitar perder tempo escrevendo a minha própria abstração, vou utilizar uma biblioteca de alto nível: a &lt;a href=&quot;https://www.raylib.com/&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;raylib&lt;/a&gt;. Talvez numa segunda iteração eu isole melhor o tratamento de áudio e vídeo para que possa facilmente trocar a biblioteca.&lt;/p&gt;
&lt;p&gt;Por fim, eu não imagino que o projeto vá crescer muito em número de arquivos, então uma build simples usando &lt;em&gt;Make&lt;/em&gt; já deverá ser o suficiente.&lt;/p&gt;
&lt;p&gt;Para garantir que nenhuma regressão inesperada aconteça, eu vou utilizar uma ferramenta de Integração Contínua. Acho que Github Actions já será suficiente para o meu caso de uso.&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1fo8kvr6t17s&quot;&gt;Visão geral: arquitetura do NES&lt;/h2&gt;
&lt;p&gt;Há três componentes essenciais em um emulador NES: CPU (unidade central de processamento), PPU (unidade de processamento de imagens), APU (unidade de processamento de áudio). Há mais elementos a serem emulados, mas estes três são os essenciais para alcançar o meu objetivo.&lt;/p&gt;
&lt;p&gt;Estes componentes se comunicam através do barramento (BUS).&lt;/p&gt;
&lt;p&gt;Por fim, os programas são carregados a partir de ROMs. ROMs são na realidade cópias dos programas gravados nos cartuchos.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fo8kvr6t17t&quot;&gt;BUS ou barramento&lt;/h3&gt;
&lt;p&gt;Este componente é o mais simples de emular porque é basicamente o acesso a memória entre os componentes.&lt;/p&gt;
&lt;p&gt;O barramento (ou memory bus) é o que permite a CPU gravar uma sequência de bytes no endereço A e outro componente, como a PPU, ler esta sequência de bytes e interpretar como uma imagem ou algo assim.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fo8kvr6t17u&quot;&gt;CPU: central processing unit ou unidade central de processamento&lt;/h3&gt;
&lt;p&gt;Emular a CPU do NES será quase equivalente a emular o chip 6502. Este é o microprocessador utilizado neste console.&lt;/p&gt;
&lt;p&gt;Este processador naturalmente possui algumas instruções que podem ser descritas na linguagem Assembly. Como &lt;em&gt;LDA&lt;/em&gt;, &lt;em&gt;STA&lt;/em&gt;, &lt;em&gt;PHP&lt;/em&gt; entre outras. Mais detalhes no post sobre a emulação da CPU.&lt;/p&gt;
&lt;p&gt;Dentre todos os componentes este é o mais complexo porque possui muitas instruções, modos de endereçamento e comportamentos complexos.&lt;/p&gt;
&lt;p&gt;Um erro aqui muitas vezes é silencioso e difícil de capturar. Em alguns casos determinado bug só se materializa com uma ROM específica, em condições específicas. Quanto mais testes e cobertura tivermos aqui, melhor.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fo8kvr6t17v&quot;&gt;PPU: picture processing unit ou unidade de processamento de imagens&lt;/h3&gt;
&lt;p&gt;Este componente é responsável por ler trechos específicos da memória e traduzir em vídeo.&lt;/p&gt;
&lt;p&gt;Em termos de esforço deverá ser bem menor do que a emulação da CPU, mas com certeza é o mais complexo.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fo8kvr6t180&quot;&gt;APU: audio processing unit ou unidade de processamento de áudio&lt;/h3&gt;
&lt;p&gt;Semelhante ao PPU, este componente é capaz de sintetizar os áudios dos jogos: traduzir pedaços de memória em som.&lt;/p&gt;
&lt;p&gt;Eu ainda não estudei sobre o APU, então não possui muitos detalhes sobre como este componente funciona. Vamos descobrir mais no futuro.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fo8kvr6t181&quot;&gt;Visão geral da arquitetura&lt;/h3&gt;
&lt;p&gt;Com a imagem abaixo eu tento descrever o modelo que eu tenho cristalizado sobre a arquitetura do NES.&lt;/p&gt;
&lt;p&gt;O barramento (BUS) é o que conecta todos os outros componentes.&lt;/p&gt;
&lt;p&gt;A ROM possui um programa que é carregado para a memória, de forma que o conteúdo da ROM fica disponível no Barramento (BUS) para que outros componentes possam acessar.&lt;/p&gt;
&lt;p&gt;A CPU é responsável por executar instruções, que são carregadas a partir de uma ROM.&lt;/p&gt;
&lt;p&gt;A PPU é responsável por pintar na tela o estado atual da aplicação (jogo). O programa (definido na ROM) define em quais endereços de memória gravar quais bytes, e a PPU sabe exatamente quais áreas da memória acessar para pintar a tela. A APU provavelmente opera de forma semelhante.&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/20/nes-arquitetura-2.png&quot; alt=&quot;O barramento (BUS) conecta todos os outros componentes do NES.&quot; width=&quot;432&quot; height=&quot;390&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;O barramento (BUS) conecta todos os outros componentes do NES.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;mcetoc_1fo8kvr6t182&quot;&gt;Próximos passos&lt;/h2&gt;
&lt;p&gt;A visão geral foi dada, agora é preciso colocar a mão na massa.&lt;/p&gt;
&lt;p&gt;No próximo post eu vou preparar o repositório no Github e configurar o Github Actions para executar uma build simples.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded><category>c</category><category>devlog</category><category>emulador-nes</category></item><item><title>Comandos e atalhos do editor VIM para iniciantes</title><link>https://codamos.com.br/vim-basico/</link><guid isPermaLink="true">https://codamos.com.br/vim-basico/</guid><description>O meu foco aqui é te mostrar que VIM pode te trazer muita produtividade no desenvolvimento de software. Aqui tem um vídeo meu sobre como utilizar FFI em PHP, onde eu programo tudo utilizando VIM. Nele</description><pubDate>Wed, 29 Dec 2021 16:31:38 GMT</pubDate><content:encoded>&lt;p&gt;O meu foco aqui é te mostrar que VIM pode te trazer muita produtividade no desenvolvimento de software. Aqui tem um vídeo meu sobre como utilizar FFI em PHP, onde eu programo tudo utilizando VIM. Nele você pode reparar que a ferramenta me serviu muito bem para prototipar o programa e que é possível mover relativamente rápido entre um arquivo e outro.&lt;/p&gt;
&lt;p&gt;&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/wPbnjcvW-Tk&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;allowfullscreen&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p&gt;Mais tarde eu acabei migrando para o &lt;em&gt;PhpStorm&lt;/em&gt; naturalmente, porque é a minha ferramenta de preferência para desenvolver com PHP.&lt;/p&gt;
&lt;div class=&quot;post__toc&quot;&gt;
&lt;h3&gt;Conteúdo do post&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo3h03cl251&quot;&gt;O que é VIM?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo3h03cl252&quot;&gt;Pra quê aprender a utilizar vim?&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo3h03cl253&quot;&gt;Abrir arquivos grandes sem travar o computador&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo3h03cl254&quot;&gt;Há situações em que não é possível utilizar uma IDE&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo3h03cl255&quot;&gt;VIM está preparado para trabalhar com quase todas linguagens de programação&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo3uq4b43hk&quot;&gt;Você pode adicionar funcionalidades ao VIM com a linguagem que quiser&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo3h03cl256&quot;&gt;Filosofia VIM&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo3uq4b43hl&quot;&gt;Não tire as mãos do teclado&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo3uq4b43hm&quot;&gt;Evite repetições&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo3h03cl257&quot;&gt;Primeiros passos com VIM&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo42nnu54t5&quot;&gt;Como abrir um arquivo (novo ou existente) com o VIM&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo3h03cl259&quot;&gt;Como fechar um arquivo no VIM&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo3uq4b43ho&quot;&gt;Como abrir um arquivo com o VIM já aberto&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo3h03cl25a&quot;&gt;Edição de texto&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo3h03cl25b&quot;&gt;Como navegar no texto&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo42nnu54t6&quot;&gt;Como mostrar as linhas do documento&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo42nnu54t7&quot;&gt;Mover o cursor para uma linha específica&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo42nnu54t8&quot;&gt;Mover o cursor linha a linha ou coluna a coluna&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo42nnu54t9&quot;&gt;Mover para o começo ou fim da linha&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo42nnu54ta&quot;&gt;Pular palavras para frente e para trás&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo3h03cl25c&quot;&gt;Buscar conteúdo no VIM&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo43obg450e&quot;&gt;Ainda tem muito chão pela frente&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id=&quot;mcetoc_1fo3h03cl251&quot;&gt;O que é VIM?&lt;/h2&gt;
&lt;p&gt;VIM é um editor de texto livre, grátis, simples, leve e robusto.&lt;/p&gt;
&lt;p&gt;É comum utilizar VIM dentro de um terminal ou emulador de terminal, mas também é possível usar a aplicação gráfica do VIM chamada gVIM.&lt;/p&gt;
&lt;p&gt;Você encontra os pacotes para download do VIM no &lt;a href=&quot;https://www.vim.org/download.php&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;site oficial&lt;/a&gt;. Mas normalmente gerenciadores de pacotes como &lt;em&gt;apt, apk&lt;/em&gt; e &lt;em&gt;HomeBrew&lt;/em&gt; possuem uma forma simples e rápida de instalar em seu sistema.&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/19/Screenshot-2021-12-29-at-17.29.08.png&quot; alt=&quot;Um arquivo novo chamado &amp;quot;arquivo.txt&amp;quot; aberto com o editor de textos VIM. O símbolo &amp;quot;~&amp;quot; significa ausência de conteúdo, não é uma linha vazia.&quot; width=&quot;351&quot; height=&quot;225&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Um arquivo novo chamado &lt;em&gt;&quot;arquivo.txt&quot; &lt;/em&gt;aberto com o editor de textos VIM. O símbolo &quot;&lt;em&gt;~&quot; &lt;/em&gt;significa ausência de conteúdo, não é uma linha vazia.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;mcetoc_1fo3h03cl252&quot;&gt;Pra quê aprender a utilizar vim?&lt;/h2&gt;
&lt;p&gt;Antes de qualquer coisa, vamos deixar claro: você não precisa saber utilizar VIM para ter reconhecimento na área de desenvolvimento de software! Eu conheço inúmeros profissionais incríveis que não têm familiaridade alguma com esta ferramenta.&lt;/p&gt;
&lt;p&gt;Eu não quero que ao terminar de ler este texto você pense que PRECISA saber utilizar o VIM para ter reconhecimento na profissão, ou que é inferior por não saber. Não é este o ponto!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;VIM tem a capacidade de aumentar muito a sua produtividade&lt;/strong&gt; para resolver os mais diversos problemas do dia a dia tanto na profissão de desenvolvimento de software quanto como usuários.&lt;/p&gt;
&lt;p&gt;Abaixo eu descrevo alguns motivos pelos quais eu encorajo todo profissional de desenvolvimento a obter pelo menos o mínimo de proficiência com VIM.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fo3h03cl253&quot;&gt;Abrir arquivos grandes sem travar o computador&lt;/h3&gt;
&lt;p&gt;VIM é altamente otimizado e não precisa indexar todo o conteúdo do seu projeto para operar. É um editor de texto simples e portátil que te permite abrir e operar em arquivos de vários megabytes sem muita dificuldade ou lentidão.&lt;/p&gt;
&lt;p&gt;Quando se precisa navegar ou entender qual o tipo de conteúdo existe em determinado projeto, o VIM com certeza é uma opção rápida e que não requer segundos/minutos só para abrir uma pasta.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fo3h03cl254&quot;&gt;Há situações em que não é possível utilizar uma IDE&lt;/h3&gt;
&lt;p&gt;Em determinados momentos você vai se encontrar modificando ou depurando uma aplicação dentro de um conteiner &lt;em&gt;Docker&lt;/em&gt;, fazendo &lt;em&gt;ssh&lt;/em&gt; num servidor remoto ou mesmo rodando seu sistema *nix sem um servidor gráfico como o X11.&lt;/p&gt;
&lt;p&gt;Nestes casos VIM é uma ferramenta incrível porque consegue te dar todo o poder de um editor de texto mesmo sem o suporte gráfico que normalmente teríamos num computador pessoal.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fo3h03cl255&quot;&gt;VIM está preparado para trabalhar com quase todas linguagens de programação&lt;/h3&gt;
&lt;p&gt;Hoje em dia temos IDEs ultra especializadas dominando o mercado, como as ferramentas da JetBrains que são incríveis mas focadas em poucas linguagens cada uma.&lt;/p&gt;
&lt;p&gt;Para aprender uma linguagem nova ou experimentar rapidamente alterar o conteúdo de um programa de código aberto numa linguagem com a qual não se está familiarizado, VIM é extremamente útil.&lt;/p&gt;
&lt;p&gt;Sempre que eu trabalho com Python, por exemplo, utilizo VIM. Não utilizo uma IDE especializada como o PyCharm porque python não é a minha ferramenta de trabalho e não me preocupei em comprar uma licença desta IDE.&lt;/p&gt;
&lt;p&gt;Até hoje eu não consegui encontrar uma IDE gratuita especializada em linguagem C que me satisfizesse melhor do que o VIM.&lt;/p&gt;
&lt;p&gt;Alterar rapidamente um código e ver os resultados é extremamente satisfatório com VIM, é um processo pouquíssimo burocrático.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fo3uq4b43hk&quot;&gt;Você pode adicionar funcionalidades ao VIM com a linguagem que quiser&lt;/h3&gt;
&lt;p&gt;Pouco da customização do VIM é específico deste editor: você não vai precisar escrever arquivos YAML ou JSON que pouco entende, nem navegar em diversos menus de configuração.&lt;/p&gt;
&lt;p&gt;Adicionar uma funcionalidade ao VIM pode ser feito através de plugins (específicos do editor) ou linha de comando. O que você consegue executar numa linha de comando, pode ser inserido no seu estilo de trabalho com VIM.&lt;/p&gt;
&lt;p&gt;Portanto scripts em C, PHP, Python, Java, LUA ou o que mais você desejar podem ser facilmente integrados ao seu ambiente de desenvolvimento com VIM.&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1fo3h03cl256&quot;&gt;Filosofia VIM&lt;/h2&gt;
&lt;p&gt;VIM traz consigo três conceitos importantíssimos. Ao assimilar estes três conceitos, a maioria dos comandos e atalhos do VIM passam a fazer mais sentido.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fo3uq4b43hl&quot;&gt;Não tire as mãos do teclado&lt;/h3&gt;
&lt;p&gt;Este é um conceito fundamental que vai te acompanhar durante toda a sua jornada com VIM.&lt;/p&gt;
&lt;p&gt;Se você precisar usar o cursor para clicar, rolar a página, ou pressionar as setas para navegar as chances de estar fazendo algo de forma pouco eficiente são altas!&lt;/p&gt;
&lt;p&gt;Outro aspecto fundamental é que as suas mão precisam sempre focar no centro do teclado. Se algum movimento ou ação sua te obrigar a mover as mãos para as bordas do teclado ou, pior ainda, segurar o mouse, com certeza há uma forma de otimizar no VIM.&lt;/p&gt;
&lt;h3&gt;Foco no centro do teclado&lt;/h3&gt;
&lt;p&gt;Durante o nosso fluxo de desenvolvimento com outras ferramentas é comum pressionar atalhos que utilizam as teclas de função (F1, F2, ... F12) e muitas vezes outras teclas de navegação como o &lt;em&gt;page-up/down&lt;/em&gt;, &lt;em&gt;home&lt;/em&gt;, &lt;em&gt;end&lt;/em&gt;, &lt;em&gt;delete&lt;/em&gt;. E o pior de tudo: largar o teclado para alcançar o &lt;em&gt;mouse&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Isso tudo interrompe o fluxo de desenvolvimento e dispersa o foco de quem escreve.&lt;/p&gt;
&lt;p&gt;O VIM tenta corrigir isto concentrando todas as suas funcionalidades ao centro do teclado. Se você precisou levantar a mão e viajar para outro canto do teclado, ou para fora dele, provavelmente existe uma forma mais inteligente de alcançar o mesmo objetivo no VIM.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fo3uq4b43hm&quot;&gt;Evite repetições&lt;/h3&gt;
&lt;p&gt;VIM é um editor de texto de alta produtividade. Todas as repetições podem ser encurtadas com atalhos, programadas e em alguns casos até transformadas em macros.&lt;/p&gt;
&lt;p&gt;Por exemplo, o comando &lt;code&gt;dd&lt;/code&gt; apaga a linha atual do cursor. Para apagar 5 linhas você pode apertar &lt;code&gt;dd&lt;/code&gt; cinco vezes OU pressionar a sequência &lt;code&gt;d5d&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Todas as ações do VIM podem se beneficiar desta repetição. E para coisas mais complexas que envolvam múltiplas ações, é possível criar macros sem precisar programar uma linha de código sequer.&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1fo3h03cl257&quot;&gt;Primeiros passos com VIM&lt;/h2&gt;
&lt;p&gt;Guarde estes três conceitos como um mantra pra a sua prática VIM: não tire as mãos do teclado, foco no centro do teclado e evite repetições.&lt;/p&gt;
&lt;p&gt;Repetir este mantra somado com um tanto de curiosidade, vai te ajudar a dominar o VIM muito mais facilmente.&lt;/p&gt;
&lt;p&gt;Abaixo eu vou te contar sobre alguns comandos e ações básicas pra começar a trabalhar com VIM sem sofrer, perder tempo ou se frustrar. Eu garanto que com alguns dias de prática você já vai começar a entender como pode ser produtivo trabalhar com este editor de textos.&lt;/p&gt;
&lt;p&gt;Para evitar quaisquer distrações, eu vou rodar todos os exemplos abaixo utilizando uma imagem docker. Rode os comandos abaixo e provavelmente tudo o que eu escrever aqui vai funcionar pra ti sem nenhum problema.&lt;/p&gt;
&lt;pre&gt;$ docker run --rm -it alpine:latest&lt;br&gt;/ # apk add vim&lt;/pre&gt;
&lt;p&gt;O primeiro comando deverá inicializar uma imagem linux (alpine) vazia. A segunda linha, já dentro do conteiner, instala o programa VIM.&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/19/Screenshot-2021-12-29-at-21.11.08.png&quot; alt=&quot;Screenshot mostrando o resultado dos comandos acima. O último comando, &amp;quot;vim --version | head -n4&amp;quot;, mostra a versão do programa VIM instalado.&quot; width=&quot;1668&quot; height=&quot;772&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Screenshot mostrando o resultado dos comandos acima. O último comando, &quot;vim --version | head -n4&quot;, mostra a versão do programa VIM instalado.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Estamos prontos para começar!&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fo42nnu54t5&quot;&gt;Como abrir um arquivo (novo ou existente) com o VIM&lt;/h3&gt;
&lt;p&gt;É possível abrir um arquivo no VIM quando ele ainda estiver fechado, e quando já está aberto. Também é possível abrir um arquivo já existente ou criar um novo. Vamos ver cada opção aqui.&lt;/p&gt;
&lt;p&gt;Não tem diferença nenhuma o processo de abrir um arquivo novo ou existente no VIM. A maior diferença está em iniciar o VIM ou abrir o arquivo com o VIM já aberto.&lt;/p&gt;
&lt;p&gt;Para abrir um arquivo com o VIM, basta executar o comando &lt;em&gt;vim&lt;/em&gt; no terminal e passar o caminho do arquivo como parâmetro. A sintaxe é essa:&lt;/p&gt;
&lt;pre&gt;$ vim [arquivo]&lt;/pre&gt;
&lt;p&gt;Onde &lt;em&gt;[arquivo]&lt;/em&gt; deve ser substituído pelo caminho do arquivo (novo ou existente) a ser aberto, sem colchetes. Por exemplo, para abrir um arquivo novo chamado &lt;em&gt;nawarian.txt&lt;/em&gt; podemos executar o seguinte comando:&lt;/p&gt;
&lt;pre&gt;$ vim nawarian.txt&lt;/pre&gt;
&lt;p&gt;Ao executar o comando acima, uma tela parecida com esta deverá abrir:&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/19/Screenshot-2021-12-29-at-21.18.58.png&quot; alt=&quot;Programa VIM com o arquivo &amp;quot;nawarian.txt&amp;quot; aberto. A palavra [New] na barra de status indica que o arquivo não existia antes.&quot; width=&quot;758&quot; height=&quot;508&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Programa VIM com o arquivo &lt;em&gt;&quot;nawarian.txt&quot;&lt;/em&gt; aberto. A palavra &lt;em&gt;[New]&lt;/em&gt; na barra de status indica que o arquivo não existia antes.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;mcetoc_1fo3h03cl259&quot;&gt;Como salvar e sair do VIM&lt;/h3&gt;
&lt;p&gt;Mesmo sem adicionar nada no arquivo, já podemos salvar e sair. Desta forma o arquivo já será criado no sistema operacional normalmente, porém vazio. Pressione &lt;code&gt;:wq&lt;/code&gt; e em seguida &lt;em&gt;enter&lt;/em&gt; para que VIM salve e feche o arquivo.&lt;/p&gt;
&lt;p&gt;Aqui &lt;em&gt;w&lt;/em&gt; significa &quot;write&quot;, ou &quot;escrever&quot; em português. E &lt;em&gt;q&lt;/em&gt; significa &quot;quit&quot;, ou &quot;sair&quot; em português. Portanto o comando &lt;em&gt;:wq&lt;/em&gt; pode ser lido como &quot;write and quit&quot; ou &quot;escrever e sair&quot;.&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/19/Screenshot-2021-12-29-at-21.26.58.png&quot; alt=&quot;Ao fechar VIM com :wq o arquivo nawarian.txt foi gravado em disco, mesmo com 0 bytes.&quot; width=&quot;1406&quot; height=&quot;1128&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Ao fechar VIM com &lt;em&gt;:wq&lt;/em&gt; o arquivo &lt;em&gt;nawarian.txt&lt;/em&gt; foi gravado em disco, mesmo com 0 bytes.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;mcetoc_1fo3uq4b43ho&quot;&gt;Como abrir um arquivo com o VIM já aberto&lt;/h3&gt;
&lt;p&gt;Vamos abrir novamente o arquivo &lt;em&gt;nawarian.txt&lt;/em&gt; com o comando a seguir:&lt;/p&gt;
&lt;pre&gt;$ vim nawarian.txt&lt;/pre&gt;
&lt;p&gt;Com isto, VIM abrirá o arquivo &lt;em&gt;nawarian.txt&lt;/em&gt; (agora já existente). Vamos agora abrir um arquivo chamado &lt;em&gt;codamos.com.br&lt;/em&gt; mas desta vez com o VIM já aberto.&lt;/p&gt;
&lt;p&gt;Para isto, utilizamos o comando &lt;code&gt;:o codamos.com.br&lt;/code&gt; onde &lt;em&gt;codamos.com.br&lt;/em&gt; é o nome do arquivo. &lt;code&gt;:o&lt;/code&gt; pode ser lido como &quot;open&quot;, ou &quot;abrir&quot; em português. Portanto &lt;code&gt;:o codamos.com.br&lt;/code&gt; vai &quot;abrir o arquivo codamos.com.br&quot;.&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/19/Screenshot-2021-12-29-at-21.35.19.png&quot; alt=&quot;Com o VIM já aberto, digite &amp;quot; :o codmaos.com.br&amp;quot; e em seguida pressione enter.&quot; width=&quot;538&quot; height=&quot;318&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Com o VIM já aberto, digite &lt;i&gt;&quot;&lt;/i&gt; &lt;em&gt;:o codamos.com.br&quot; &lt;/em&gt;e em seguida pressione &lt;em&gt;enter&lt;/em&gt;.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/19/Screenshot-2021-12-29-at-21.35.28.png&quot; alt=&quot;Ao pressionar enter, um novo arquivo chamado codamos.com.br deverá aparecer em seu buffer no VIM.&quot; width=&quot;588&quot; height=&quot;354&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Ao pressionar &lt;em&gt;enter&lt;/em&gt;, um novo arquivo chamado &lt;em&gt;codamos.com.br&lt;/em&gt; deverá aparecer em seu buffer no VIM.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;mcetoc_1fo3h03cl25a&quot;&gt;Edição de texto&lt;/h3&gt;
&lt;p&gt;Nós já conseguimos abrir e fechar um arquivo com VIM. Muito bem!&lt;/p&gt;
&lt;p&gt;Mas é importante também alterar o conteúdo deste arquivo, né?&lt;/p&gt;
&lt;p&gt;O VIM possui diferentes modos de trabalho. Por padrão, o modo de trabalho do VIM é o &quot;Modo Normal&quot;, a partir do qual você pode executar comandos. Para alterar o conteúdo do arquivo, precisamos ativar o &quot;Modo de inserção&quot;.&lt;/p&gt;
&lt;p&gt;Basta pressionar a tecla &lt;code&gt;i&lt;/code&gt; para ativar o &quot;Modo de inserção&quot;. Você pode notar que a barra de status do VIM indica quando estamos no modo de inserção:&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/19/Screenshot-2021-12-29-at-21.56.39.png&quot; alt=&quot;Ao pressionar a tecla i VIM entra no modo de inserção e mostra o texto -- INSERT -- na barra de status, indicando que estamos no modo de inserção.&quot; width=&quot;896&quot; height=&quot;572&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Ao pressionar a tecla &lt;em&gt;i &lt;/em&gt;VIM entra no modo de inserção e mostra o texto &lt;em&gt;-- INSERT -- &lt;/em&gt;na barra de status, indicando que estamos no modo de inserção.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Sempre que o modo de inserção estiver ativado (&lt;em&gt;-- INSERT -- &lt;/em&gt;aparece na barra de status), todas as teclas que pressionamos serão escritas no buffer do arquivo.&lt;/p&gt;
&lt;p&gt;Agora que estamos no modo de inserção, podemos escrever &quot;&lt;em&gt;Olá mundo!&quot;&lt;/em&gt;, pressionar &lt;code&gt;ESC&lt;/code&gt; para voltar ao modo normal e executar o comando de salvar e sair, ou &lt;code&gt;:wq&lt;/code&gt;.&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/19/Screenshot-2021-12-29-at-22.00.06.png&quot; alt=&quot;O texto &amp;quot;Olá mundo&amp;quot; foi escrito no buffer do vim. Ao pressionar ESC voltamos ao modo de comandos, e iniciamos o comando salvar e sair.&quot; width=&quot;650&quot; height=&quot;486&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;O texto &quot;&lt;em&gt;Olá mundo&lt;/em&gt;&quot; foi escrito no buffer do vim. Ao pressionar ESC voltamos ao modo normal, e iniciamos o comando salvar e sair.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Note que agora o arquivo &lt;em&gt;codamos.com.br&lt;/em&gt; possui 11 bytes. Pois escrevemos o texto &lt;em&gt;Olá mundo&lt;/em&gt; nele. Podemos tomar certeza de que modificamos mesmo o arquivo utilizando o comando &lt;em&gt;cat&lt;/em&gt;.&lt;/p&gt;
&lt;pre&gt;$ cat codamos.com.br&lt;/pre&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/19/Screenshot-2021-12-29-at-22.02.49.png&quot; alt=&quot;O comando ls -la mostra o arquivo codamos.com.br e seus 11 bytes. Enquanto o comando cat codamos.com.br mostra seu conteúdo &amp;quot;Olá mundo&amp;quot;.&quot; width=&quot;1462&quot; height=&quot;1210&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;O comando &lt;em&gt;ls -la&lt;/em&gt; mostra o arquivo codamos.com.br e seus 11 bytes. Enquanto o comando &lt;em&gt;cat codamos.com.br&lt;/em&gt; mostra seu conteúdo &quot;Olá mundo&quot;.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;mcetoc_1fo3h03cl25b&quot;&gt;Como navegar no texto&lt;/h3&gt;
&lt;p&gt;Navegar o conteúdo no VIM também é um pouco diferente do comum. Lembre-se: não tire as mãos do teclado, foco no centro do teclado, evite repetições.&lt;/p&gt;
&lt;p&gt;Vamos abrir o arquivo &lt;em&gt;nawarian.txt&lt;/em&gt; e escrever mais do que uma linha lá. Digite o comando abaixo:&lt;/p&gt;
&lt;pre&gt;$ vim nawarian.txt&lt;/pre&gt;
&lt;p&gt;Agora que o arquivo &lt;em&gt;nawarian.txt&lt;/em&gt; está aberto no VIM, e estamos o modo de comando, vamos entrar no modo de inserção pressionando a tecla &lt;code&gt;i&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Agora digite um texto de algumas linhas, aqui vai minha sugestão. Mas digita mesmo, não dê um copia e cola.&lt;/p&gt;
&lt;pre&gt;VIM é um editor muito massa&lt;br&gt;mas pouca gente entende o software e passa sufoco.&lt;br&gt;Se este tutorial conseguir me preparar pra começar a usar VIM com mais frequência&lt;br&gt;eu prometo que vou compartilhar nas minhas redes sociais para que&lt;br&gt;mais pessoas sejam infectadas pelo vírus do VIM.&lt;/pre&gt;
&lt;p&gt;Pronto, agora pressione &lt;code&gt;ESC&lt;/code&gt; para voltar ao modo normal. Sua tela deve mais ou menos assim:&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/19/Screenshot-2021-12-29-at-22.19.36.png&quot; alt=&quot;&quot; width=&quot;1704&quot; height=&quot;336&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Buffer do VIM mostrando o texto acima. Note que o cursor está parado no último caractere da última linha.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h4 id=&quot;mcetoc_1fo42nnu54t6&quot;&gt;Como mostrar as linhas do documento&lt;/h4&gt;
&lt;p&gt;Eu gosto de me guiar pelas linhas do documento. Isto não é obrigatório mas me ajuda muito a navegar no VIM.&lt;/p&gt;
&lt;p&gt;Basta executar o comando &lt;code&gt;:set nu&lt;/code&gt; (set number) para que o VIM exiba as linhas normalmente. O seu editor deverá ficar assim depois de executar o comando &lt;code&gt;:set nu&lt;/code&gt;:&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/19/Screenshot-2021-12-29-at-22.22.59.png&quot; alt=&quot;Editor VIM após executar o comando &amp;quot;:set nu&amp;quot; mostra o número de cada linha do arquivo nawarian.txt&quot; width=&quot;1730&quot; height=&quot;446&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Editor &lt;em&gt;VIM&lt;/em&gt; após executar o comando &quot;&lt;em&gt;:set nu&lt;/em&gt;&quot; mostra o número de cada linha do arquivo &lt;em&gt;nawarian.txt&lt;/em&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h4 id=&quot;mcetoc_1fo42nnu54t7&quot;&gt;Mover o cursor para uma linha específica&lt;/h4&gt;
&lt;p&gt;Se você já sabe com qual linha quer trabalhar, basta usar o atalho &lt;code&gt;número + gg&lt;/code&gt;. Se você quiser navegar rapidamente para a linha 2, basta digitar &lt;code&gt;2gg&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Como eu não estudei este atalho a fundo, eu costumo chamar esta ação de &quot;gogo&quot; 😅&lt;/p&gt;
&lt;h4 id=&quot;mcetoc_1fo42nnu54t8&quot;&gt;Mover o cursor linha a linha ou coluna a coluna&lt;/h4&gt;
&lt;p&gt;Caso queira mover o cursor manualmente para cima, baixo, esquerda ou direita há também atalhos específicos.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Eu não recomendo utilizar as setas do teclado&lt;/strong&gt;, lembre-se: mantenha as mãos ao centro do teclado!&lt;/p&gt;
&lt;p&gt;No modo normal, basta utilizar as teclas h, j, k e l para navegar para esquerda, baixo, cima e direita respectivamente.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;h&lt;/code&gt; move o cursor para a esquerda&lt;/li&gt;
&lt;li&gt;&lt;code&gt;j&lt;/code&gt; move o cursor para baixo&lt;/li&gt;
&lt;li&gt;&lt;code&gt;k&lt;/code&gt; move o cursor para cima&lt;/li&gt;
&lt;li&gt;&lt;code&gt;l&lt;/code&gt; move o cursor para direita&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Eu sei, no começo é difícil. Mas com a prática você vai quer que na verdade isto vai te economizar muito tempo e esforço.&lt;/p&gt;
&lt;p&gt;Existe um joguinho de navegador muito bacana que pode te ajudar a ganhar prática com o cursor: &lt;a href=&quot;https://vim-adventures.com/&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;VIM Adventures&lt;/a&gt;. Na figura abaixo você consegue ter uma noção de como o jogo funciona e pode te ajudar a dominar a navegação básica do VIM.&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img class=&quot;post__image&quot; src=&quot;/media/posts/19/vim-adventures.jpg&quot; alt=&quot;Captura de tela: jogo VIM adventures, ideal para praticar seus primeiros passos no VIM.&quot; width=&quot;876&quot; height=&quot;877&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Captura de tela: jogo VIM adventures, ideal para praticar seus primeiros passos no VIM.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Além disso, é possível repetir estes atalhos N vezes de acordo com o número de prefixo que você escolher.&lt;/p&gt;
&lt;p&gt;Por exemplo, caso queira andar 4 linhas para cima, você tem duas opções:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pressionar &lt;code&gt;k&lt;/code&gt; quatro vezes seguidas; ou&lt;/li&gt;
&lt;li&gt;Pressionar &lt;code&gt;4k&lt;/code&gt; uma única vez&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A segunda opção mantém suas mãos ao centro do teclado e evita repetições.&lt;/p&gt;
&lt;h4 id=&quot;mcetoc_1fo42nnu54t9&quot;&gt;Mover para o começo ou fim da linha&lt;/h4&gt;
&lt;p&gt;Para mover rapidamente para o começo da linha, digite &lt;code&gt;^&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Para mover rapidamente para o fim da linha, digite &lt;code&gt;$&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id=&quot;mcetoc_1fo42nnu54ta&quot;&gt;Pular palavras para frente e para trás&lt;/h4&gt;
&lt;p&gt;Para avançar o cursor em uma palavra, basta digitar &lt;code&gt;w&lt;/code&gt; (&lt;strong&gt;w&lt;/strong&gt;ord, ou &quot;palavra&quot; em português) uma única vez. Ao digitar &lt;code&gt;5w&lt;/code&gt; você avança 5 palavras.&lt;/p&gt;
&lt;p&gt;De forma semelhante, ao digitar b (&lt;strong&gt;b&lt;/strong&gt;ack, ou &quot;voltar&quot; em português) uma vez o seu cursor irá recuar uma palavra. E ao digitar &lt;code&gt;5b&lt;/code&gt;, você volta 5 palavras.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fo3h03cl25c&quot;&gt;Buscar conteúdo no VIM&lt;/h3&gt;
&lt;p&gt;Outra ação comum ao editar um texto é encontrar a ocorrência de determinada palavra ou símbolos.&lt;/p&gt;
&lt;p&gt;No VIM o comando &lt;code&gt;:/termo-de-busca&lt;/code&gt; irá buscar &lt;em&gt;termo-de-busca&lt;/em&gt; no conteúdo do buffer atual.&lt;/p&gt;
&lt;p&gt;Voltando ao texto que escrevemos, podemos buscar a palavra &lt;em&gt;VIM&lt;/em&gt;, que aparece no texto 3 vezes, com o seguinte comando:&lt;/p&gt;
&lt;pre&gt;:/VIM&lt;/pre&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/19/Screenshot-2021-12-29-at-22.40.23.png&quot; alt=&quot;Iniciando uma busca pela palavra VIM usando o comando :/VIM. Três ocorrências deverão ser encontradas no texto.&quot; width=&quot;1726&quot; height=&quot;444&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Iniciando uma busca pela palavra &lt;em&gt;VIM&lt;/em&gt; usando o comando &lt;em&gt;:/VIM&lt;/em&gt;. Três ocorrências deverão ser encontradas no texto.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Considerando que o cursor estava no fim da última linha, ao buscar &lt;em&gt;VIM&lt;/em&gt; o editor deverá retornar ao começo do arquivo e apontar a primeira ocorrência no começo da primeira linha. Note que o editor nos informa que precisou retornar ao início do arquivo:&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/19/Screenshot-2021-12-29-at-22.42.24.png&quot; alt=&quot;A busca pela palavra VIM indica que a busca chegou ao fim do arquivo e precisou retornar ao topo. O cursor foi movido para o começo da linha 1, onde a palavra VIM aparece pela primeira vez no documento.&quot; width=&quot;1730&quot; height=&quot;440&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;A busca pela palavra &lt;em&gt;VIM&lt;/em&gt; indica que a busca chegou ao fim do arquivo e precisou retornar ao topo. O cursor foi movido para o começo da linha 1, onde a palavra VIM aparece pela primeira vez no documento.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Como a palavra &lt;em&gt;VIM&lt;/em&gt; aparece mais de uma vez no texto, podemos repetir a operação de busca para encontrar a próxima. Temos duas opções para alcançar este objetivo:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Executar o comando de busca &lt;code&gt;:/VIM&lt;/code&gt; novamente (repetição); ou&lt;/li&gt;
&lt;li&gt;Invocar o atalho &lt;strong&gt;n&lt;/strong&gt;ext, ou &quot;próximo&quot; em português, ao pressionar a tecla &lt;code&gt;n&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Assim como os outros atalhos mencionados, o atalho &lt;strong&gt;n&lt;/strong&gt;ext pode ser prefixado com um número. Portanto &lt;code&gt;2n&lt;/code&gt; irá buscar o último termo de busca (VIM neste caso) duas vezes.&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1fo43obg450e&quot;&gt;Ainda tem muito chão pela frente&lt;/h2&gt;
&lt;p&gt;Com estas primeiras dicas você já vai conseguir se virar bem no seu aprendizado e ganhar proficiência com o editor VIM.&lt;/p&gt;
&lt;p&gt;Ainda tem muita coisa pra aprender no VIM que pode tornar sua prática com desenvolvimento de software mais prazeirosa e produtiva. Aqui alguns exemplos de o que se pode fazer com o VIM:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Instalar/desenvolver plugins;&lt;/li&gt;
&lt;li&gt;Gravar e utilizar macros;&lt;/li&gt;
&lt;li&gt;Abrir e navegar entre múltiplas abas de texto;&lt;/li&gt;
&lt;li&gt;Dividir a tela para editar dois arquivos ao mesmo tempo;&lt;/li&gt;
&lt;li&gt;Rodar programas de linha de comando diretamente do VIM;&lt;/li&gt;
&lt;li&gt;Direcionar o resultado de um comando para o buffer do editor atual;&lt;/li&gt;
&lt;li&gt;Outras coisas que nem eu sei...&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Mas antes de se aventurar com todas essas funcionalidades, é importante atingir algum nível de proficiência com as ferramentas que citei neste texto.&lt;/p&gt;
&lt;p&gt;Para quem entende inglês sem muita dificuldades, tem aqui um vídeo interessante sobre com várias dicas para atingir maior proficiência no VIM. Se você não aprender nada a partir deste vídeo, com certeza terá ao menos muita inspiração.&lt;/p&gt;
&lt;p&gt;&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/XA2WjJbmmoM&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;allowfullscreen&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded><category>produtividade</category><category>vim</category></item><item><title>Como migrar um campo de banco de dados em 9 passos</title><link>https://codamos.com.br/migracao-banco-de-dados/</link><guid isPermaLink="true">https://codamos.com.br/migracao-banco-de-dados/</guid><description>O problema Vamos cobrir um caso muito específico e chato de lidar: migração de chave primária. Temos uma entidade User , identificada por User::$id que é assim: final class User { public function __co</description><pubDate>Sat, 04 Dec 2021 17:04:00 GMT</pubDate><content:encoded>&lt;h2&gt;O problema&lt;/h2&gt;
&lt;p&gt;Vamos cobrir um caso muito específico e chato de lidar: migração de chave primária.&lt;/p&gt;
&lt;p&gt;Temos uma entidade &lt;code&gt;User&lt;/code&gt;, identificada por &lt;code&gt;User::$id&lt;/code&gt; que é assim:&lt;/p&gt;
&lt;pre&gt;final class User&lt;br&gt;{&lt;br&gt;    public function __construct(&lt;br&gt;        public int $id,&lt;br&gt;    ) {}&lt;br&gt;}&lt;/pre&gt;
&lt;p&gt;E para acessar seus dados a gente usa uma interface chamada &lt;code&gt;UserRepository&lt;/code&gt;. Eu vou deixar aqui uma implementação simples deste repository com Sqlite:&lt;/p&gt;
&lt;pre&gt;interface UserRepository&lt;br&gt;{&lt;br&gt;    /** @throws UserNotFoundException */&lt;br&gt;    public function findById(int $id): User;&lt;br&gt;}&lt;br&gt;&lt;br&gt;final class SqliteUserRepository implements UserRepository&lt;br&gt;{&lt;br&gt;    public function findById(int $id): User&lt;br&gt;    {&lt;br&gt;        $sql = &quot;...&quot;;&lt;br&gt;        $stmt = $this-&amp;gt;pdo-&amp;gt;prepare($sql);&lt;br&gt;&lt;br&gt;        $stmt-&amp;gt;execute([&lt;br&gt;            &apos;id&apos; =&amp;gt; $id,&lt;br&gt;        ]);&lt;br&gt;&lt;br&gt;        // ...&lt;br&gt;    }&lt;br&gt;}&lt;/pre&gt;
&lt;p&gt;Digamos que o seu time decidiu que a chave primária da classe &lt;code&gt;User&lt;/code&gt;, por motivos de segurança, não deveriam ser um integer mas um UUID. E, é claro, não é possível desativar a aplicação durante a migração.&lt;/p&gt;
&lt;h2&gt;A solução&lt;/h2&gt;
&lt;p&gt;Eu implementaria esta mudança em três fases:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Deixar os dois IDs coexistirem&lt;/li&gt;
&lt;li&gt;Migrar a aplicação para a implementação com UUID&lt;/li&gt;
&lt;li&gt;Remover a implementação com ID inteiro&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;O maior motivo de eu adotar estas três fases é que os testes não são suficientes para garantir que a aplicação vai funcionar como esperado. Este campo pode ser utilizado por outros componentes via API or alguma outra coisa.&lt;/p&gt;
&lt;p&gt;Então para evitar maiores desastres, eu gostaria de alterar a implementação de forma que eu possa voltar à implementação anterior imediatamente se necessário.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Eu estou assumindo que cada passo descrito aqui está coberto com testes, antes mesmo de &lt;a href=&quot;/livro-refactoring-martin-fowler/&quot;&gt;refatorar o código&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Passo 1: desacoplar dos tipos primitivos&lt;/h2&gt;
&lt;p&gt;Não importa o que a gente resolva implementar, vai ser difícil sem desacoplar primitivos. Aquele tipo &lt;code&gt;int&lt;/code&gt; an classe &lt;code&gt;User&lt;/code&gt; é um catalisador de desgraças.&lt;/p&gt;
&lt;p&gt;Uma forma simples de fazer isso é encapsular primitivos. Eu vou criar uma classe chamada &lt;code&gt;UserId&lt;/code&gt; e fazer com que &lt;code&gt;User&lt;/code&gt; dependa dela em vez de &lt;code&gt;int&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;final class UserId&lt;br&gt;{&lt;br&gt;    public function __construct(public int $id) {}&lt;br&gt;&lt;br&gt;    public function getId(): int&lt;br&gt;    {&lt;br&gt;        return $this-&amp;gt;id;&lt;br&gt;    }&lt;br&gt;}&lt;br&gt;&lt;br&gt;final class User&lt;br&gt;{&lt;br&gt;    public function __construct(public UserId $id) {}&lt;br&gt;}&lt;br&gt;&lt;br&gt;interface UserRepository&lt;br&gt;{&lt;br&gt;    /** @throws UserNotFoundException */&lt;br&gt;    public function findById(UserId $id): User;&lt;br&gt;}&lt;/pre&gt;
&lt;p&gt;Esta mudança vai tornar a nossa refatoração bem mais fácil. &lt;code&gt;UserId&lt;/code&gt; ainda retorna &lt;code&gt;int&lt;/code&gt; quando &lt;code&gt;UserId::getId()&lt;/code&gt; é chamado, mas isto não é problema! O que importa é que &lt;code&gt;User&lt;/code&gt; agora depende do tipo &lt;code&gt;UserId&lt;/code&gt; - um tipo que nós controlamos - em vez do primitivo &lt;code&gt;integer&lt;/code&gt; - o qual não temos controle algum.&lt;/p&gt;
&lt;p&gt;Agora é só atualizar o código existente para utilizar &lt;code&gt;UserId&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;final class SqliteUserRepository implements UserRepository&lt;br&gt;{&lt;br&gt;    public function findById(UserId $id): User&lt;br&gt;    {&lt;br&gt;        $sql = &quot;...&quot;;&lt;br&gt;        $stmt = $this-&amp;gt;pdo-&amp;gt;prepare($sql);&lt;br&gt;        $stmt-&amp;gt;execute([&lt;br&gt;            &apos;id&apos; =&amp;gt; $id-&amp;gt;getId(),&lt;br&gt;        ]);&lt;br&gt;&lt;br&gt;        // ...&lt;br&gt;    }&lt;br&gt;}&lt;/pre&gt;
&lt;p&gt;Até aqui nada mudou, só preparamos o ambiente. Eu não veria muitos problemas em subir este código para produção, &lt;em&gt;especialmente se estiver coberto com testes&lt;/em&gt;.&lt;/p&gt;
&lt;h2&gt;Passo 2: Deixar as duas chaves coexistirem&lt;/h2&gt;
&lt;p&gt;Agora vamos adicionar o novo campo uuid à nossa tabela do banco de dados:&lt;/p&gt;
&lt;pre&gt;sqlite&amp;gt; ALTER TABLE `users` ADD `uuid` VARCHAR;&lt;/pre&gt;
&lt;p&gt;Este campo ainda não pode ser &lt;code&gt;NOT NULL&lt;/code&gt; e nem &lt;code&gt;UNIQUE&lt;/code&gt; por enquanto, porque todos registros que já existem vão considerar uuid como NULL.&lt;/p&gt;
&lt;p&gt;Agora vamos modificar a nossa classe UserId:&lt;/p&gt;
&lt;pre&gt;final class UserId&lt;br&gt;{&lt;br&gt;    public function __construct(&lt;br&gt;        public int $id,&lt;br&gt;        public ?UuidInterface $uuid,&lt;br&gt;    ) {}&lt;br&gt;&lt;br&gt;    public function getId(): int&lt;br&gt;    {&lt;br&gt;        return $this-&amp;gt;id;&lt;br&gt;    }&lt;br&gt;&lt;br&gt;    public function getUuid(): ?UuidInterface&lt;br&gt;    {&lt;br&gt;        return $this-&amp;gt;uuid;&lt;br&gt;    }&lt;br&gt;}&lt;/pre&gt;
&lt;p&gt;Note que o campo &lt;em&gt;uuid&lt;/em&gt; é nullable, porque nenhum registro possui UUID ainda.&lt;/p&gt;
&lt;p&gt;Agora a precisa garantir duas coisas:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Todo registro da tabela &quot;users&quot; possui um UUID que não é nulo; e&lt;/li&gt;
&lt;li&gt;Todo novo registro da tabela &quot;users&quot; possuirá um UUID&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;É possível considerar que os dois ids estão coexistindo sem problemas somente quando o campo &lt;code&gt;users.uuid&lt;/code&gt; nunca é &lt;code&gt;NULL&lt;/code&gt; no banco de dados.&lt;/p&gt;
&lt;h2&gt;Passo 3: garantir que todo novo registro possui um UUID&lt;/h2&gt;
&lt;p&gt;Em algum lugar do sistema, alguma coisa grava usuários na tabela &lt;code&gt;Users&lt;/code&gt;. Precisamos ter certeza de que em todo lugar onde isto acontece, o campo UUID será preenchido.&lt;/p&gt;
&lt;p&gt;Então o método abaixo:&lt;/p&gt;
&lt;pre&gt;...&lt;br&gt;&lt;br&gt;public function insert(User $user): void&lt;br&gt;{&lt;br&gt;    // insert into...&lt;br&gt;}&lt;br&gt;...&lt;/pre&gt;
&lt;p&gt;Precisaria ser modificado com algo assim:&lt;/p&gt;
&lt;pre&gt;...&lt;br&gt;&lt;br&gt;public function insert(User $user): void&lt;br&gt;{&lt;br&gt;    $id = $user-&amp;gt;id;&lt;br&gt;&lt;br&gt;    if ($id-&amp;gt;uuid === null) {&lt;br&gt;        $id-&amp;gt;uuid = Uuid::uuid4();&lt;br&gt;    }&lt;br&gt;&lt;br&gt;    // insert into...&lt;br&gt;}&lt;br&gt;...&lt;/pre&gt;
&lt;p&gt;Eu recomendo fortemente cobrir este IF com testes, para garantir que você não importou nada errado ou coisa do gênero. Mas fora isso, eu não esperaria ver nenhuma outra regressão.&lt;/p&gt;
&lt;p&gt;Todo novo registro na tabela &lt;code&gt;users&lt;/code&gt; a partir de agora deverá ter o campo uuid com um valor não nulo.&lt;/p&gt;
&lt;h2&gt;Passo 4: preencher UUID para registros já existentes&lt;/h2&gt;
&lt;p&gt;Isto pode ser feito com um script. Se você utiliza algum tipo de framework de &lt;em&gt;migrations&lt;/em&gt;, provavelmente será mais fácil ainda.&lt;/p&gt;
&lt;p&gt;A gente só precisa buscar todos os &lt;code&gt;User&lt;/code&gt; com uuid nulo e preenchê-los. Algo assim já deveria dar conta do recado:&lt;/p&gt;
&lt;pre&gt;$users = getUsersWithEmptyUuid();&lt;br&gt;foreach ($users as $user) {&lt;br&gt;    $user-&amp;gt;id-&amp;gt;uuid = Uuid::uuid4();&lt;br&gt;    updateUser($user);&lt;br&gt;}&lt;/pre&gt;
&lt;p&gt;Este snippet de código não representa a maioria dos codebases por aí, mas acho que dá pra ter uma noção de o que eu quis dizer.&lt;/p&gt;
&lt;p&gt;É importante também revisar possíveis chaves estrangeiras que referenciem &lt;code&gt;user.id&lt;/code&gt; e migrá-las se você achar que faz sentido.&lt;/p&gt;
&lt;h2&gt;Passo 5: deixar a aplicação rodar por um tempo&lt;/h2&gt;
&lt;p&gt;Não há motivos pra mudar tudo de uma vez. Deixa o sistema rodar com o código novo por um tempo para podermos ter certeza de que os dados estão consistentes: &lt;code&gt;users.uuid&lt;/code&gt; não é nulo em lugar algum, as chaves estrangeiras estão se comportando como deveriam e por aí vai.&lt;/p&gt;
&lt;p&gt;Avance para o passo 6 somente quando tiver segurança de que &lt;code&gt;users.uuid&lt;/code&gt; nunca será nulo.&lt;/p&gt;
&lt;h2&gt;Passo 6: Atualizar UserRepository para utilizar UUID&lt;/h2&gt;
&lt;p&gt;Apesar de já estarmos numa posição confortável para migrar para a nova implementação que utiliza UUID, eu não recomendo mudar totalmente ainda.&lt;/p&gt;
&lt;p&gt;Vamos primeiro proteger o nosso código com uma feature flag. Atualize a classe &lt;code&gt;SqliteUserRepository&lt;/code&gt; com o seguinte:&lt;/p&gt;
&lt;pre&gt;final class SqliteUserRepository implements UserRepository&lt;br&gt;{&lt;br&gt;    public function findById(UserId $id): User&lt;br&gt;    {&lt;br&gt;        if (isFeatureFlagActive(&apos;enableNewUsersUuidImplementation&apos;)) {&lt;br&gt;            // Nova implementação, utiliza UUID&lt;br&gt;            $sql = &quot;...&quot;;&lt;br&gt;            $stmt = $this-&amp;gt;pdo-&amp;gt;prepare($sql);&lt;br&gt;&lt;br&gt;            $stmt-&amp;gt;execute([&apos;uuid&apos; =&amp;gt; (string) $id-&amp;gt;getUuid()]);&lt;br&gt;            // ...&lt;br&gt;        } else {&lt;br&gt;            // Implementação antiga, utiliza $id inteiro&lt;br&gt;            $sql = &quot;...&quot;;&lt;br&gt;            $stmt = $this-&amp;gt;pdo-&amp;gt;prepare($sql);&lt;br&gt;&lt;br&gt;            $stmt-&amp;gt;execute([&apos;id&apos; =&amp;gt; $id-&amp;gt;getId()]);&lt;br&gt;            // ...&lt;br&gt;        }&lt;br&gt;    }&lt;br&gt;}&lt;/pre&gt;
&lt;p&gt;Resumidamente: &lt;code&gt;isFeatureFlagActive()&lt;/code&gt; retorna &lt;code&gt;TRUE&lt;/code&gt; se a funcionalidade estiver habilitada e &lt;code&gt;FALSE&lt;/code&gt; caso não esteja. Isto pode ser manipulado com configurações, registros num banco de dados ou mesmo variáveis de ambiente.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;O que é importante é que você pode mudar o retorno TRUE/FALSE desta função sem precisar fazer outro deploy.&lt;/strong&gt; Desta forma você consegue facilmente voltar à implementação anterior caso encontre algum problema.&lt;/p&gt;
&lt;h2&gt;Passo 7: Lançar, habilitar e monitorar&lt;/h2&gt;
&lt;p&gt;Vamos primeiro fazer o deploy do software e tomar certeza de que &lt;code&gt;isFeatureFlagActive()&lt;/code&gt; sempre vai retornar FALSE para que a implementação original seja utilizada.&lt;/p&gt;
&lt;p&gt;Depois, vamos fazer com que &lt;code&gt;isFeatureFlagActive()&lt;/code&gt; retorne TRUE para que a nova implementação seja utilizada.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ai não! Alguma coisa tá errada! O site ficou mega lento de repente!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Desligue a feature flag, para que &lt;code&gt;isFeatureFlagActive()&lt;/code&gt; retorne FALSE novamente.&lt;/p&gt;
&lt;p&gt;...&lt;/p&gt;
&lt;p&gt;As coisas parecem ter voltado ao normal. Vamos voltar à aplicação em máquina local e tentar entender o que aconteceu.&lt;/p&gt;
&lt;p&gt;Você vai perceber que esquecemos de adicionar um índice para o campo &lt;code&gt;users.uuid&lt;/code&gt;, então toda query para este campo ficou mega lenta. Hora de corrigir!&lt;/p&gt;
&lt;h2&gt;Passo 8: Tornar UUID unique e adicionar um índice nele&lt;/h2&gt;
&lt;p&gt;Como eu estou implementando com SQLITE, aqui vai o snippet que resolveria a situação:&lt;/p&gt;
&lt;pre&gt;sqlite&amp;gt; CREATE UNIQUE INDEX `users_uuid_uq` ON `users`(`uuid`);&lt;/pre&gt;
&lt;p&gt;Seria ideal mudar o campo para que fique NOT NULL também, mas eu vou pular esta etapa aqui porque é mais complicado no SQLITE e isto não é relevante para o nosso problema em questão.&lt;/p&gt;
&lt;p&gt;Bom, tudo parece estar correto agora. Vamos lançar para produção, habilitar a feature flag e ver como o sistema se comporta.&lt;/p&gt;
&lt;p&gt;Tudo certo? Agora é hora de limpar a casa.&lt;/p&gt;
&lt;h2&gt;Passo 9: limpar o campo id da tabela users&lt;/h2&gt;
&lt;p&gt;Agora que o novo código está funcionando como deveria, é hora de limpar o campo id que existia antes.&lt;/p&gt;
&lt;p&gt;Você pode decidir se quer limpar apenas do código ou também do banco de dados, é uma questão de situação.&lt;/p&gt;
&lt;p&gt;Ao fim das contas, &lt;code&gt;SqliteUserRepository&lt;/code&gt; deverá ficar assim:&lt;/p&gt;
&lt;pre&gt;final class SqliteUserRepository implements UserRepository&lt;br&gt;{&lt;br&gt;    public function findById(UserId $id): User&lt;br&gt;    {&lt;br&gt;        $sql = &quot;...&quot;;&lt;br&gt;        $stmt = $this-&amp;gt;pdo-&amp;gt;prepare($sql);&lt;br&gt;&lt;br&gt;        $stmt-&amp;gt;execute([&apos;uuid&apos; =&amp;gt; (string) $id-&amp;gt;getUuid()]);&lt;br&gt;        // ...&lt;br&gt;    }&lt;br&gt;}&lt;/pre&gt;
&lt;p&gt;E a função que adiciona novos usuários também precisa de algumas mudanças:&lt;/p&gt;
&lt;pre&gt;...&lt;br&gt;public function insert(User $user): void&lt;br&gt;{&lt;br&gt;    $user-&amp;gt;id-&amp;gt;uuid = Uuid::uuid4();&lt;br&gt;&lt;br&gt;    // insert logic&lt;br&gt;}&lt;br&gt;...&lt;/pre&gt;
&lt;p&gt;Vamos também remover o campo $id numérico da classe &lt;code&gt;UserId&lt;/code&gt; e tornar UUID não nulo:&lt;/p&gt;
&lt;pre&gt;final class UserId&lt;br&gt;{&lt;br&gt;    public function __construct(public UuidInterface $uuid) {}&lt;br&gt;&lt;br&gt;    public function getUuid(): UuidInterface&lt;br&gt;    {&lt;br&gt;        return $this-&amp;gt;uuid;&lt;br&gt;    }&lt;br&gt;}&lt;/pre&gt;
&lt;h2&gt;Seu banco de dados foi migrado com segurança&lt;/h2&gt;
&lt;p&gt;É claro que cada projeto tem sua especificidade, mas no fim das contas, você vai precisar executar alguma variação da técnica descrita aqui.&lt;/p&gt;
&lt;p&gt;Isto se aplica a qualquer migração relativa a repositórios de dados. Basta lembrar-se das três fases:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Deixar os dois IDs coexistirem&lt;/li&gt;
&lt;li&gt;Migrar a aplicação para a implementação com UUID&lt;/li&gt;
&lt;li&gt;Remover a implementação com ID inteiro&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Não precisa sentir vergonha ou preguiça de rodar vários passos de uma vez, mesmo que vá apagar depois! Fazer um rollback ou migrar um banco de dados em produção para corrigir problemas é muito mais doloroso do que os passos descritos aqui.&lt;/p&gt;
&lt;p&gt;Abraço!&lt;/p&gt;</content:encoded><category>php</category></item><item><title>Tutorial: como compilar o PHP</title><link>https://codamos.com.br/tutorial-compilar-php/</link><guid isPermaLink="true">https://codamos.com.br/tutorial-compilar-php/</guid><description>Saber como compilar o PHP vai abrir uma das poucas portas necessárias para contribuir com a linguagem. Assim que você se familiarizar com este processo vai ser muito mais fácil para você contribuir de</description><pubDate>Mon, 24 May 2021 09:27:00 GMT</pubDate><content:encoded>&lt;p&gt;Saber como compilar o PHP vai abrir uma das poucas portas necessárias para contribuir com a linguagem. Assim que você se familiarizar com este processo vai ser muito mais fácil para você contribuir de diversas maneiras: rodando testes e fazendo upload de reports, escrevendo novos testes e reportando ou corrigindo bugs.&lt;/p&gt;
&lt;p&gt;Eu escrevi este tutorial como um esforço inspirado pelo &lt;a href=&quot;https://blog.krakjoe.ninja/2021/05/avoiding-busses.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;post do Joe sobre o Bus Factor que assombra a linguagem&lt;/a&gt; nos dias atuais. Na minha opinião o post é bem alarmista, mas necessário. Já que meu tempo é escasso, faz mais sentido para mim multiplicar o conhecimento em vez de tentar contribuir com o código do PHP sozinho.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/php/php-src&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;A gente vai utilizar o código fonte do PHP, disponível no Github. Você pode clicar aqui para visitar a página.&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;post__toc&quot;&gt;
&lt;h3&gt;Navegação rápida&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo0al20g3ta&quot;&gt;O código é separado entre core (/Zend) e extensões (/ext)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo0al20g3tb&quot;&gt;Como seguir este tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo0al20g3tc&quot;&gt;Preparação do ambiente: pacotes necessários para compilar PHP&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo0al20g3td&quot;&gt;gcc&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo0al20g3te&quot;&gt;libc-dev&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo0al20g3tf&quot;&gt;autoconf&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo0al20g3tg&quot;&gt;bison&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo0al20g3th&quot;&gt;re2c&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo0al20g3ti&quot;&gt;make&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo0al20g3tj&quot;&gt;Existem diferentes passos da compilação, vamos entender o motivo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo0al20g3tk&quot;&gt;Vamos compilar o PHP a partir do código fonte&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo0al20g3tl&quot;&gt;Instale os pacotes necessários&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo0al20g3tm&quot;&gt;Construa o script de configuração&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo0al20g3tn&quot;&gt;Gere o arquivo Makefile&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo0al20g3to&quot;&gt;Compilando o código fonte do PHP utilizando Make&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo0al20g3tp&quot;&gt;Bora rodar os testes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo0al20g3tq&quot;&gt;(Opcional) Instale o PHP&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo0al20g3tr&quot;&gt;Erros e problemas comuns&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo0al20g3ts&quot;&gt;Eu segui este tutorial passo a passo e não consegui compilar o PHP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo0al20g3tt&quot;&gt;Como adivinhar quais extensões eu posso adicionar à minha configuração?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo0al20g3tu&quot;&gt;Eu ainda estou tendo problemas mesmo seguindo este tutorial passo a passo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo0al20g3tv&quot;&gt;Como saber quais extensões estão disponíveis?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo0al20g3u0&quot;&gt;E se eu quiser utilizar bibliotecas modificadas ou não quiser as instalar no sistema todo?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo0al20g3u1&quot;&gt;Eu consegui compilar o PHP mas não encontro o binário&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo0al20g3u2&quot;&gt;Obrigado, comunidade, por me ajudar a construi este artigo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fo0al20g3u3&quot;&gt;E agora?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id=&quot;mcetoc_1fo0al20g3ta&quot;&gt;O código é separado entre core (/Zend) e extensões (/ext)&lt;/h2&gt;
&lt;p&gt;Antes de começar eu preciso te dar uma explicação ultra simplificada sobre a estrutura de pastas do PHP. A gente tem duas pastas:  &lt;code&gt;/Zend&lt;/code&gt; e &lt;code&gt;/ext&lt;/code&gt;.&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/18/zend-ext-folders.png&quot; alt=&quot;Pastas /Zend e /ext colocadas em evidência. Screenshot tomada da página do repositório no Github.&quot; width=&quot;924&quot; height=&quot;629&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Pastas /Zend e /ext colocadas em evidência. Screenshot tomada da página do repositório no Github.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;code&gt;/Zend&lt;/code&gt; contém o código da Máquina Virtual, também conhecida como Zend Virtual Machine ou Zend VM. Os códigos desta pasta são responsáveis pela tokenização, interpretação, compilação, gerenciamento da pilha de execução e, em geral, rodar código PHP.&lt;/p&gt;
&lt;p&gt;Se você não fazia ideia que o PHP tinha uma Máquina Virtual, considere também ler &lt;a href=&quot;/php-8-jit/&quot;&gt;este post que explica sobre como PHP e seu compilador Just In Time funcionam&lt;/a&gt;, aqui você entende como o PHP funciona desde o seu código fonte, passando pela compilação até o tempo de execução. Não é complicado, não. Dê uma olhadinha 😉.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;/ext&lt;/code&gt; é onde a mágica acontece! Esta é a pasta para as extensões suportadas pelo time de desenvolvimento do PHP. Toda função e classe que existe no PHP está descrita dentro desta pasta. Por exemplo, dentro de &lt;code&gt;/ext/standard&lt;/code&gt; você encontra todas as funções da biblioteca padrão (SPL - Standard PHP Library). &lt;a href=&quot;https://github.com/php/php-src/blob/230ccda431a18cb5d479bc1857b5f785331dca09/ext/standard/php_string.h&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Você pode ver as funções da SPL para manipulação de strings aqui&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A forma mais fácil de entender a &lt;code&gt;/ext&lt;/code&gt; é sempre lembrar que toda extensão PHP é na verdade uma interface para uma biblioteca escrita em C. Coisas que o PHP não poderia fazer sozinho (carregar DLLs, por exemplo) ou que não faria de forma tão performática (leitura de metadados de imagem no formato EXIF) são escritas aqui em C e disponibilizadas à linguagem PHP.&lt;/p&gt;
&lt;p&gt;O motivo principal de eu te explicar sobre as pastas  &lt;code&gt;/Zend&lt;/code&gt; e &lt;code&gt;/ext/&lt;/code&gt; é que você sempre vai precisar compilar  &lt;code&gt;/Zend&lt;/code&gt; quando compilar PHP. Mas você pode escolher a dedo quais extensões você quer compilar. Isto é muito útil quando se quer rodar testes ou depurar partes específicas do código.&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1fo0al20g3tb&quot;&gt;Como seguir este tutorial&lt;/h2&gt;
&lt;p&gt;Eu imagino que você queira rodar os códigos aqui na sua máquina local, o que pode te induzir ao erro por diversos motivos: versões de pacote que não batem, pacotes quebrados, dependências que não vão te permitir atualizar...&lt;/p&gt;
&lt;p&gt;Já que eu quero MUITO que você consiga compilar o PHP, eu vou rodar tudo dentro de um container docker vazio. Você não precisa disso para desenvolvimento no dia a dia se não quiser, mas eu recomendo demais que você utilize &lt;em&gt;Docker&lt;/em&gt; pelo menos nas primeiras vezes que compilar PHP &lt;strong&gt;para evitar distrações inúteis&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Rode o comando abaixo. Isto vai subir um container &lt;em&gt;Docker&lt;/em&gt; quase vazio, com pouquíssimas bibliotecas e programas instalados. &lt;strong&gt;Todos os comandos deste tutorial consideram que você está os executando dentro deste container.&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ docker run --rm -it alpine:3.13
/ #
&lt;/code&gt;&lt;/pre&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/18/running-docker-alpine.png&quot; alt=&quot;Uma screenshot mostrando uma sessão bash utilizando o comando &amp;quot;docker run --rm -it alpine:3.13&amp;quot;&quot; width=&quot;848&quot; height=&quot;578&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Uma screenshot mostrando uma sessão bash utilizando o comando &quot;docker run --rm -it alpine:3.13&quot;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Ao executar o comando acima você terá aberto uma sessão bash &lt;em&gt;dentro do container&lt;/em&gt;. E assim que você sair do container (com o comando &lt;em&gt;exit&lt;/em&gt;), o container será destruído.&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1fo0al20g3tc&quot;&gt;Preparação do ambiente: pacotes necessários para compilar PHP&lt;/h2&gt;
&lt;p&gt;O código fonte do PHP tem várias dependências: algumas relacionadas à compilação do código em C, outras sobre tokenização e interpretação, outras são opcionais dependendo de quais extensões você quiser instalar.&lt;/p&gt;
&lt;p&gt;Os requisitos que eu vou listar aqui são o mínimo necessário para compilar o PHP, sem extensões. Quando você adicionar outras extensões vai precisar adicionar mais dependências a esta lista.&lt;/p&gt;
&lt;p&gt;Abaixo eu vou te explicar cada dependência para tornar tudo ao menos um pouquinho mais claro pra ti.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fo0al20g3td&quot;&gt;gcc&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://gcc.gnu.org/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;GCC (GNU C Compiler)&lt;/a&gt; é um compilador C livre, utilizado pela maioria dos projetos C mundo afora. Este compilador transforma código C em código de máquina, que seu computador consegue rodar.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fo0al20g3te&quot;&gt;libc-dev&lt;/h3&gt;
&lt;p&gt;A linguagem C é bem crua e não oferece ferramentas para lidar com strings, arquivos, rede e por aí vai. Pra isso &lt;a href=&quot;https://www.gnu.org/software/libc/manual/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;a biblioteca libc&lt;/a&gt; vem para salvar o dia: ela possui várias funções que tornam o desenvolvimento com C muito mais simples. Você provavelmente já viu &lt;em&gt;stdlib.h, stdio.h&lt;/em&gt; ou &lt;em&gt;string.h &lt;/em&gt;em algum lugar. Estes arquivos .h (e vários outros) são da biblioteca &lt;em&gt;libc&lt;/em&gt;.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fo0al20g3tf&quot;&gt;autoconf&lt;/h3&gt;
&lt;p&gt;Autoconf é uma ferramenta para gerar configuração de build. Este programa é necessário para quando você executar o passo &lt;code&gt;buildconf&lt;/code&gt;, descrito neste texto.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fo0al20g3tg&quot;&gt;bison&lt;/h3&gt;
&lt;p&gt;Bison é um gerador de interpretadores. Sempre que você encontrar um arquivo com a extensão &lt;code&gt;.y&lt;/code&gt;, pode ter certeza de que o processo de build do PHP vai utilizar &lt;em&gt;Bison&lt;/em&gt; para transformar aquele arquivo &lt;code&gt;.y&lt;/code&gt; em um arquivo &lt;code&gt;.c&lt;/code&gt; que sabe como interpretar tokens lá definidos.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fo0al20g3th&quot;&gt;re2c&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://re2c.org/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Re2C é uma ferramenta responsável por compilar expressões regulares em lexers performáticos em C&lt;/a&gt;.&lt;a href=&quot;https://re2c.org/&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fo0al20g3ti&quot;&gt;make&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.gnu.org/software/make/&quot;&gt;Make é uma ferramenta versátil de automação de build.&lt;/a&gt; Esta ferramenta lê definições de um arquivo chamado &lt;em&gt;Makefile&lt;/em&gt; que explica quais comandos precisam ser executados em cada passo da build.&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1fo0al20g3tj&quot;&gt;Existem diferentes passos da compilação, vamos entender o motivo&lt;/h2&gt;
&lt;p&gt;Quando a gente compila código em C, normalmente a gente escolhe uma máquina alvo: uma arquitetura de CPU específica, um sistema operacional específico... Um binário compilado para Windows não vai rodar no Linux sem algum tipo de emulação. De forma semelhante, um programa compilado para uma CPU 64-bit não vai rodar numa CPU 32-bit.&lt;/p&gt;
&lt;p&gt;Isso tudo fica ainda mais complicado quando você leva as CPUs em consideração: cada CPU pode ter sua própria maneira de processar opcodes, ler memória, comunicar com o barramento, otimizar certas operações... O trabalho do &lt;em&gt;gcc&lt;/em&gt; é, dado uma CPU e Sistema Operacional alvos, transformar código em C em binários específicos para aquela CPU e sistema operacional.&lt;/p&gt;
&lt;p&gt;Com todos estes detalhes fica difícil escrever um único Makefile que consiga capturar todos os requisitos de todas plataformas e CPUs possíveis. O que o projeto PHP faz (e isto é normal para projetos grandes em C) é gerar um Makefile antes da build.&lt;/p&gt;
&lt;p&gt;O projeto utiliza várias macros &lt;em&gt;m4 &lt;/em&gt;e gera um script chamado &lt;code&gt;configure&lt;/code&gt; a partir delas. Este script quando executado, vai gerar um &lt;em&gt;Makefile&lt;/em&gt; específico para a sua CPU e Sistema Operacional.&lt;/p&gt;
&lt;p&gt;Pode parecer um pouco estranho agora, mas vamos seguir o passo a passo e provavelmente tudo vai ficar mais claro.&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1fo0al20g3tk&quot;&gt;Vamos compilar o PHP a partir do código fonte&lt;/h2&gt;
&lt;h3 id=&quot;mcetoc_1fo0al20g3tl&quot;&gt;Instale os pacotes necessários&lt;/h3&gt;
&lt;p&gt;Para instalar os pacotes mencionados acima no Alpine Linux (no nosso container Docker), basta rodar os comandos a seguir:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/ # apk add gcc autoconf libc-dev bison re2c make
&lt;/code&gt;&lt;/pre&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/18/install-deps.png&quot; alt=&quot;Dependências do PHP instaladas.&quot; width=&quot;1688&quot; height=&quot;1198&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Dependências do PHP instaladas.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Eu também vou baixar o programa cURL pra gente poder baixar o código fonte do PHP a partir do Github.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/ # apk add curl
/ # cd /opt
/opt # curl -L https://github.com/php/php-src/archive/refs/heads/master.zip -o php.zip
/opt # unzip php.zip
/opt # cd php-src-master/
/opt # ls -la
&lt;/code&gt;&lt;/pre&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/18/php-src-ls-a.png&quot; alt=&quot;Listando arquivos da pasta /opt/php-src-master que acabamos de baixar usando cURL.&quot; width=&quot;1716&quot; height=&quot;1176&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Listando arquivos da pasta /opt/php-src-master que acabamos de baixar usando cURL.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Se você rodou os comandos acima, você deverá estar na pasta &lt;em&gt;/opt/php-src-master&lt;/em&gt; e no ponto para começar o processo de compilação.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fo0al20g3tm&quot;&gt;Construa o script de configuração&lt;/h3&gt;
&lt;p&gt;Toda máquina tem suas especificidades. Seu processador provavelmente tem uma arquitetura diferente do meu, do seu amigo ou de um provedor de Cloud. Já que C precisa de informações muito específica sobre o processador alvo (e outras coisinhas mais) a gente usa um gerador de configurações.&lt;/p&gt;
&lt;p&gt;Rode o comando abaixo e você vai gerar um script &lt;code&gt;configure&lt;/code&gt;  como resultado:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/opt/php-src-master # ./buildconf
&lt;/code&gt;&lt;/pre&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/18/buildconf.png&quot; alt=&quot;Resultados da execução do script ./buildconf&quot; width=&quot;2292&quot; height=&quot;912&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Resultados da execução do script ./buildconf&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Este passo utiliza várias macros &lt;em&gt;.m4&lt;/em&gt; espalhadas pelo projeto todo para compilar o script &lt;code&gt;configure&lt;/code&gt;, utilizando a ferramenta &lt;code&gt;autoconf&lt;/code&gt;. Como isso tudo funciona está fora do escopo deste tutorial, mas pode entrar em contato comigo se precisar de mais detalhes.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fo0al20g3tn&quot;&gt;Gere o arquivo Makefile&lt;/h3&gt;
&lt;p&gt;Agora que a gente tem o script &lt;code&gt;configure&lt;/code&gt; é só executar para obter o builder automatizado: o Makefile.&lt;/p&gt;
&lt;p&gt;Execute &lt;code&gt;./configure&lt;/code&gt; com o parâmetro &lt;code&gt;--disable-all&lt;/code&gt; pra evitar que quaisquer extensões opcionais como a FFI ou SimpleXML sejam instaladas.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/opt/php-src-master # ./configure --disable-all
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;O que &lt;em&gt;configure&lt;/em&gt; faz é verificar a arquitetura, ferramentas e bibliotecas disponíveis na máquina local e seus respectivos diretórios. Toda esta informação é então compilada num arquivo &lt;em&gt;Makefile&lt;/em&gt;:&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/18/configure-checking-tools.png&quot; alt=&quot;Configure está verificando a arquitetura do sistema, ferramentas e bibliotecas instaladas.&quot; width=&quot;1254&quot; height=&quot;1236&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;&lt;em&gt;Configure&lt;/em&gt; está verificando a arquitetura do sistema, ferramentas e bibliotecas instaladas.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;O &lt;em&gt;Makefile&lt;/em&gt; gerado após este passo pode ser visto aqui:&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/18/makefile-created.png&quot; alt=&quot;O passo configure gerou um Makefile no mesmo diretório.&quot; width=&quot;2276&quot; height=&quot;1370&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;O passo &lt;em&gt;configure&lt;/em&gt; gerou um Makefile no mesmo diretório.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;mcetoc_1fo0al20g3to&quot;&gt;Compilando o código fonte do PHP utilizando Make&lt;/h3&gt;
&lt;p&gt;Agora que o &lt;em&gt;Makefile&lt;/em&gt; está disponível, precisamos apenas executar o comando &lt;code&gt;make&lt;/code&gt; e pronto! Eu vou adicionar a opção &lt;code&gt;-j8&lt;/code&gt; para aumentar o número de cores utilizados durante a compilação.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/opt/php-src-master # make -j8
&lt;/code&gt;&lt;/pre&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/18/make-compile.png&quot; alt=&quot;Ao rodar &amp;quot;make&amp;quot; vários objetos são compilados.&quot; width=&quot;2878&quot; height=&quot;710&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Ao rodar &quot;make&quot; vários objetos são compilados.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Se tudo correr bem, uma tela de sucesso parecida com a seguinte deverá aparecer e você então poderá rodar os testes.&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/18/make-succeeded.png&quot; alt=&quot;Compilação completa com a mensagem &amp;quot;Build complete&amp;quot;. Podemos rodar os testes agora.&quot; width=&quot;958&quot; height=&quot;590&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Compilação completa com a mensagem &quot;Build complete&quot;. Podemos rodar os testes agora.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Os binários ficam disponíveis na pasta &lt;code&gt;sapi&lt;/code&gt;. Lá nós podemos encontrar diferentes binários como o FPM e CLI.&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/18/compiled-targets.png&quot; alt=&quot;Binários dentro da pasta &amp;quot;sapi/&amp;quot;. A imagem mostra a execução do comando &amp;quot;php -v&amp;quot; utilizando o binário CLI.&quot; width=&quot;2388&quot; height=&quot;928&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Binários dentro da pasta &quot;sapi/&quot;. A imagem mostra a execução do comando &quot;php -v&quot; utilizando o binário CLI.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;mcetoc_1fo0al20g3tp&quot;&gt;Bora rodar os testes&lt;/h3&gt;
&lt;p&gt;Rodar os testes não vai apenas te mostrar que PHP está funcionando da forma esperada, mas também lhe dá a oportunidade de compartilhar os resultados com a comunidade online. Os testes ficam disponibilizados &lt;a href=&quot;https://qa.php.net/reports/run_tests.php&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;aqui&lt;/a&gt; e podem ser utilizados por outras pessoas para coletar informação o suficiente pra resolver bugs (&lt;a href=&quot;https://twitter.com/geekcom2/status/1389920857724751874&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;obrigado pela dica Daniel @geekcom2!&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Vamos rodar os testes utilizando a ferramenta Make:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/opt/php-src-master # make test
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Se PHP falhar qualquer teste, você receberá um resultado parecido com o seguinte:&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/18/test-failed.png&quot; alt=&quot;Tela mostrando testes que falharam e a pergunta &amp;quot;Você quer enviar este relatório de testes agora? [Sim/Não]&amp;quot;.&quot; width=&quot;1776&quot; height=&quot;1088&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Tela mostrando testes que falharam e a pergunta &quot;Você quer enviar este relatório de testes agora? [Sim/Não]&quot;.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Ao escolher enviar o relatório você já estará contribuindo com a comunidade PHP. Bacana, né?&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fo0al20g3tq&quot;&gt;(Opcional) Instale o PHP&lt;/h3&gt;
&lt;p&gt;Se você estiver feliz com a versão que acabou de compilar e gostaria de tornar seu binário PHP disponível para todo o sistema, basta rodar a tarefa &lt;em&gt;install &lt;/em&gt;do seu Makefile:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/opt/php-src-master # make install
&lt;/code&gt;&lt;/pre&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/18/make-install.png&quot; alt=&quot;Resultado da tarefa &amp;quot;make install&amp;quot;. Ilustra que &amp;quot;php -v&amp;quot; mostra a versão &amp;quot;8.1.0-dev&amp;quot;, mais atual no momento em que escrevo este tutorial.&quot; width=&quot;1222&quot; height=&quot;1064&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Resultado da tarefa &quot;make install&quot;. Ilustra que &quot;php -v&quot; mostra a versão &quot;8.1.0-dev&quot;, mais atual no momento em que escrevo este tutorial.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Eu não recomendo instalar a versão compilada do PHP a menos que você saiba muito bem o que está fazendo. Se você precisar desta versão só para testar algumas coisas, utilize um &lt;em&gt;alias&lt;/em&gt; ou adicione à variável &lt;em&gt;PATH&lt;/em&gt; temporariamente.&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1fo0al20g3tr&quot;&gt;Erros e problemas comuns&lt;/h2&gt;
&lt;p&gt;Se você sabe programar em C isto provavelmente não vai te afetar muito porque provavelmente já tem o costume de usar algumas convenções. Para quem programa somente em PHP eu resolvi coletar algumas dicas que vão facilitar o processo um pouquinho.&lt;/p&gt;
&lt;p&gt;Eu coletei as dicas abaixo perguntando a outros membros da comunidade no twitter e através de pesquisas com usuários deste site. Aqui vai um resumo dos problemas e soluções.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fo0al20g3ts&quot;&gt;Eu segui este tutorial passo a passo e não consegui compilar o PHP&lt;/h3&gt;
&lt;p&gt;Eu duvido que este caso aconteça com muita frequência porque estamos usando um ambiente isolado com &lt;em&gt;Docker&lt;/em&gt;, as chances de algo dar errado sem que você tenha modificado uma linha sequer são baixíssimas.&lt;/p&gt;
&lt;p&gt;Mas caso este seja mesmo o caso, ou se você tiver mudado alguma coisa e a build quebrou, a maior dica que eu posso lhe dar é: leia a mensagem de erro. Sério, leia a mensagem de erro!&lt;/p&gt;
&lt;p&gt;A minha intenção não é te fazer sentir inferior! Acontece que a maioria de nós, devs PHP, ignoramos as mensagens de erro de compiladores C porque a gente tem o costume de ver coisas coloridas no terminal, que tornam muito fácil identificar onde está o problema. Isto não é comum em C.&lt;/p&gt;
&lt;p&gt;Mas normalmente o problema é descrito na última mensagem impressa na tela, porque as boas práticas em C dizem que assim que um problema acontecer, o código deve abortar o quanto antes.&lt;/p&gt;
&lt;p&gt;Se você não entende inglês bem o suficiente, você vai precisar adivinhar baseado em alguns símbolos.&lt;/p&gt;
&lt;p&gt;Por exemplo, ao habilitar a extensão &lt;em&gt;simplexml&lt;/em&gt; a nnossa compilação já não vai mais funcionar por algum motivo:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/opt/php-src-master # ./configure --disable-all --enable-simplexml
&lt;/code&gt;&lt;/pre&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/18/enabling-simplexml.png&quot; alt=&quot;Rodando &amp;quot;configure&amp;quot; com a opção &amp;quot;--enable-simplexml&amp;quot;.&quot; width=&quot;845&quot; height=&quot;601&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Rodando &quot;configure&quot; com a opção &quot;--enable-simplexml&quot;.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Ao utilizar a flag &lt;em&gt;&quot;--disable-all&quot;&lt;/em&gt; nós desabilitamos todas extensões possíveis, incluindo a extensão &lt;em&gt;libxml&lt;/em&gt; que adiciona suporte a XML. Aqui a mensagem de erro que recebemos:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;configure: error: SimpleXML extension requires LIBXML extension, add --with-libxml&lt;/p&gt;
&lt;/blockquote&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/18/configure-libxml-error.png&quot; alt=&quot;Rodando &amp;quot;configure&amp;quot; com a flag &amp;quot;--enable-simplexml&amp;quot; gera um erro dizendo que a extensão LIBXML não está disponível.&quot; width=&quot;845&quot; height=&quot;597&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Rodando &quot;configure&quot; com a flag &quot;--enable-simplexml&quot; gera um erro dizendo que a extensão LIBXML não está disponível.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;O próprio programa nos instrui que ao adicionar &lt;em&gt;&quot;--with-libxml&quot;&lt;/em&gt; o problema deverá ser resolvido.&lt;/p&gt;
&lt;p&gt;Vamos rapidamente visitar o manual da extensão simplexml. Em &lt;em&gt;&lt;a href=&quot;https://www.php.net/manual/pt_BR/simplexml.requirements.php&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&quot;Instalação &amp;gt; Requisitos&quot;&lt;/a&gt; &lt;/em&gt;nós encontramos mais informações sobre quais extensões e bibliotecas são necessárias, e mais outras dicas de como compilar esta extensão.&lt;/p&gt;
&lt;p&gt;Tanto a página quanto o comando &lt;code&gt;configure&lt;/code&gt; dizem a mesma coisa: é preciso habilitar a &lt;a href=&quot;https://www.php.net/manual/pt_BR/book.libxml.php&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;extensão libxml&lt;/a&gt;. Então teoricamente ao adicionar &lt;code&gt;--with-libxml&lt;/code&gt; ao configure, nosso problema deverá ser resolvido.&lt;/p&gt;
&lt;p&gt;Mas agora estamos vacinados e sabemos que é possível visitar a página da extensão libxml antes de tentar compilar de novo para que possamos instalar suas dependências. Vamos abrir a &lt;a href=&quot;https://www.php.net/manual/pt_BR/libxml.requirements.php&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;página de requisitos da extensão libxml&lt;/a&gt; e verificar suas dependências: a extensão depende da biblioteca &lt;em&gt;libxml&lt;/em&gt; na versão 2.6.0 ou superior. Vamos instalar esta biblioteca e depois compilar o PHP novamente:&lt;/p&gt;
&lt;pre&gt;/opt/php-src-master # apk add libxml2-dev&lt;br&gt;/opt/php-src-master # ./configure --disable-all --with-libxml --enable-simplexml&lt;/pre&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/18/libxml2-dev-configure-passes.png&quot; alt=&quot;Adicionamos o pacote libxml2-dev e executamos o comando configure com as extensões libxml (&amp;quot;--with-libxml&amp;quot;) e simplexml (&amp;quot;--enable-simplexml&amp;quot;).&quot; width=&quot;911&quot; height=&quot;686&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Adicionamos o pacote &lt;em&gt;libxml2-dev&lt;/em&gt; e executamos o comando &lt;i&gt;configure&lt;/i&gt; com as extensões libxml (&quot;--with-libxml&quot;) e simplexml (&quot;--enable-simplexml&quot;).&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Agora é só rodar &lt;em&gt;Make&lt;/em&gt; novamente para que os binários dentro de &lt;code&gt;&lt;em&gt;/sapi&lt;/em&gt;&lt;/code&gt; fiquem atualizados e com suporte à extensão SimpleXML.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fo0al20g3tt&quot;&gt;Como adivinhar quais extensões eu posso adicionar à minha configuração?&lt;/h3&gt;
&lt;p&gt;Isto é um problema comum em projetos em C. Eu ainda não vi um projeto em C que utilize um gerenciador de dependências parecido com o Composer our NPM.&lt;/p&gt;
&lt;p&gt;Com programas em C você normalmente deveria resolver as dependências manualmente e, na verdade, isto é muito benéfico e eficiente. Por exemplo, esta boa pratica reduz o tamanho do binário a ser construído porque várias bibliotecas e dependências são conectadas de forma dinâmica (arquivos .dll ou .so) quando o programa é executado em vez de copiar e compilar todo seu código fonte.&lt;/p&gt;
&lt;p&gt;O ideal é que antes de habilitar uma extensão você busque por sua página no manual do PHP. Toda extensão padrão do PHP têm um manual que inclui uma página de Instalação, requisitos e dependências.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fo0al20g3tu&quot;&gt;Eu ainda estou tendo problemas mesmo seguindo este tutorial passo a passo&lt;/h3&gt;
&lt;p&gt;Pode ser que o artigo envelheceu: PHP é um projeto muito ativo, as coisas mudam e você precisa conseguir se adaptar. As ideias principais deste tutorial vão te acompanhar na jornada, mas talvez você precise investigar um pouco por si só.&lt;/p&gt;
&lt;p&gt;Normalmente quando mudanças bruscas acontecem, elas ficam documentadas no código fonte em dois arquivos: &lt;a href=&quot;https://github.com/php/php-src/blob/master/UPGRADING&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;UPGRADING&lt;/a&gt; e &lt;a href=&quot;https://github.com/php/php-src/blob/master/UPGRADING.INTERNALS&quot; rel=&quot;nofollow&quot;&gt;UPGRADING INTERNALS&lt;/a&gt;. Dá uma lida nestes arquivos se você tiver algum problema e tem certeza de que os passos e configurações que você usou já funcionaram algum dia.&lt;/p&gt;
&lt;p&gt;Obrigado novamente &lt;a href=&quot;https://twitter.com/geekcom2&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Daniel @geekcom2&lt;/a&gt; pela dica!&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fo0al20g3tv&quot;&gt;Como saber quais extensões estão disponíveis?&lt;/h3&gt;
&lt;p&gt;Existem várias flags de compilação disponíveis que a gente pode passar para o script &lt;code&gt;configure&lt;/code&gt; como &lt;em&gt;--enable-ffi&lt;/em&gt; ou &lt;em&gt;--enable-simplexml&lt;/em&gt;. Mas como encontrar todas elas?&lt;/p&gt;
&lt;p&gt;O ideal é que você saiba quais extensões quer habilitar, verifique as páginas do manual de cada uma e a partir de lá entenda quais extensões e flags são necessárias.&lt;/p&gt;
&lt;p&gt;Se você não quiser ou não puder visitar as páginas do manual, verifique o código offline. Depois de rodar &lt;code&gt;buildconf&lt;/code&gt; o arquivo &lt;code&gt;configure&lt;/code&gt; será criado no diretório &lt;em&gt;php-src&lt;/em&gt;. Basta rodar &lt;code&gt;configure&lt;/code&gt; com a flag &lt;code&gt;--help&lt;/code&gt;:  &lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/opt/php-src-master # ./configure --help
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;O comando acima vai mostrar uma lista de flags de compilação e variáveis de ambiente que você pode mudar antes de gerar seu Makefile.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fo0al20g3u0&quot;&gt;E se eu quiser utilizar bibliotecas modificadas ou não quiser as instalar no sistema todo?&lt;/h3&gt;
&lt;p&gt;As vezes você vai ter a necessidade de utilizar uma versão específica de uma biblioteca para satisfazer a instalação do PHP, mas seu sistema já utiliza uma versão diferente. Mudar a versão no sistema todo as vezes não é a melhor opção...&lt;/p&gt;
&lt;p&gt;Uma opção para resolver este problema é utilizar um ambiente isolado como uma máquina virtual ou um container &lt;em&gt;Docker&lt;/em&gt; por exemplo. Mas isto não resolve todos os casos.&lt;/p&gt;
&lt;p&gt;Outra opção é baixar e compilar manualmente a biblioteca em outro diretório. Desta forma você pode compilar a biblioteca sem instalar no sistema, criando objetos dinâmicos (arquivos .dll, .so ou .dylib) que não precisam ser utilizados pelo resto do sistema.&lt;/p&gt;
&lt;p&gt;Se você escolher compilar uma biblioteca manualmente, você precisa dizer ao &lt;code&gt;configure&lt;/code&gt; em quais pastas procurar determinadas bibliotecas. Você pode fazer isso através de variáveis de ambiente. Tem até um &lt;a href=&quot;https://www.php.net/manual/pt_BR/faq.build.php#faq.build.not-found&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;FAQ&lt;/a&gt; no site oficial do PHP sobre isso.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/opt/php-src-master # export LDFLAGS=-L/opt/a-biblioteca-que-voce-compilou
/opt/php-src-master # ./configure
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;mcetoc_1fo0al20g3u1&quot;&gt;Eu consegui compilar o PHP mas não encontro o binário&lt;/h3&gt;
&lt;p&gt;Todos os binários (executáveis) do PHP ficam dentro da pasta &lt;code&gt;sapi/&lt;/code&gt;. Lá você encontra diferentes binários como o FPM, CLI e Embed. Utilize o que for mais adequado para seu caso de uso.&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1fo0al20g3u2&quot;&gt;Obrigado, comunidade, por me ajudar a construi este artigo&lt;/h2&gt;
&lt;p&gt;Desta vez em vez de pesquisar e escrever tudo sozinho eu decidi pedir ajuda da comunidade brasileira de PHP, especialmente na seção de &lt;em&gt;Erros e problemas comuns&lt;/em&gt;. Eu vou deixar os nomes e perfis destas pessoas como forma de reconhecimento e agradecimento pela ajuda.&lt;/p&gt;
&lt;p&gt;Se você, assim como eu, gosta de fazer o PHP chorar, trate de seguir estas pessoas. Eu garanto conteúdo e sabedorias de alta qualidade:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Diana Arnos (&lt;a href=&quot;https://twitter.com/dianaarnos&quot;&gt;@dianaarnos&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Daniel (&lt;a href=&quot;https://twitter.com/geekcom2&quot;&gt;@geekcom2&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Leo Cavalcante (&lt;a href=&quot;https://twitter.com/leocavalcante&quot;&gt;@leocavalcante&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Marcel dos Santos (&lt;a href=&quot;https://twitter.com/marcelgsantos&quot;&gt;@marcelgsantos&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Vinícius Dias (&lt;a href=&quot;https://twitter.com/cviniciussdias&quot;&gt;@cviniciussdias&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Luis Machado Reis (&lt;a href=&quot;https://twitter.com/luismachadoreis&quot;&gt;@luismachadoreis&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Dev Frustrado (&lt;a href=&quot;https://twitter.com/geckones&quot;&gt;@geckones&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Robson Pierre (&lt;a href=&quot;https://twitter.com/robsonpiere&quot;&gt;@robsonpiere&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Algumas das contribuições foram diretas, outras apenas propagaram a minha voz para alcançar mais pessoas. Eu sou muito grato por toda a força que vocês me deram!&lt;/p&gt;
&lt;p&gt;Também não esqueça de me seguir no twitter se você gosta do tipo de conteúdo que eu compartilho e gostaria de ver coisas aleatórias sobre programação no seu feed: &lt;a href=&quot;https://twitter.com/nawarian&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;@nawarian&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1fo0al20g3u3&quot;&gt;E agora?&lt;/h2&gt;
&lt;p&gt;Agora que você se familiarizou com a compilação do PHP, vá em frente e rode alguns testes, quebra alguns deles brincando com o código C. Vai se divertir!&lt;/p&gt;
&lt;p&gt;Eu espero que este tutorial vá te ajudar a tomar mais um passo em direção a contribuir com a comunidade PHP. Nós precisamos de você!&lt;/p&gt;
&lt;p&gt;Até a próxima!&lt;/p&gt;</content:encoded><category>php</category></item><item><title>Guia completo: FFI em PHP</title><link>https://codamos.com.br/php-ffi/</link><guid isPermaLink="true">https://codamos.com.br/php-ffi/</guid><description>Antes de qualquer coisa, eu quero te dizer que eu comecei uma pequena série de vídeos onde eu implementei uma biblioteca em PHP para usar a biblioteca raylib (escrita em C) usando FFI. Você pode ver n</description><pubDate>Thu, 18 Mar 2021 11:18:00 GMT</pubDate><content:encoded>&lt;p&gt;Antes de qualquer coisa, eu quero te dizer que eu comecei uma pequena série de vídeos onde eu implementei uma biblioteca em PHP para usar a biblioteca raylib (escrita em C) usando FFI. Você pode ver no vídeo abaixo ou &lt;a href=&quot;https://youtu.be/wPbnjcvW-Tk&quot; target=&quot;null&quot; rel=&quot;nofollow&quot;&gt;neste link para o YouTube&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;iframe width=&quot;560&quot; height=&quot;315&quot; id=&quot;lbry-iframe&quot; src=&quot;https://lbry.tv/$/embed/php_ffi_ola_mundo/a6959afa7affbba52bb31e68fbfbd222af129261?r=HRN5EEjNyXcykeZ8RjgLX697DuZvpA7g&quot; allowfullscreen=&quot;allowfullscreen&quot; data-mce-fragment=&quot;1&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2&gt;O que é FFI e pra quê serve?&lt;/h2&gt;
&lt;p&gt;FFI ou &lt;a href=&quot;https://en.wikipedia.org/wiki/Foreign_function_interface&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Foreign Function Interface&lt;/a&gt; é uma técnica que permite programas utilizarem bibliotecas escritas em diferentes linguagens de programação. É bem mais rápido que usar RPC ou APIs porque o programa não vai se comunicar através de rede e, em vez disso, faz interface direta com a biblioteca.&lt;/p&gt;
&lt;p&gt;Para ser mais direto: ao utilizar FFI no seu programa PHP você será capaz de utilizar bibliotecas escritas em C, Rust, Golang ou quaisquer outras linguagens capazes de produzir uma ABI.&lt;/p&gt;
&lt;p&gt;É importante notar que você vai conseguir se comunicar com bibliotecas, não entre dois programas diferentes. Para comunicar dois programas você ainda vai precisar de algum mecanismo de comunicação em tempo real, e FFI não te ajuda em nada com isso!&lt;/p&gt;
&lt;p&gt;Ao utilizar FFI no PHP você será capaz de usar qualquer shared object que quiser em seu projeto: .dll no Windows, .so no Linux ou .dylib no MacOS.&lt;/p&gt;
&lt;p&gt;Com isso você tem a oportunidade de sair da &lt;a href=&quot;/php-8-jit/&quot;&gt;Máquina Virtual do PHP (Zend VM)&lt;/a&gt; e escrever quase qualquer coisa que você gostaria usando PHP. Utilizar bibliotecas como raylib ou libui não vai te obrigar a utilizar uma extensão em C (como nós fizemos &lt;a href=&quot;/jogos-em-php/&quot;&gt;neste post sobre como desenvolver jogos em PHP usando a extensão raylib&lt;/a&gt;).&lt;/p&gt;
&lt;h2&gt;FFI vai tornar meu código mais rápido?&lt;/h2&gt;
&lt;p&gt;Você talvez esteja imaginando que já que o FFI permite utilizar código escrito originalmente em C, o seu programa potencialmente será mais rápido do que seria em PHP. A linha de raciocínio não está necessariamente errada, mas você precisa levar em consideração que linguagens de programação não fazem mágica: elas fazem o que nós as comandamos fazer.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Em termos de tempo de CPU, chamar funções externas a partir do PHP utilizando FFI pode te custar duas vezes mais do que realizar a mesma operação em PHP puro.&lt;/strong&gt; Isto acontece porque a máquina virtual do PHP já é bem otimizada e fazer interface com código externo requer um processo de tradução que vai adicionar um certo custo de processamento.&lt;/p&gt;
&lt;p&gt;Isso é normal e todas linguagens que suportam FFI que eu vi até agora vão performar um pouquinho pior quando utilizam FFI.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mas você pode otimizar o consumo de memória!&lt;/strong&gt; Como você pôde ver no meu post sobre &lt;a href=&quot;/php-bitwise/&quot;&gt;Operações Binárias em PHP&lt;/a&gt;, cada variável do PHP tem um tipo interno zval e ele faz várias coisas pra tonar a vida do PHP mais fácil, como representar todo integer em PHP com o tipo INT64. Então o valor &lt;code&gt;0x10&lt;/code&gt; teria de ser armazenado como &lt;code&gt;0x0000000000000010&lt;/code&gt; em PHP (e todos os outros membros de zval terão seus ponteiros alocados).&lt;/p&gt;
&lt;p&gt;Então uma boa prática é tentar encontrar o equilíbrio entre processar coisas usando PHP e utilizar o FFI para lidar com objetos na memória. Desta forma você consegue otimizar o consumo de memória, que pode ou não impactar no seu tempo de CPU.&lt;/p&gt;
&lt;h2&gt;FFI ou Extensões em C, o que eu devo utilizar?&lt;/h2&gt;
&lt;p&gt;FFI normalmente é utilizado para prototipação: você dá os primeiros passos com FFI e depois migra o código para uma extensão escrita em C.&lt;/p&gt;
&lt;p&gt;Eu acho que se o seu código não se importa muito com performance (improvável, mas pode ser…) é de boa usar o FFI só para ampliar a capacidade do PHP. &lt;a href=&quot;https://www.php.net/manual/en/intro.ffi.php&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Mas não se esqueça que FFIs em PHP ainda são experimentais e você pode encontrar bugs ou mudanças na API podem acontecer de vez em quando&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Extensões em C deveriam normalmente ser escritas em código C, uma barreira para muitas pessoas acostumadas com PHP. Mas estas extensões se integram à Máquina Virtual do PHP, e por conta disso tendem a ser bem mais rápidas porque chamam código em C diretamente do C (nenhuma tradução é necessária) e mapeiam apenas o código que vai interfacear com o usuário final da extensão.&lt;/p&gt;
&lt;p&gt;Extensões são compiladas contra uma versão específica do PHP, e isso cria uma dependência bem chatinha que pode te impedir de atualizar a versão do PHP, por exemplo. Se você tiver disponibilidade pra atualizar a extensão por si e seguir o processo de integração que a comunidade propõe, menos mal. Mas ainda assim vai te custar alguns dias.&lt;/p&gt;
&lt;p&gt;FFIs sempre vão funcionar direto e não vão te impedir de atualizar a versão do PHP porque a &lt;a href=&quot;https://github.com/php/php-src/tree/master/ext/ffi&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;extensão FFI é parte do core do PHP&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Começando com FFI: vamos construir uma janela nativa usando a biblioteca raylib&lt;/h2&gt;
&lt;p&gt;Uma coisa que o PHP sozinho definitivamente não consegue fazer é manipular janelas nativas no sistema operacional. Existem algumas extensões como o PHP-GTK e &lt;a href=&quot;/jogos-em-php/&quot;&gt;a extensão raylib que nós vimos antes&lt;/a&gt;, outra opção é usar FFI.&lt;/p&gt;
&lt;p&gt;Eu vou escolher a &lt;a href=&quot;https://www.raylib.com/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Raylib&lt;/a&gt; como exemplo porque a sua interface é bem simplificada e gostosa de se trabalhar.&lt;/p&gt;
&lt;h3&gt;Instalando o shared object da raylib (biblioteca)&lt;/h3&gt;
&lt;p&gt;Para quem usa mac isto deveria ser bem simples utilizando o HomeBew:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ brew install raylib
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Existem alguns guias completos de como instalar em outros sistemas. Aqui você encontra guias sobre &lt;a href=&quot;https://github.com/raysan5/raylib/wiki/Working-on-Windows&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;como instalar no Windows&lt;/a&gt; e &lt;a href=&quot;https://github.com/raysan5/raylib/wiki/Working-on-GNU-Linux&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;como instalar no Linux&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Depois de instalar tudo você deverá ter um shared object disponível no seu sistema. No MacOS você pode ver o arquivo &lt;code&gt;libraylib.dylib&lt;/code&gt; dentro do diretório &lt;code&gt;/usr/local/Cellar/raylib/&amp;lt;versão&amp;gt;/lib&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ ls -la /usr/local/Cellar/raylib/3.5.0/lib
cmake           libraylib.351.dylib libraylib.dylib
libraylib.3.5.0.dylib   libraylib.a     pkgconfig
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No Windows você vai se preocupar em encontrar o arquivo &lt;code&gt;.dll&lt;/code&gt; e no GNU Linux você precisa encontrar o arquivo &lt;code&gt;.so&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Vamos primeiro prototipar nosso programa em C&lt;/h3&gt;
&lt;p&gt;A forma mais fácil de entender se o FFI está funcionando corretamente em PHP é entender se a coisa funciona em C em primeiro lugar. Faz sentido né?&lt;/p&gt;
&lt;p&gt;Então a primeira coisa que vamos fazer é construir um programa em C que utilize a raylib e que construa a nossa janela. Vamos criar um arquivo &lt;code&gt;hello_raylib.c&lt;/code&gt; com o seguinte conteúdo:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &quot;raylib.h&quot;

int main(void)
{
  Color white = { 255, 255, 255, 255 };
  Color red = { 255, 0, 0, 255 };

  InitWindow(
    800,
    600,
    &quot;Hello raylib from C&quot;
  );

  while (
    !WindowShouldClose()
  ) {
    ClearBackground(white);

    BeginDrawing();
      DrawText(
        &quot;Hello raylib!&quot;,
        400,
        300,
        20,
        red
      );
    EndDrawing();
  }

  CloseWindow();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;O código acima deve criar uma janela com dimensões 800x600 e o texto &quot;Hello raylib from C&quot; na barra de título. Dentro desta janela o texto “Hello raylib!” em cor vermelha deverá aparecer com origem no meio da janela.&lt;/p&gt;
&lt;p&gt;Vamos compilar e rodar o programa acima:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ gcc -o hello_raylib \
  hello_raylib.c -lraylib
$ ./hello_raylib
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Repare:&lt;/strong&gt; utilize o compilador C disponível em sua plataforma. No meu caso eu utilizo o &lt;code&gt;clang&lt;/code&gt; mas deveria ser mais ou menos a mesma coisa.&lt;/p&gt;
&lt;p&gt;Abaixo o resultado esperado.&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/16/raylib-window-c.png&quot; alt=&quot;Uma janela nativa com dimensões 800 por 600 e o título &amp;quot;Hello raylib from C&amp;quot; apresentando um texto em cor vermelha que diz &amp;quot;Hello raylib!&amp;quot;&quot; width=&quot;1315&quot; height=&quot;744&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Uma janela nativa com dimensões 800 por 600 e o título &quot;Hello raylib from C&quot; apresentando um texto em cor vermelha que diz &quot;Hello raylib!&quot;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3&gt;Agora com PHP! Vamos criar nosso arquivo de cabeçalho (header)&lt;/h3&gt;
&lt;p&gt;Para permitir que o PHP se comunique com o C (ou outras linguagens), nós primeiro precisamos criar uma interface. Em C esta interface é representada por arquivos de cabeçalho. Esta é exatamente a razão pela qual a maioria dos arquivos &lt;code&gt;.c&lt;/code&gt; têm um correspondente &lt;code&gt;.h&lt;/code&gt; no projeto: o arquivo de cabeçalho indica quais objetos e assinaturas de funções existem.&lt;/p&gt;
&lt;p&gt;Já que nós queremos referenciar o &lt;code&gt;libraylib.dylib&lt;/code&gt; a primeira linha do nosso cabeçålho deve conter o seguinte define, específico para FFI. Então vamos começar escrevendo o nosso &lt;code&gt;raylib.h&lt;/code&gt; que vai interfacear com o código PHP:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#define FFI_LIB &quot;libraylib.dylib&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Repare:&lt;/strong&gt; o arquivo referenciado pode mudar de acordo com seu sistema operacional.&lt;/p&gt;
&lt;p&gt;A Raylib tem várias funções, e &lt;a href=&quot;https://www.raylib.com/cheatsheet/cheatsheet.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;você pode verificar cada uma na cheatsheet oficial&lt;/a&gt;. Mas nós não precisamos importar todas as funções. Na verdade eu recomendo que você importe apenas as funções necessárias para o seu programa funcionar. No nosso caso nós precisamos de apenas 7 funções:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#define FFI_LIB &quot;libraylib.dylib&quot;

void InitWindow(
  int width,
  int height,
  const char *title
);
bool WindowShouldClose(void);
void ClearBackground(
  Color color
);
void BeginDrawing(void);
void DrawText(
  const char *text,
  int x,
  int y,
  int size,
  Color color
);
void EndDrawing(void);
void CloseWindow(void);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Repare que algumas assinaturas de função requerem tipos muito específicos que são oferecidos pela Raylib. As funções &lt;code&gt;ClearBackground&lt;/code&gt; e &lt;code&gt;DrawText&lt;/code&gt; exigem um argumento do tipo &lt;code&gt;Color&lt;/code&gt;, que nós também precisamos importar. Então vamos adicionar ao nosso arquivo de cabeçalho:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#define FFI_LIB &quot;libraylib.dylib&quot;

typedef struct Color {
  unsigned char r;
  unsigned char g;
  unsigned char b;
  unsigned char a;
} Color;

void InitWindow(int width, int height, const char *title);
// ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nosso arquivo &lt;strong&gt;raylib.h&lt;/strong&gt; agora está pronto para ser utilizado dentro do PHP.&lt;/p&gt;
&lt;h3&gt;Carregando o cabeçalho no PHP&lt;/h3&gt;
&lt;p&gt;Agora que nós temos um arquivo de cabeçalho nós podemos importá-lo utilizando a função &lt;a href=&quot;https://www.php.net/manual/en/ffi.load.php&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;FFI::load()&lt;/a&gt; desta maneira:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;?php

$ffi = FFI::load(
  __DIR__ . &apos;/raylib.h&apos;
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Com este objeto &lt;code&gt;$ffi&lt;/code&gt; nós podemos agora imitar o código em C que escrevemos antes. Vamos construir as variáveis &lt;code&gt;white&lt;/code&gt; e &lt;code&gt;red&lt;/code&gt; do tipo &lt;code&gt;Color&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;?php

$ffi = FFI::load(__DIR__ . &apos;/raylib.h&apos;);

$white = $ffi-&amp;gt;new(&apos;Color&apos;);
$white-&amp;gt;r = 255;
$white-&amp;gt;g = 255;
$white-&amp;gt;b = 255;
$white-&amp;gt;a = 255;

$red = $ffi-&amp;gt;new(&apos;Color&apos;);
$red-&amp;gt;r = 255;
$red-&amp;gt;a = 255;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Por padrão todos os campos do struct serão inicializados com um valor zero. No caso do &lt;code&gt;unsigned char&lt;/code&gt; (que varia entre 0 e 255) o valor zero é um inteiro &lt;code&gt;0&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Agora nós podemos facilmente construir a nossa janela e desenhar na tela:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;?php

$ffi = FFI::load(__DIR__ . &apos;/raylib.h&apos;);

// ...

$ffi-&amp;gt;InitWindow(
  800,
  600,
  &quot;Hello raylib from PHP&quot;
);

while (
  !$ffi-&amp;gt;WindowShouldClose()
) {
  $ffi-&amp;gt;ClearBackground(
    $white
  );

  $ffi-&amp;gt;BeginDrawing();
    $ffi-&amp;gt;DrawText(
      &quot;Hello raylib!&quot;,
      400,
      300,
      20,
      $red
    );
  $ffi-&amp;gt;EndDrawing();
}

$ffi-&amp;gt;CloseWindow();
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Temos uma janela usando a raylib no PHP!&lt;/h3&gt;
&lt;p&gt;Como você provavelmente percebeu, todas as funções em C definidas em &lt;code&gt;raylib.h&lt;/code&gt; podem ser utilizadas pelo PHP se utilizamos o objeto &lt;code&gt;$ffi&lt;/code&gt; para referenciá-las. As variáveis em C são mapeadas para PHP e vice-versa.&lt;/p&gt;
&lt;p&gt;O nosso arquivo PHP final e seu resultado ficaram assim:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;?php

$ffi = FFI::load(__DIR__ . &apos;/raylib.h&apos;);

$white = $ffi-&amp;gt;new(&apos;Color&apos;);
$white-&amp;gt;r = 255;
$white-&amp;gt;g = 255;
$white-&amp;gt;b = 255;
$white-&amp;gt;a = 255;

$red = $ffi-&amp;gt;new(&apos;Color&apos;);
$red-&amp;gt;r = 255;
$red-&amp;gt;a = 255;

$ffi-&amp;gt;InitWindow(800, 600, &quot;Hello raylib from PHP&quot;);
while (!$ffi-&amp;gt;WindowShouldClose()) {
  $ffi-&amp;gt;ClearBackground($white);

  $ffi-&amp;gt;BeginDrawing();
    $ffi-&amp;gt;DrawText(&quot;Hello raylib!&quot;, 400, 300, 20, $red);
  $ffi-&amp;gt;EndDrawing();
}

$ffi-&amp;gt;CloseWindow();
&lt;/code&gt;&lt;/pre&gt;
&lt;figure&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/16/raylib-window-php-ffi.png&quot; alt=&quot;Uma janela nativa com dimensões 800 por 600 e o título &amp;quot;Hello raylib from PHP&amp;quot; apresentando um texto em cor vermelha que diz &amp;quot;Hello raylib!&amp;quot;&quot; width=&quot;1365&quot; height=&quot;859&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Uma janela nativa com dimensões 800 por 600 e o título &quot;Hello raylib from PHP&quot; apresentando um texto em cor vermelha que diz &quot;Hello raylib!&quot;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/figure&gt;
&lt;h2&gt;Problemas comuns com FFI e como resolvê-los&lt;/h2&gt;
&lt;p&gt;Eu estive brincando com o FFI para tentar construir bindings bacanas para a Raylib em PHP e encontrei alguns problemas no caminho. Saber sobre estes problemas e como corrigi-los talvez possa lhe ser útil.&lt;/p&gt;
&lt;p&gt;A minha maior dica é: não misture o código da sua aplicação com código FFI. Extraia o FFI para uma biblioteca independente e adicione-a ao seu projeto utilizando o composer. Isto não vai resolver a maioria dos seus problemas, mas com certeza vai os isolar e tornar muito fácil a testagem.&lt;/p&gt;
&lt;h3&gt;FFI pode ser difícil de testar&lt;/h3&gt;
&lt;p&gt;No caso da Raylib em específico a gente não consegue testar muita coisa. Principalmente porque a raylib manipula janelas nativas e o PHP não tem uma forma fácil de fazer assertions deste tipo.&lt;/p&gt;
&lt;p&gt;Então tenha em mente que se você estiver escrevendo algo realmente fora do escopo normal do PHP, você vai precisar de outras ferramentas para conduzir seus testes. Tenha certeza, portanto, que estas ferramentas também rodam em outras plataformas.&lt;/p&gt;
&lt;p&gt;Por exemplo, é possível capturar o PID de uma janela procurando por seu título com xorg, e eu sei que de alguma forma a Windows API também nos permite fazer isso. &lt;strong&gt;Se você quer testar, você provavelmente vai precisar utilizar outras ferramentas que não o PHP para testar sua aplicação.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Também é importante lembrar que os testes não vão necessariamente agregar valor em todo lugar na sua aplicação. &lt;a href=&quot;/tdl-aprendizado-por-testes/&quot;&gt;Eu utilizo testes como uma ferramenta de aprendizado para que eu possa ter um ambiente seguro para testar novos conceitos aos poucos&lt;/a&gt; sem me importar muito sobre todas as dependências de uma vez e, infelizmente, a maioria dos frameworks PHP não me ajudaram muito enquanto estive trabalhando com a raylib. A minha solução para este caso é criar diferentes arquivos PHP que deveriam fazer uma única coisa, exatamente como casos de teste.&lt;/p&gt;
&lt;h3&gt;É difícil fazer análise estática&lt;/h3&gt;
&lt;p&gt;Eu não achei uma forma perfeita de resolver este problema. Ferramentas de análise estática como o &lt;a href=&quot;https://psalm.dev/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;psalm&lt;/a&gt; ficam doidinhas com código FFI.&lt;/p&gt;
&lt;p&gt;De volta ao snippet &lt;code&gt;$white&lt;/code&gt; e &lt;code&gt;$red&lt;/code&gt; vamos ver o motivo:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$white = $ffi-&amp;gt;new(&apos;Color&apos;);
$white-&amp;gt;r = 255;
$white-&amp;gt;g = 255;
$white-&amp;gt;b = 255;
$white-&amp;gt;a = 255;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Se você verificar a &lt;a href=&quot;https://www.php.net/manual/en/ffi.new.php&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;assinatura de FFI::new()&lt;/a&gt; vai sacar que ele retorna &lt;code&gt;FFI\CData&lt;/code&gt; ou &lt;code&gt;null&lt;/code&gt;. Este tipo CData é um objeto que deveria conter todos os membros do struct referenciado.&lt;/p&gt;
&lt;p&gt;Até onde eu sei o psalm não tem uma forma fácil de anotar que a variável &lt;code&gt;$white&lt;/code&gt; contém quatro campos do tipo integer: &lt;code&gt;$r&lt;/code&gt;, &lt;code&gt;$g&lt;/code&gt;, &lt;code&gt;$b&lt;/code&gt; e &lt;code&gt;$a&lt;/code&gt;. O psalm sequer vai conseguir saber que eles existem porque, bem, eles foram escritos em C nalgum outro lugar!&lt;/p&gt;
&lt;p&gt;Então o ideal é que você abstraia a lógica de FFI em algum tipo de classe Facade ou Adapter, que você vai prometer de pé juntinho que vai cobrir com testes o máximo que puder, e então pode dizer ao psalm para ignorar esta classe enquanto estiver conduzindo a análise estática.&lt;/p&gt;
&lt;p&gt;Esta classe Facade/Adapter deverá mapear valores PHP (primitivos ou objetos) em CData e tomar conta de chamar as funções em C para você.&lt;/p&gt;
&lt;p&gt;Assim você acaba construindo mais ou menos uma biblioteca em PHP, que é o ideal se você parar pra pensar. Desta forma você evita que o código de produção fique poluído com lógicas específicas do FFI e as coisas ficarão naturalmente testáveis na sua aplicação.&lt;/p&gt;
&lt;h3&gt;Mantenha a sua biblioteca atualizada&lt;/h3&gt;
&lt;p&gt;Um grande benefício de utilizar FFI em vez de extensões do PHP é que você não vai precisar atualizar o seu código C a cada nova versão do PHP. Mas você ainda precisa gerenciar suas versões da biblioteca em C.&lt;/p&gt;
&lt;p&gt;Eu recomendo que você aprenda sobre o sistema de versionamento da biblioteca original e faça releases na sua biblioteca em PHP seguindo a mesma regra, exceto para versões &lt;strong&gt;patch&lt;/strong&gt;. Então versões &lt;strong&gt;major&lt;/strong&gt; e &lt;strong&gt;minor&lt;/strong&gt; sempre vão bater com a versão original da biblioteca em C, enquanto você terá a liberdade de aumentar a versão &lt;strong&gt;patch&lt;/strong&gt; sempre que você corrigir bugs e coisas do tipo.&lt;/p&gt;
&lt;p&gt;Isto naturalmente vai te forçar a respeitar 100% as interfaces da biblioteca C original. Mas te deixa livre para distribuir correções de segurança e de bugs que possam existir tanto na biblioteca C quanto na sua própria biblioteca em PHP.&lt;/p&gt;
&lt;h3&gt;O problema de ser multiplataforma&lt;/h3&gt;
&lt;p&gt;O PHP é multiplataforma. Quem utiliza PHP espera que todas as bibliotecas sejam multiplataforma também! Manter as coisas assim pode ser um pouco complicado quando utilizamos código FFI.&lt;/p&gt;
&lt;p&gt;De volta ao exemplo da raylib, importar aquele shared object nos força a escolher por nome de arquivo: &lt;code&gt;raylib.so&lt;/code&gt; (GNU Linux), &lt;code&gt;libraylib.dylib&lt;/code&gt; (MacOS) ou &lt;code&gt;raylib.dll&lt;/code&gt; (Windows). Importe o arquivo errado e a sua biblioteca simplesmente não vai funcionar!&lt;/p&gt;
&lt;p&gt;Você pode escrever diferentes arquivos de cabeçalho, específicos para a sua plataforma. Isto vai criar muita duplicação de código mas ajuda um pouco.&lt;/p&gt;
&lt;p&gt;Outra opção é utilizar o &lt;a href=&quot;https://www.php.net/manual/en/ffi.cdef.php&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;FFI::cdef()&lt;/a&gt; para carregar as assinaturas de função. Este método é bem semelhante ao FFI::load() mas espera uma string em vez de um caminho de arquivo. Neste caso você pode escolher o caminho do seu shared object em tempo de execução.&lt;/p&gt;
&lt;p&gt;Você consegue detectar o Sistema Operacional que está rodando o seu código PHP chamando a função &lt;a href=&quot;https://www.php.net/manual/en/function.php-uname.php&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;php_uname()&lt;/a&gt;. Evite utilizar a constante &lt;code&gt;PHP_OS&lt;/code&gt;: ela contém o sistema operacional que compilou o seu binário PHP, que em alguns casos pode não ser o mesmo que está efetivamente rodando o seu código.&lt;/p&gt;
&lt;p&gt;Por último, mas não menos importante, considere que algumas bibliotecas simplesmente não são multiplataforma. Postá-las pra PHP pode ser bem frustrante pra quem utiliza e, se você decidir portar esta biblioteca mesmo assim, por favor considere lançar exceções em sistemas operacionais aos quais você não oferece suporte: isto vai dizer ao usuário final logo de cara quais são os problemas.&lt;/p&gt;
&lt;h3&gt;Existem bugs na própria extensão FFI&lt;/h3&gt;
&lt;p&gt;Lembre-se: FFI ainda é experimental no PHP! Você pode encontrar bugs inesperados a qualquer momento!&lt;/p&gt;
&lt;p&gt;Sempre que você encontrar algum comportamento super estranho na sua integração FFI, sempre crie um arquivo em C que seja equivalente e veja seu comportamento antes de duvidar do que o FFI está fazendo.&lt;/p&gt;
&lt;p&gt;Se a suspeita estiver correta e for realmente um bug, aproveite e &lt;a href=&quot;https://bugs.php.net/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;crie um bug ticket para o time do PHP&lt;/a&gt; (em inglês!). Eu não sei se o time vai ficar feliz pelo seu bug, mas com certeza você estará ajudando a comunidade a crescer.&lt;/p&gt;
&lt;p&gt;Recentemente eu encontrei um e estou inclusive tentando implementar uma correção por conta própria, vai ser um projetinho bacana e potencialmente um post futuro. Então se liga aí!&lt;/p&gt;
&lt;h2&gt;Concluindo&lt;/h2&gt;
&lt;p&gt;Eu fiquei bem animado ao trabalhar com FFI e espero que este post te ajude a começar a brincar com FFI também!&lt;/p&gt;
&lt;p&gt;De pouco em pouco eu estou ficando mais acostumado com código de baixo nível e FFI tem sido uma ótima oportunidade para eu programar diferentes casos de uso (como desenvolvimento de games ou processamento áudio) numa linguagem que eu amo (PHP).&lt;/p&gt;
&lt;p&gt;Lembre-se sempre que o PHP é uma linguagem de código aberto e que sua comunidade depende da contribuição de pessoas como você. Você pode utilizar seu conhecimento para devolver a comunidade ao reportar bugs, corrigi-los, complementar a documentação com coisas que você encontrou no caminho ou escrevendo artigos como este aqui. O FFI é definitivamente uma área de conhecimento que precisa de mais artigos e vídeos para que não caia no esquecimento.&lt;/p&gt;
&lt;p&gt;Enfim, te vejo na próxima. Se cuida aí!&lt;/p&gt;</content:encoded><category>php</category></item><item><title>Operações binárias (bitwise) com PHP</title><link>https://codamos.com.br/php-bitwise/</link><guid isPermaLink="true">https://codamos.com.br/php-bitwise/</guid><description>Recentemente eu trabalhei em diferentes projetos que me forçaram a usar bastante operações com binários em PHP. De ler arquivos a emular processadores, este é um conhecimento interessantíssimo e muito</description><pubDate>Wed, 24 Feb 2021 11:16:00 GMT</pubDate><content:encoded>&lt;p&gt;Recentemente eu trabalhei em diferentes projetos que me forçaram a usar bastante operações com binários em PHP. De ler arquivos a emular processadores, este é um conhecimento interessantíssimo e muito útil.&lt;/p&gt;
&lt;p&gt;PHP tem várias ferramentas pra lhe dar suporte a manipulação de dados em formato binário, mas é bom saber desde o começo: se você está buscando eficiência de ultra baixo nível, PHP não é a sua linguagem.&lt;/p&gt;
&lt;p&gt;Mas continua aqui! &lt;strong&gt;Neste artigo eu vou te mostrar algumas coisas importantíssimas sobre operações bitwise, como lidar com binários e hexadecimais, e conhecimentos que lhe serão úteis em QUALQUER linguagem.&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;post__toc&quot;&gt;
&lt;h3&gt;Conteúdo do post&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#php-melhor-linguagem&quot;&gt;Por que PHP talvez não seja a melhor linguagem pra isso?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#introducao-binario-hexadecimal&quot;&gt;Uma breve introdução aos formatos binário e hexadecimal&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#vai-um&quot;&gt;Operações de &quot;vai um&quot; (carry)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#representacao-em-memoria&quot;&gt;Representação de dados na memória do computador&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#overflow&quot;&gt;Overflows Aritméticos&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#numeros-e-strings-binarias-no-php&quot;&gt;Números e strings binárias no PHP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#int-ou-string&quot;&gt;Binários: Inteiros ou Strings, qual usar no PHP?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#depurando-binarios-em-php&quot;&gt;Depurando valores binários em PHP&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fnrivvbh1um&quot;&gt;Visualizando representações binárias de números inteiros&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#visualizando-strings-binarias&quot;&gt;Visualizando strings binárias&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#operacoes-bitwise&quot;&gt;Operações Binárias (Bitwise)&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fnrivvbh1un&quot;&gt;Como o Ou Inclusivo (Or) funciona ($x | $y)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fnrivvbh1uo&quot;&gt;Como o Ou exclusivo (Xor) funciona ($x ^ $y)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fnrivvbh1up&quot;&gt;Como o E (And) funciona ($x &amp;amp; $y)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fnrivvbh1uq&quot;&gt;Como a operação Negar (Not) funciona (~$x)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#o-que-e-bitmask&quot;&gt;O que é uma Máscara? (bitmask)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#corrigindo-inteiros&quot;&gt;Corrigindo Inteiros&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#conclusao&quot;&gt;Enfim, binário é maneirão&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id=&quot;php-melhor-linguagem&quot;&gt;Por que PHP talvez não seja a melhor linguagem pra isso?&lt;/h2&gt;
&lt;p&gt;Veja bem, eu amo PHP, tá? Não me leve a mal. E eu tenho certeza de que PHP é capaz de lidar com muito mais casos do que você possa imaginar. Mas se você precisa ser extremamente eficiente quando lidar com binários, o PHP não vai segurar a barra.&lt;/p&gt;
&lt;p&gt;Clarificando: eu não tô falando de uma aplicação que possa consumir 5 ou 10mb a mais. Eu estou falando sobre alocar o montante exato necessário pra determinado tipo de dado.&lt;/p&gt;
&lt;p&gt;De acordo com a &lt;a href=&quot;https://www.php.net/manual/pt_BR/language.types.integer.php&quot;&gt;documentação oficial sobre o tipo integer&lt;/a&gt;, PHP representa números decimais, hexadecimais, octais e binários com o tipo &lt;em&gt;integer&lt;/em&gt;. Então não importa muito o valor que você coloque numa variável deste tipo, ela será sempre um &lt;em&gt;integer&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Você provavelmente já ouviu falar do ZVAL antes, aquela &lt;em&gt;struct&lt;/em&gt; em C que representa toda variável PHP. Esta &lt;em&gt;struct&lt;/em&gt; tem &lt;a href=&quot;https://github.com/php/php-src/blob/da0663a337b608a4b0008672b494e3a71e6e4cfc/Zend/zend_types.h#L286&quot;&gt;um campo para representar todos os integers chamado zend_long&lt;/a&gt;. Como você pode ver, &lt;em&gt;zend_long&lt;/em&gt; é do tipo &lt;em&gt;lval&lt;/em&gt;, cujo tamanho depende da plataforma (32 ou 64 bits): numa plataforma 64 bits, &lt;a href=&quot;https://github.com/php/php-src/blob/74f3bfc6eb7ec80287178e46bd5c269fd371ce5a/Zend/zend_long.h#L30-L31&quot;&gt;será um integer de 64 bits&lt;/a&gt;, enquanto numa plataforma 32 bits, &lt;a href=&quot;https://github.com/php/php-src/blob/74f3bfc6eb7ec80287178e46bd5c269fd371ce5a/Zend/zend_long.h#L40-L41&quot;&gt;será um integer de 32 bits&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# zval guarda todo integer como lval
typedef union _zend_value {
  zend_long lval;
  // ...
} zend_value;

# lval é um integer 32 ou 64-bit
#ifdef ZEND_ENABLE_ZVAL_LONG64
 typedef int64_t zend_long;
 // ...
#else
 typedef int32_t zend_long;
 // ...
#endif
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Em suma: não importa se você precisa guardar os valores &lt;em&gt;0xff&lt;/em&gt;, &lt;em&gt;0xffff&lt;/em&gt;, &lt;em&gt;0xffffff&lt;/em&gt; ou o que for. Todos serão armazenados como um long (&lt;em&gt;lval&lt;/em&gt;) com 32 ou 64 bits no PHP.&lt;/p&gt;
&lt;p&gt;Eu recentemente trabalhei na emulação de um microcontrolador e, ao mesmo tempo que tratar a memória e operações corretamente é essencial, eu não me importei tanto com a eficiência na alocação de memória porque o meu computador consegue compensar isto em ordens de grandeza.&lt;/p&gt;
&lt;p&gt;É claro que tudo muda quando você fala sobre extensões em C ou FFI, mas não é disso que eu tô falando. Eu tô falando de PHP puro! (PHP das ruas como diria o grande PokémãoBR xD)&lt;/p&gt;
&lt;p&gt;Então lembre-se: trabalhar dados binários em PHP funciona e você consegue desenvolver qualquer aplicação que quiser, mas os tipos não vão encaixar de forma eficiente na maioria das vezes.&lt;/p&gt;
&lt;h2 id=&quot;introducao-binario-hexadecimal&quot;&gt;Uma breve introdução aos formatos binário e hexadecimal&lt;/h2&gt;
&lt;p&gt;Bom, antes de a gente falar sobre como o PHP trabalha com dados binários, a gente precisa parar um pouquinho e falar sobre binários antes. Se você acha que já sabe tudo o que precisa sobre binários, pode &lt;a href=&quot;#numeros-e-strings-binarias-no-php&quot;&gt;pular direto para a seção &quot;Números e Strings binárias no PHP&quot;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Existe um negócio na matemática chamado &quot;base&quot;. A base define como nós podemos representar quantidades em diferentes formatos. Nós, humanos, normalmente utilizamos a base decimal (base 10) que nos permite representar números somente com os dígitos 0, 1, 2, 3, 4, 5, 6, 7, 8 e 9.&lt;/p&gt;
&lt;p&gt;Pra deixar nossos exemplos mais simples eu vou chamar o número &quot;20&quot; de &quot;20 decimal&quot;.&lt;/p&gt;
&lt;p&gt;Números binários (base 2) podem representar qualquer número, mas apenas utilizando dois dígitos: 0 e 1. O 20 decimal pode ser representado em binário como 0b000&lt;strong&gt;10100&lt;/strong&gt;. Não se preocupe em converter este número, deixa que o computador faz isso pra ti 😉&lt;/p&gt;
&lt;p&gt;Números hexadecimais (base 16) podem representar qualquer número e utilizam não somente os dez dígitos que vimos na base 10 (0, 1, 2, 3, 4, 5, 6, 7, 8 e 9) mas também seis caracteres do alfabeto latino: a, b, c, d, e, e o caractere f.&lt;/p&gt;
&lt;p&gt;O 20 decimal pode ser representado como 0x&lt;strong&gt;14&lt;/strong&gt; em hexadecimal. De novo, não tente converter na sua cabeça: deixa que os computadores são especialistas nisso!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;O que é importante você entender é que números podem ser representados em diferentes bases:&lt;/strong&gt; binária (base 2), octal (base 8), decimal (base 10, a nossa base comum) e hexadecimal (base 16).&lt;/p&gt;
&lt;p&gt;Em PHP e diversas linguagens, &lt;strong&gt;números binários&lt;/strong&gt; são escritos normalmente mas com um &lt;strong&gt;prefixo 0b&lt;/strong&gt;, como o 20 decimal foi representado assim: &lt;strong&gt;0b&lt;/strong&gt;00010100. &lt;strong&gt;Números hexadecimais&lt;/strong&gt; recebem um &lt;strong&gt;prefixo 0x&lt;/strong&gt;, como o 20 decimal que foi representado assim: &lt;strong&gt;0x&lt;/strong&gt;14.&lt;/p&gt;
&lt;p&gt;Você já deve ter ouvido falar: computadores não guardam dados da forma como nós entendemos. Tudo é representado utilizando números binários: zeros e uns (0 e 1). Caracteres, números, símbolos, instruções... tudo é representado usando base 2. Caracteres são somente uma convenção de números em sequência: o caractere &apos;a&apos;, por exemplo, é o número 97 na tabela ASCII.&lt;/p&gt;
&lt;p&gt;Mesmo com tudo guardado em formato binário, a forma mais conveniente para programadores(as) lerem estes valores é utilizando hexadecimais. Tipo... a gente lê eles como se fosse poema, se liga:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# string &quot;abc&quot;
&apos;abc&apos;

# formato binário
0b01100001 0b01100010 0b01100011

# formato hexadecimal &amp;lt;3
0x61 0x62 0x63
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Enquanto os binários tomam um espaço visual enorme, hexadecimais são bem arrumadinhos. É por este motivo que normalmente utilizamos hexadecimais quando lidamos com programação de baixo nível.&lt;/p&gt;
&lt;h2 id=&quot;vai-um&quot;&gt;Operações de &quot;vai um&quot; (carry)&lt;/h2&gt;
&lt;p&gt;Você já conhece o conceito de &quot;vai um&quot;, mas eu preciso que você preste atenção nele para que possamos utilizar diferentes bases.&lt;/p&gt;
&lt;p&gt;Na base decimal nós conseguimos representar números utilizando apenas dez dígitos, do zero (0) ao nove (9). Mas sempre que você tentar representar qualquer número maior que 9 nós não temos mais dígitos disponíveis! Então o que a gente precisa fazer é adicionar um prefixo com o dígito um (1) e devolver o dígito à direita para zero (0).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# decimal (base 10)
1 + 1 = 2
2 + 2 = 4
9 + 1 = 10 // &amp;lt;- vai um
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Na base binária temos o mesmo comportamento, mas limitados aos dígitos 0 e 1.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# binário (base 2)
0 + 0  = 0
0 + 1  = 1
1 + 1  = 10 // &amp;lt;- vai um
1 + 10 = 11
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;E a mesma coisa acontece com a base hexadecimal, mas com uma faixa mais ampla.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# hexadecimal (base 16)
1 + 9  = a // sem vai um
1 + a  = b
1 + f  = 10 // &amp;lt;- vai um
1 + 10 = 11
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Como você percebeu, operações &quot;vai um&quot; precisam de mais dígitos para representar um certo número. Compreender isto te permite entender como alguns tipos de dados são limitados e, por serem armazenados em computadores, essa limitação é representada no formato binário.&lt;/p&gt;
&lt;h2 id=&quot;representacao-em-memoria&quot;&gt;Representação de dados na memória do computador&lt;/h2&gt;
&lt;p&gt;Como eu comentei antes, computadores armazenam tudo usando o formato binário. Então apenas 0s e 1s são efetivamente armazenados.&lt;/p&gt;
&lt;p&gt;The easiest way to visualize how they are stored, is by imagining a big table with a single row and many columns (as many as storage capacity), where each column is a binary digit (bit).&lt;/p&gt;
&lt;p&gt;A forma mais fácil de visualizar como estes dados são armazenados é imaginar uma grande tabela com uma única linha e várias colunas (tantas colunas quanto a capacidade de armazenamento), onde cada coluna representa um dígito binário (um bit).&lt;/p&gt;
&lt;p&gt;A gente pode representar o nosso 20 decimal nesta tabela utilizando apenas 8 bits, fica assim:&lt;/p&gt;
&lt;table&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;th&gt;Posição (Endereço)&lt;/th&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;Bit&lt;/th&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Um inteiro de 8 bits sem sinal (unsigned integer de 8 bits) é um número inteiro que pode ser representado somente com no máximo 8 dígitos binários. Então &lt;strong&gt;0b11111111&lt;/strong&gt; (255 decimal) é o maior número que este integer pode armazenar. Somar 1 ao 255 decimal requer uma operação &quot;vai um&quot;, que não pode ser representada com a mesma quantidade de dígitos (precisaria de 9 dígitos, no nosso caso).&lt;/p&gt;
&lt;p&gt;Com isto em mente nós podemos facilmente entender o motivo de existir tantas formas de representar números e o que elas realmente são: uint8 é um inteiro de 8 bits sem sinal (0 a 255 decimal), uint16 é um inteiro de 16 bits sem sinal (0 a 65.535 decimal). Existe também uint32, uint64 e teoricamente limites maiores.&lt;/p&gt;
&lt;p&gt;Inteiros com sinal, que também podem representar valores negativos, normalmente usam o último bit para determinar se o valor é positivo (último bit = 0) ou negativo (último bit = 1). Como você provavelmente deduziu, um inteiro com sinal é capaz de representar números bem menores que os inteiros sem sinal. Um inteiro com sinal de 8 bits é capaz de representar do decimal -128 até o decimal 127 apenas.&lt;/p&gt;
&lt;p&gt;Aqui vai o decimal -20, representado como um inteiro de 8 bits e com sinal. Note como o último bit (endereço 0) está ligado (o valor é igual a 1). Este bit marca o número todo como negativo.&lt;/p&gt;
&lt;table&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;th&gt;Posição (Endereço)&lt;/th&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;Bit&lt;/th&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Eu espero que até aqui tudo tenha feito sentido. Essa introdução é muito importante pra que você entenda como os computadores funcionam internamente. Só a partir daí você vai conseguir entender de forma confortável o que o PHP está fazendo por debaixo dos panos.&lt;/p&gt;
&lt;h2 id=&quot;overflow&quot;&gt;Overflows Aritméticos&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Nota sobre a palavra Overflow:&lt;/strong&gt; a tradução de Overflow seria &quot;transbordo&quot;, mas este termo é pouco utilizado. Eu vou me manter utilizando o termo em inglês: Overflow. O significado é equivalente ao de &quot;transbordar&quot; mesmo. Quando você enche um copo d&apos;água além do limite, parte da água sai do copo: isto é um transbordo ou overflow.&lt;/p&gt;
&lt;p&gt;A forma como os números são representados (8 bits, 16 bits...) determina a faixa de valores mínimos e máximos que podem ser representados. E isto ocorre por conta da forma como eles são armazenados em memória: adicionar 1 a um dígito binário 1 deveria causar uma operação &quot;vai um&quot; (carry) e, portanto, um outro bit seria necessário para fazer prefixo ao número atual.&lt;/p&gt;
&lt;p&gt;Já que os números inteiros são bem definidinhos, não é possível confiar em operações &quot;vai um&quot; que ultrapassam seu limite. (Na verdade É POSSÍVEL, mas não recomendo nem para meu pior inimigo)&lt;/p&gt;
&lt;p&gt;Vamos usar o tipo uint8 (inteiro de 8 bits sem sinal) como exemplo e representar seu número máximo - 1: o decimal 254.&lt;/p&gt;
&lt;table&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;th&gt;Posição (Endereço)&lt;/th&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;Bit&lt;/th&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Aqui nós estamos bem perto do limite dos 8 bits (decimal 255). Se somarmos 1 a este número teremos o decimal 255 e a seguinte representação:&lt;/p&gt;
&lt;table&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;th&gt;Posição (Endereço)&lt;/th&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;Bit&lt;/th&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Todos os bits estão ligados! Somar 1 a este número requer uma operação de &quot;vai um&quot; que não pode acontecer, porque não temos bits o suficiente: todos os 8 bits estão ligados! Isto gera uma coisa chamada &lt;strong&gt;overflow&lt;/strong&gt;, que acontece toda vez que você tenta ir acima de um determinado limite. A operação binária 255 + 2 vai resultar em 1, e fica representada assim:&lt;/p&gt;
&lt;table&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;th&gt;Posição (Endereço)&lt;/th&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;Bit&lt;/th&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Este comportamento não é aleatório! Existe toda uma base de cálculos, que não é relevante aqui, envolvida para determinar este valor.&lt;/p&gt;
&lt;h2 id=&quot;numeros-e-strings-binarias-no-php&quot;&gt;Números e strings binárias no PHP&lt;/h2&gt;
&lt;p&gt;Ok, de volta ao PHP! Foi mal desviar tanto o assunto, mas foi necessário.&lt;/p&gt;
&lt;p&gt;Eu espero que a partir deste momento os pontos já foram ligados na sua cabeça: números binários, como eles são armazenados, o que é um overflow, como o PHP representa números...&lt;/p&gt;
&lt;p&gt;O decimal 20 representado como um inteiro no PHP pode ter dois formatos diferentes, dependendo da sua plataforma. A plataforma x86 o representa com 32 bits enquanto a plataforma x64 o representa com 64 bits, ambos com sinal (permite valores negativos). Nós bem sabemos que o decimal 20 pode ser representado num espaço bem mais curto, de 8 bits apenas, mas o PHP trata todo valor decimal como um inteiro de 32 ou 64 bits.&lt;/p&gt;
&lt;p&gt;No PHP também existe o conceito de strings binárias, que podem ser convertidas e interpretadas utilizando as funções &lt;a href=&quot;https://www.php.net/manual/en/function.pack.php&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;pack()&lt;/a&gt; and &lt;a href=&quot;https://www.php.net/manual/en/function.unpack.php&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;unpack()&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A maior diferença entre strings binárias e números no PHP é que strings binárias apenas armazenam dados, como um buffer. Já os inteiros no PHP (binários ou não) nos permite executar operações aritméticas neles como a soma, subtração e operações binárias (bitwise) como AND, OR e XOR.&lt;/p&gt;
&lt;h2 id=&quot;int-ou-string&quot;&gt;Binários: Inteiros ou Strings, qual usar no PHP?&lt;/h2&gt;
&lt;p&gt;Para transportar dados nós normalmente utilizamos strings binárias. Então ler um arquivo binário ou se comunicar por rede vai nos exigir utilizar as funções &lt;em&gt;pack()&lt;/em&gt; e &lt;em&gt;unpack()&lt;/em&gt; em strings binárias.&lt;/p&gt;
&lt;p&gt;Operações como OR e XOR não são confiáveis quando executadas com strings, então nós devemos utilizá-las com inteiros.&lt;/p&gt;
&lt;h2 id=&quot;depurando-binarios-em-php&quot;&gt;Depurando valores binários em PHP&lt;/h2&gt;
&lt;p&gt;Agora vem a parte legal! Vamos sujar as mãos e brincar um pouco com código PHP! A primeira coisa que eu quero te mostrar é como visualizar os dados. Afinal a gente precisa entender o que estamos lidando.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fnrivvbh1um&quot;&gt;Visualizando representações binárias de números inteiros&lt;/h3&gt;
&lt;p&gt;Depurar inteiros é bem simples: a gente pode usar a função &lt;a href=&quot;https://www.php.net/manual/en/function.sprintf&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;sprintf()&lt;/a&gt;. A sua formatação é muito poderosa e nos permite identificar rapidamente o que os valores são.&lt;/p&gt;
&lt;p&gt;Abaixo eu vou representar o decimal 20 como um inteiro de 8 bits em binário e como um byte hexadecimal.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;?php
// Decimal 20
$n = 20;

echo sprintf(&apos;%08b&apos;, $n) . &quot;\n&quot;;
echo sprintf(&apos;%02X&apos;, $n) . &quot;\n&quot;;

// Saída:
00010100
14
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;O formato &quot;%08b&quot; apresenta a variável $n no formato binário (b) utilizando 8 dígitos (08).&lt;/p&gt;
&lt;p&gt;O formato &quot;%02X&quot; representa a variável $n no formato hexadecimal (X) e utilizando 2 dígitos (02).&lt;/p&gt;
&lt;h3 id=&quot;visualizando-strings-binarias&quot;&gt;Visualizando strings binárias&lt;/h3&gt;
&lt;p&gt;Enquanto os inteiros no PHP são sempre de 32 ou 64 bits, uma string pode ocupar tanta memória quanto seu conteúdo requer. Para visualizar seu valor nós precisamos interpretar cada byte.&lt;/p&gt;
&lt;p&gt;A nossa sorte é que no PHP strings podem ter seus caracteres acessados como fazemos com arrays, então cada posição da string aponta para um char de 1 byte. Abaixo mostro um exemplo de como estes caracteres podem ser acessados:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;?php
$str = &apos;thephp.website&apos;;

echo $str[3];
echo $str[4];
echo $str[5];

// saída:
php
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Confiando que cada char tem 1 byte, podemos facilmente chamar a função &lt;a href=&quot;https://www.php.net/manual/en/function.ord&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;ord()&lt;/a&gt; para converter este char em um inteiro de 1 byte (8 bits). Mais ou menos assim:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;?php
$str = &apos;thephp.website&apos;;

$p = ord($str[3]);
$s = ord($str[4]);
$t = ord($str[5]);

echo sprintf(&apos;%02X %02X %02X&apos;, $p, $s, $t);
// Saída:
70 68 70
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A gente pode ver que não estamos nos confundindo ao verificar este mesmo valor utilizando a ferramenta hexdump:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ echo &apos;php&apos; | hexdump
// Saída
0000000 70 68 70 ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A primeira coluna mostra o endereço apenas, e a partir da segunda coluna nós vemos os valores hexadecimais representando os caracteres &apos;p&apos;, &apos;h&apos; e &apos;p&apos;.&lt;/p&gt;
&lt;p&gt;Nós também podemos utilizar as funções &lt;a href=&quot;https://www.php.net/manual/en/function.pack.php&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;pack()&lt;/a&gt; e &lt;a href=&quot;https://www.php.net/manual/en/function.unpack.php&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;unpack()&lt;/a&gt; quando lidamos com strings binárias e eu tenho um ótimo exemplo pra você bem aqui!!&lt;/p&gt;
&lt;p&gt;Digamos que você queira ler um arquivo JPEG para coletar alguns metadados (como o EXIF, por exemplo). A gente pode abrir o arquivo utilizando o modo de leitura binário. Vamos fazer isto imediatamente e ler os primeiros 2 bytes:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;?php

$h = fopen(&apos;arquivo.jpeg&apos;, &apos;rb&apos;);

// Ler 2 bytes
$soi = fread($h, 2);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Para coletar estes valores num array de números inteiros a gente pode usar a função unpack desta forma:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ints = unpack(&apos;C*&apos;, $soi);

var_dump($ints);
// Saída
array(2) {
  [1] =&amp;gt; int(-1)
  [2] =&amp;gt; int(-40)
}

echo sprintf(&apos;%02X&apos;, $ints[1]);
echo sprintf(&apos;%02X&apos;, $ints[2]);
// Saída
FFD8
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note que o formato &quot;C&quot; que passamos para a função unpack() vai interpretar caracteres na string $soi como números inteiros de 8 bit sem sinal. O modificador &quot;*&quot; faz com que o unpack() extraia todos os caracteres restantes na string da mesma forma.&lt;/p&gt;
&lt;h2 id=&quot;operacoes-bitwise&quot;&gt;Operações Binárias (Bitwise)&lt;/h2&gt;
&lt;p&gt;O PHP implementa todas as operações binárias que você possa querer. Elas são implementadas como expressões e seus resultados são descritos abaixo:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Código PHP&lt;/th&gt;
&lt;th&gt;Nome&lt;/th&gt;
&lt;th&gt;Descrição&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;$x | $y&lt;/td&gt;
&lt;td&gt;Ou inclusivo (Or)&lt;/td&gt;
&lt;td&gt;Um valor com os bits ligados em $x e $y ao mesmo tempo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$x ^ $y&lt;/td&gt;
&lt;td&gt;Ou exclusivo (Or)&lt;/td&gt;
&lt;td&gt;Um valor com os bits ligados em $x ou $y, mas nunca nos dois ao mesmo tempo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$x &amp;amp; $y&lt;/td&gt;
&lt;td&gt;E (AND)&lt;/td&gt;
&lt;td&gt;Um valor somente com os bits ligados em $x e $y ao mesmo tempo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;~$x&lt;/td&gt;
&lt;td&gt;Negar (Not)&lt;/td&gt;
&lt;td&gt;Nega todos os bits em $x. O que é 1 vira 0, e o que é 0 vira 1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$x &amp;lt;&amp;lt; $y&lt;/td&gt;
&lt;td&gt;Deslocamento a esquerda (Left shift)&lt;/td&gt;
&lt;td&gt;Desloca os bits de $x para a esquerda $y vezes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$x &amp;gt;&amp;gt; $y&lt;/td&gt;
&lt;td&gt;Deslocamento a direita (Right shift)&lt;/td&gt;
&lt;td&gt;Desloca os bits de $x para a direita $y vezes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Eu vou explicar uma por uma como estas operações funcionam, não se preocupe! Vamos assumir que &lt;em&gt;$x = 0x20&lt;/em&gt; e &lt;em&gt;$y = 0x30&lt;/em&gt;. Os exemplos abaixo vão os apresentar usando a notação binária para esclarecer as coisas.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fnrivvbh1un&quot;&gt;Como o Ou Inclusivo (Or) funciona ($x | $y)&lt;/h3&gt;
&lt;p&gt;A operação Ou inclusivo vai produzir um resultado que pega todos os bits ligados das duas variáveis passadas. Então a operação $x | $y deve retornar o valor 0x30. Veja o que tá acontecendo abaixo:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// 1 | 1 = 1
// 1 | 0 = 1
// 0 | 0 = 0

0b00100000 // $x = 0x20
0b00110000 // $y = 0x30
OR ------- // $x | $y
0b00110000 // 0x30
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Repare bem: da esquerda para a direita, o sexto bit de $x estava ligado (valor = 1) enquanto os bits 5 e 6 de $y também estavam ligados. O resultado une os dois e gera um valor com os bits 5 e 6 ligados: 0x30.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fnrivvbh1uo&quot;&gt;Como o Ou exclusivo (Xor) funciona ($x ^ $y)&lt;/h3&gt;
&lt;p&gt;O Ou exclusivo (também conhecido como Xor) captura bits que estejam ligados em apenas um dos lados da operação. Então o resultado de $x ^ $y é 0x10. Veja o que acontece nesta operação:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// 1 ^ 1 = 0
// 1 ^ 0 = 1
// 0 ^ 0 = 0

0b00100000 // $x = 0x20
0b00110000 // $y = 0x30
XOR ------ // $x ^ $y
0b00010000 // 0x10
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;mcetoc_1fnrivvbh1up&quot;&gt;Como o E (And) funciona ($x &amp;amp; $y)&lt;/h3&gt;
&lt;p&gt;A operação E é bem mais simples de entender. Cada bit, dos dois lados, são comparados e apenas os valores que são iguais serão coletados para o resultado.&lt;/p&gt;
&lt;p&gt;O resultado de $x &amp;amp; $y é 0x20, olha o porquê:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// 1 &amp;amp; 1 = 1
// 1 &amp;amp; 0 = 0
// 0 &amp;amp; 0 = 0

0b00100000 // $x = 0x20
0b00110000 // $y = 0x30
AND ------ // $x &amp;amp; $y
0b00100000 // 0x20
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;mcetoc_1fnrivvbh1uq&quot;&gt;Como a operação Negar (Not) funciona (~$x)&lt;/h3&gt;
&lt;p&gt;A operação Negar requer apenas um operando e simplesmente inverte todos os bits. Ela transforma todos bits que eram 0 em 1, e todos os bits que eram 1 em 0. Veja:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// ~1 = 0
// ~0 = 1

0b00100000 // $x = 0x20
NOT ------ // ~$x
0b11011111 // 0xDF
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Se você rodou esta operação no PHP e decidiu depurar o resultado utilizando sprintf() você provavelmente recebeu um número bem mais longo, né? Eu vou te explicar o que aconteceu e como corrigir abaixo na seção &lt;a href=&quot;#corrigindo-inteiros&quot;&gt;&quot;Corrigindo Inteiros&quot;&lt;/a&gt;. Deslocamentos à esquerda e à direita (Left e Right shifts) ($x &amp;lt;&amp;lt; $n, $x &amp;gt;&amp;gt; $n) Deslocar bits é a mesma coisa que multiplicar ou dividir seus números por múltiplos de dois. O que esta operação faz é que todos os bits andem $n vezes para a esquerda ou direita.&lt;/p&gt;
&lt;p&gt;Eu vou pegar um número binário menor para representar esta operação, só pra deixar a leitura mais facilitada. Vamos pegar $x = 0b0010 como exemplo! Se a deslocarmos uma vez para a esquerda, aquele bit 1 se move um passo para a esquerda:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0b0010 // $x
$x = $x &amp;lt;&amp;lt; 1
0b0100
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A mesma coisa acontece com o deslocamento a direita. Agora que $x = 0b0100 vamos deslocá-la para a direita duas vezes:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0b0100 // $x
$x = $x &amp;gt;&amp;gt; 2
0b0001
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No fim das contas, deslocar um número $n vezes para a esquerda é o mesmo que multiplicá-lo por 2 $n vezes, e deslocá-lo $n vezes para a direita é equivalente a dividir por 2 $n vezes.&lt;/p&gt;
&lt;h2 id=&quot;o-que-e-bitmask&quot;&gt;O que é uma Máscara? (bitmask)&lt;/h2&gt;
&lt;p&gt;Tem várias coisas interessantes que a gente pode fazer com estas operações e outras técnicas. Uma ótima técnica para sempre trazer consigo é utilizar máscaras (bitmasks).&lt;/p&gt;
&lt;p&gt;Uma máscara é apenas um binário que você escolhe, escrito para extrair uma informação específica de acordo com a sua necessidade.&lt;/p&gt;
&lt;p&gt;Por exemplo, vamos tomar a ideia de que um inteiro de 8 bits com sinal é positivo quando o último bit está desligado (valor = 0) e é negativo quando o último bit está ligado (valor = 1). Eu então te pergunto: o número 0x20 é positivo ou negativo? E o 0x81?&lt;/p&gt;
&lt;p&gt;Pra responder essas perguntas nós podemos criar um byte que liga apenas o último bit (0b10000000, equivalente a 0x80) e utilizar a operação E (AND) entre este valor e 0x20. Se o resultado for 0x80 (0b10000000, a nossa máscara) então o número é negativo, se não o número é positivo:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// 0x80 === 0b10000000 (bitmask)
// 0x20 === 0b00100000
// 0x81 === 0b10000001

0x20 &amp;amp; 0x80 === 0x80 // false
0x81 &amp;amp; 0x80 === 0x80 // true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Isto é muito útil quando você quer lidar com flags. Você pode inclusive ver exemplos de utilização no próprio PHP: &lt;a href=&quot;https://www.php.net/manual/pt_BR/function.error-reporting.php&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;the error reporting flags&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;É possível escolher quais tipos de são reportados fazendo algo assim:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;error_reporting(E_WARNING | E_NOTICE);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;O que tá acontecendo aqui? Bom, vamos verificar os valores que utilizamos:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0b00000010 (0x02) E_WARNING
0b00001000 (0x08) E_NOTICE
OR -------
0b00001010 (0x0A)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Então sempre que o PHP ver que um Notice poderia ser reportado, vai verificar algo assim:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// error reporting que definimos antes
$e_level = 0x0A;

// Pode lançar um notice?
if ($e_level &amp;amp; E_NOTICE === E_NOTICE)
   // Lançar notice
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;E você vai ver isto em tudo quanto é lugar! Arquivos binários, processadores e todo tipo de computação de baixo nível!&lt;/p&gt;
&lt;h2 id=&quot;corrigindo-inteiros&quot;&gt;Corrigindo Inteiros&lt;/h2&gt;
&lt;p&gt;No PHP tem algo muito particular quando lidamos com números binários: nossos inteiros são de 32 ou 64 bits. Isto significa que várias vezes vamos precisar corrigir os valores para confiar em nossos cálculos.&lt;/p&gt;
&lt;p&gt;Por exemplo, a seguinte operação numa máquina de 64 bits vai nos retornar um número bem estranho (apesar de ser o resultado correto):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;echo sprintf(
  &apos;0b%08b&apos;,
  ~0x20
);

// Expectativa
0b11011111
// Realidade
0b1111111111111111111111111111111111111111111111111111111111011111
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Diabé isso!? Veja, ao negar aquele inteiro 0x20 nós transformamos todos os bits zero e os transformamos em 1s. Adivinha o que costumava ser zero? Exato, todos os outros 56 bits à esquerda que nós ignoramos antes!&lt;/p&gt;
&lt;p&gt;Novamente, isto acontece porque os inteiros do PHP têm 32 ou 64 bits, não importa o valor que você colocar dentro deles!&lt;/p&gt;
&lt;p&gt;Mas o código ainda funciona como esperado. Por exemplo, a operação &lt;code&gt;~0x20 &amp;amp; 0b11011111 === 0b11011111&lt;/code&gt; resulta em &lt;em&gt;bool(true)&lt;/em&gt;. Mas tenha sempre em mente que estes bits à esquerda estão ali, ou você pode acabar tendo comportamentos inesperados no seu código.&lt;/p&gt;
&lt;p&gt;Para resolver este problema, você pode corrigir os inteiros aplicando uma máscara (bitmask) que limita os zeros. Por exemplo, para normalizar ~0x20 como um inteiro de 8 bits a gente precisa utilizar uma operação E (AND) com o 0xFF (0b11111111) de forma que todos os 56 bits restantes vão ser desligados (valor = 0).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;~0x20 &amp;amp; 0xFF
-&amp;gt; 0b11011111
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Prestenção ein!&lt;/strong&gt; Nunca se esqueça de o que você está armazenando em suas variáveis, ou sua aplicação pode acabar com bugs bem difíceis de se encontrar. Por exemplo, vamos ver o que acontece quando deslocamos à direita o valor acima sem utilizar uma máscara.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;~0x20 &amp;amp; 0xFF
-&amp;gt; 0b11011111

0b11011111 &amp;gt;&amp;gt; 2
-&amp;gt; 0b00110111 // esperado

(~0x20 &amp;amp; 0xFF) &amp;gt;&amp;gt; 2
-&amp;gt; 0b00110111 // esperado

(~0x20 &amp;gt;&amp;gt; 2) &amp;amp; 0xFF
-&amp;gt; 0b11110111 // esperado?
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Só para esclarecer: do ponto de vista do PHP este comportamento É esperado, porque você claramente está lidando com um inteiro de 64 bits aqui! Você precisa sempre deixar bem explícito o que o SEU programa precisa.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dica de mestre:&lt;/strong&gt; você pode escapar de erros bestas como estes ao &lt;a href=&quot;/tdd-php-exemplos/&quot;&gt;escrever seu código com TDD&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;conclusao&quot;&gt;Enfim, binário é maneirão&lt;/h2&gt;
&lt;p&gt;Eu espero que você tenha curtido ler tanto quanto eu curti escrever este post. E mais importante: eu espero que este conhecimento te permita se aventurar por este maravilhoso mundo de dados binários.&lt;/p&gt;
&lt;p&gt;Com estas ferramentas em mão, todo o resto é apenas questão de achar a documentação correta sobre como arquivos ou protocolos binários se comportam. Tudo é uma sequência de binários no fim das contas.&lt;/p&gt;
&lt;p&gt;Eu recomendo fortemente que você dê uma olhada na especificação dos formatos PDF ou EXIF (metadados de imagem). Talvez você até queira brincar com a sua própria implementação do &lt;a href=&quot;/benchmark-messagepack-json/&quot;&gt;formato de serialização MessagePack&lt;/a&gt; ou talvez Avro, Protobuf... Infinitas possibilidades!&lt;/p&gt;
&lt;p&gt;Como você deve ter reparado este arquivo me levou um tempão pra escrever. Se você quiser recompensar o esforço, dá aquela compartilhada e salva nos favoritos pra voltar aqui sempre que tiver alguma dúvida sobre este tópico.&lt;/p&gt;
&lt;p&gt;Talvez em breve eu volte com algumas coisas mais práticas sobre lidar com binários! :)&lt;/p&gt;
&lt;p&gt;Valeu!&lt;/p&gt;</content:encoded><category>php</category></item><item><title>Novidades do PHP 8.0</title><link>https://codamos.com.br/php-8-features/</link><guid isPermaLink="true">https://codamos.com.br/php-8-features/</guid><description>Chegou a hora! No dia 26 de Novembro de 2020, o PHP 8.0 foi lançado e tornado disponível para download. Depois de 5 Release Candidates e um enorme esforço da comunidade, nós podemos finalmente começar</description><pubDate>Thu, 26 Nov 2020 11:14:00 GMT</pubDate><content:encoded>&lt;p&gt;Chegou a hora! No dia 26 de Novembro de 2020, o PHP 8.0 foi lançado e tornado disponível para download. Depois de 5 Release Candidates e um enorme esforço da comunidade, nós podemos finalmente começar com o PHP 8.0 em produção.&lt;/p&gt;
&lt;p&gt;PHP 8.0 trouxe várias inovações, dentre elas incríveis mudanças sintáticas, atualizações nas APIs e mudanças fundamentais no core e, claro, várias correções de bug. Aqui eu vou te mostrar as principais mudanças à linguagem!&lt;/p&gt;
&lt;p class=&quot;msg msg--highlight &quot;&gt;&lt;strong&gt;😉 Veja também o PHP 8.2!&lt;/strong&gt;&lt;br&gt;&lt;br&gt;Em Novembro de 2022 é lançada a versão 8.2 do PHP. Eu escrevi &lt;a href=&quot;/novidades-php-82/&quot;&gt;uma publicação detalhada sobre as mudanças da linguagem para esta versão também&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Mas ó, se tu tiver sem tempo pra ver esse post inteiro, dá uma olhada &lt;a href=&quot;https://www.php.net/releases/8.0/pt_BR.php?lang=pt_BR&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;na página oficial de lançamento do PHP 8&lt;/a&gt; que lá tem um resumão bem visual das mudanças da linguagem.&lt;/p&gt;
&lt;div class=&quot;post__toc&quot;&gt;
&lt;h3&gt;Table of Contents&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fnrlnpus2j0&quot;&gt;Mudanças Sintáticas do PHP 8.0&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fnrlnpus2j1&quot;&gt;Union Types e o Mixed Type&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fnrlnpus2j2&quot;&gt;Atributos (Annotations)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fnrlnpus2j3&quot;&gt;Operador Nullsafe&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fnrlnpus2j4&quot;&gt;Non-Capturing Catches&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fnrlnpus2j5&quot;&gt;Throw Expression&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fnrlnpus2j6&quot;&gt;Expressão Match&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fnrlnpus2j7&quot;&gt;Named Parameters&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fnrlnpus2j8&quot;&gt;Constructor Promotion&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fnrlnpus2j9&quot;&gt;Mudanças na Máquina Virtual do PHP 8&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fnrlnpus2ja&quot;&gt;Compilador Just In Time (JIT)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fnrlnpus2jb&quot;&gt;Weak Maps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fnrlnpus2jc&quot;&gt;Erros e Alertas&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fnrlnpus2jd&quot;&gt;Verificações das Assinaturas de Métodos Mágicos&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fnrlnpus2je&quot;&gt;Correções em Strings Numéricas&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fnrlnpus2jf&quot;&gt;Mudanças na Comparação de String Numéricas&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fnrlnpus2jg&quot;&gt;Agora é aproveitar e aguardar as próximas&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id=&quot;mcetoc_1fnrlnpus2j0&quot;&gt;Mudanças Sintáticas do PHP 8.0&lt;/h2&gt;
&lt;p&gt;Há várias mudanças sintáticas na linguagem nesta versão! Eu consigo ver claramente uma tendência: o php está tentando ficar cada vez mais ergonômico quando se trata de operações rápidas e classes.&lt;/p&gt;
&lt;p&gt;Abaixo eu listo 8 mudanças sintáticas que entraram no PHP 8.0 e dou uma introdução rápida. Todas elas terão links para a RFC que as introduziu à linguagem, então caso você tenha dúvidas basta ler os links &lt;a href=&quot;https://github.com/nawarian/The-PHP-Website/issues&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;(ou abrir uma issue, eu vou responder o quanto antes)&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fnrlnpus2j1&quot;&gt;Union Types e o Mixed Type&lt;/h3&gt;
&lt;p&gt;Eu escrevi um post detalhado sobre como o sistema de tipos do PHP se organiza entre escalares, compostos e especiais. &lt;a href=&quot;/tipos-em-php/&quot;&gt;Você pode acessar o post neste link aqui&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;PHP 8.0 traz duas mudanças importantes que transformaram os tipos compostos em uma estrutura formal da linguagem em vez de apenas uma convenção como antes.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://wiki.php.net/rfc/union_types_v2&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;A primeira mudança é a dos Union Types&lt;/a&gt; , que torna possível definir que tipos uma variável pode ter e gerará um erro se um tipo de valor inesperado for passado. A sintaxe é bem semelhante com o que o TypeScript faz:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

function sumTwo(int|float $x): int
{
  return round($x + 2);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Mas tem algumas limitações. O tipo &lt;code&gt;void&lt;/code&gt; não pode ser utilizado, e todas as declarações de tipo não podem ser ambíguas. Por exemplo &lt;code&gt;MyClass|object&lt;/code&gt; não deveria compilar, porque &lt;code&gt;object&lt;/code&gt; já bate com qualquer instância de qualquer classe.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://wiki.php.net/rfc/mixed_type_v2&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;A segunda mudança adiciona o tipo &lt;em&gt;mixed&lt;/em&gt; no PHP 8.0&lt;/a&gt;. O tipo &lt;em&gt;mixed&lt;/em&gt; é na verdade um Union Type muito específico. Você pode pensar nele como um alias do Union &lt;code&gt;array|bool|callable|int|float|null|object|resource|string&lt;/code&gt; e deverá funcionar semelhante ao tipo &lt;code&gt;any&lt;/code&gt; do TypeScript.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fnrlnpus2j2&quot;&gt;Atributos (Annotations)&lt;/h3&gt;
&lt;p&gt;Esta mudança foi definitivamente a que trouxe mais discussão na comunidade PHP. Ao todo foram 5 RFCs para compor esta alteração de sintaxe, todas muito discutidas pelos internals e pela comunidade nas redes sociais.&lt;/p&gt;
&lt;p&gt;A primeira vez que apareceu foi em 2016, &lt;a href=&quot;https://wiki.php.net/rfc/attributes&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;com a proposta do Dmitry&lt;/a&gt; , mas não passou já que a implementação não era suficiente para substituir as implementações já existentes como do &lt;a href=&quot;https://github.com/doctrine/annotations&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Doctrine\Annotations&lt;/a&gt; ou &lt;a href=&quot;https://github.com/php-annotations/php-annotations&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Php-Annotations\Php-Annotations&lt;/a&gt;. Esta RFC foi extremamente importante para construir o conhecimento para a RFC da nova sintaxe.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://wiki.php.net/rfc/attributes_v2&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Em março esta RFC foi revivida por Benjamin Eberlei e Martin Schröder&lt;/a&gt; , corrigindo a maioria dos problemas que a comunidade encontrou antes. A sintaxe ficou mais ou menos assim:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

use PhpAttribute;

&amp;lt;&amp;lt;PhpAttribute&amp;gt;&amp;gt;
class MyAttributesClass
{
}

&amp;lt;&amp;lt;MyAttributesClass&amp;gt;&amp;gt;
function myFunction () {}

$reflection = new ReflectionFunction(&apos;myFunction&apos;);
// ReflectionAttribute[]
var_dump($reflection-&amp;gt;getAttributes());
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Os Atributos são referências a classes que podem ser instanciadas a partir do próprio objeto &lt;em&gt;ReflectionAttribute&lt;/em&gt;. Cada classe de Atributo deverá utilizar um atributo do próprio PHP chamado &lt;em&gt;PhpAttribute&lt;/em&gt;, isto só mudou depois que a RFC &lt;a href=&quot;https://wiki.php.net/rfc/attribute_amendments&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;attribute amendments&lt;/a&gt; passou e agora em vez de &lt;em&gt;PhpAttribute&lt;/em&gt; deverá ser utilizada a classe &lt;em&gt;Attribute&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Esta sintaxe pode ser utilizada com: - funções, closures e short closures - classes, classes anônimas, interfaces, traits - constantes de classes - propriedades de classes - métodos de classes - parâmetros de funções ou métodos&lt;/p&gt;
&lt;p&gt;Esta segunda RFC (attribute amendments) também trouxe mudanças interessantes como a validação de que um Atributo deveria ser utilizado somente com classes ou com funções, se poderia ser utilizado várias vezes ou não, e também a opção de agrupar utilizações de atributos.&lt;/p&gt;
&lt;p&gt;As duas últimas RFCs ( &lt;a href=&quot;https://wiki.php.net/rfc/shorter_attribute_syntax&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;esta&lt;/a&gt; e &lt;a href=&quot;https://wiki.php.net/rfc/shorter_attribute_syntax_change&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;esta&lt;/a&gt; ) foram somente sobre como a sintaxe de utilização dos Attributes deveria ser. A sintaxe final adotada ficou como a seguinte e parece bastante com a do Rust:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

use Attribute;

#[Attribute(Attribute::TARGET_FUNCTION)]
class MyAttributesClass
{
}

#[MyAttributesClass]
function myFunction () {}

$reflection = new ReflectionFunction(&apos;myFunction&apos;);
// ReflectionAttribute[]
var_dump($reflection-&amp;gt;getAttributes());
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Reparou naquele &lt;code&gt;Attribute::TARGET_FUNCTION&lt;/code&gt; alí? Ele diz ao php que aquele Attribute só pode ser utilizado com funções e um erro será gerado se utilizado em qualquer outro lugar.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fnrlnpus2j3&quot;&gt;Operador Nullsafe&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Uncaught Error: Call to a member function example() on null&lt;/em&gt;. Este erro aqui persegue muitos(as) engenheiros(as) php que podem ter esquecido de verificar o tipo de retorno ou tenham escrito errado uma condição if.&lt;/p&gt;
&lt;p&gt;Isto vai mudar no PHP 8.0, com a &lt;a href=&quot;https://wiki.php.net/rfc/nullsafe_operator&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;introdução do operador nullsafe&lt;/a&gt;. Esta sintaxe faz verificações em valores nulos e dá um curto-circuito se alguma parte da cadeia for null, evitando uncaught errors como o mencionado acima. A sintaxe é a seguinte:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

$obj = new class {
  public function f()
  {
    return null;
  }
}

// &quot;$obj?-&amp;gt;&quot; verifica se $obj é null e,
// caso não, continua coma a chamada
// &quot;f()?-&amp;gt;&quot; verifica se o tipo do retorno de f()
// é null como acima
$obj?-&amp;gt;f()?-&amp;gt;neverCalled();

// neverCalled() nunca foi chamado, pois f() retorna null
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;mcetoc_1fnrlnpus2j4&quot;&gt;Non-Capturing Catches&lt;/h3&gt;
&lt;p&gt;Sempre que escrevemos o bloco &lt;em&gt;catch&lt;/em&gt; quando tratamos uma exceção é necessário receber também o objeto Exception.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://wiki.php.net/rfc/non-capturing_catches&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;No PHP 8.0, graças ao Max Semenik&lt;/a&gt; , não será mais necessário fazer isso. Agora é possível capturar exceções sem precisar capturar o objeto em si. Como no exemplo abaixo:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

try {
  throw new IncredibleException();
} catch (IncredibleException) {
  // Eu não ligo tanto pro
  // objeto $exceptionabout
  // the $exception object
} catch (Exception $e) {
  // Mas aqui eu ligo, e tudo bem
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;mcetoc_1fnrlnpus2j5&quot;&gt;Throw Expression&lt;/h3&gt;
&lt;p&gt;Anteriormente a palavra chave &lt;em&gt;throw&lt;/em&gt; era considerado um &lt;em&gt;statement&lt;/em&gt; na linguagem, o que nos impediu por muito tempo de lançar exceções em alguns lugares onde apenas expressões como atribuição de variáveis, short closures, ternários e expressões binárias poderiam estar.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://wiki.php.net/rfc/throw_expression&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Ilija Tovilo implementou a RFC Throw Exception&lt;/a&gt; que transformou &lt;code&gt;throw $obj&lt;/code&gt; numa expressão. Então os exemplos abaixo são válidos:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

$a = null ?? throw new Exception();
$b = $obj-&amp;gt;func() || throw new Exception();
$c = fn() =&amp;gt; throw new Exception();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Esta funcionalidade foi inspirada numa mudança introduzida ao C# em 2017 e uma proposta ao ECMAScript escrita em 2018.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fnrlnpus2j6&quot;&gt;Expressão Match&lt;/h3&gt;
&lt;p&gt;Esta é a minha favorita! A intenção é trazer uma sintaxe mais limpa sempre que normalmente faríamos um &lt;em&gt;switch&lt;/em&gt; para decidir o valor de uma variável.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://wiki.php.net/rfc/match_expression_v2&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;A RFC foi escrita por Ilija Tovilo&lt;/a&gt; e nesta versão ainda não oferece suporte a blocos, então apenas expressões são permitidas. A utilização ficou assim:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

$a = 100;

$duzentos = match ($a) {
  10, 100, 1000 =&amp;gt; $a * 2,
  50, 500, 5000 =&amp;gt; $a / 2,
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;O snippet acima retornaria &lt;code&gt;$a * 2&lt;/code&gt; sempre que $a for igual a 10, 100 ou 1000. Retornaria &lt;code&gt;$a / 2&lt;/code&gt; sempre que $a for igual a 50, 500 ou 5000.&lt;/p&gt;
&lt;p&gt;É importante observer que a sintaxe de Match constrói uma expressão, então ela pode ser armazenada em variáveis, passada como parâmetro ou ser composta com outras expressões.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

$type = ...;
$filter = match ($type) {
  &apos;as_object&apos; =&amp;gt; $myObject,
  &apos;assoc&apos; =&amp;gt; $myObject-&amp;gt;toArray(),
} || throw new InvalidArgumentException(&apos;Invalid type requested.&apos;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Implementações futuras irão adicionar suporte a blocos ao lado direito desta expressão, de forma semelhante ao que o Rust faz. Isto dá ao desenvolvedor(a) maior flexibilidade para escrever programas complexos sem invadir escopos de variáveis.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fnrlnpus2j7&quot;&gt;Named Parameters&lt;/h3&gt;
&lt;p&gt;É bem comum ver métodos com parâmetros contendo valores padrão e os únicos que queremos mudar são os últimos. Isto nos força a entrar com &lt;code&gt;null&lt;/code&gt; em todos os parâmetros para mudar apenas os últimos.&lt;/p&gt;
&lt;p&gt;Muitos podem dizer que isto é um problema de design, mas ao mesmo tempo não é possível simplesmente garantir um ótimo design para cada projeto open source escrito por aí.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://wiki.php.net/rfc/named_params&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Nikita Popov decidiu adicionar o Named Parameters ao PHP 8.0&lt;/a&gt; , que nos permite pular parâmetros de funções ou métodos e definir valores somente para as que nos importam. Para isso as variáveis precisam ser nomeadas, funciona assim:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

function myFunc(
  $a = 10,
  $b = 20,
  $c = null
) {
}

myFunc(c: 100);
// $a = 10; $b = 20; $c = 100
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Isto também nos dá a liberdade de desconsiderar a ordem dos parâmetros definida pela interface.&lt;/p&gt;
&lt;p&gt;Eu acho que esta é uma ótima forma para criar um código mais bem escrito sem quebrar bibliotecas e extensões que já existem.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fnrlnpus2j8&quot;&gt;Constructor Promotion&lt;/h3&gt;
&lt;p&gt;Alguns dizem que o PHP é tão verboso quanto o Java quando se trata de Orientação a Objetos. Eu tendo a concordar e creio que poderíamos importar algumas facilidades de sintaxe que outras linguagens já construíram e obtiveram sucesso.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://wiki.php.net/rfc/constructor_promotion&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;A sintaxe constructor promotion&lt;/a&gt; torna mais simples e rápido escrevre classes que recebem parâmetros no construtor e os joga em propriedades imediatamente.&lt;/p&gt;
&lt;p&gt;O snippet abaixo ilustra bem esta nova sintaxe:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

class MyClass
{
  public function __construct(public int $x = 0)
  {}
}

// É equivalente a isto:

class MyClass
{
  private int $x;

  public function __construct(int $x = 0)
  {
    $this-&amp;gt;x = $x;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;mcetoc_1fnrlnpus2j9&quot;&gt;Mudanças na Máquina Virtual do PHP 8&lt;/h2&gt;
&lt;p&gt;Mudanças no core são normalmente as que podem quebrar nosso código de forma explícita ou silenciosamente, então é importante tomar uma boa atenção nelas enquanto atualizamos a versão do PHP.&lt;/p&gt;
&lt;p&gt;Esta versão trouxe atualizações muito bacanas ao PHP que impactam performance e comportamente. Aqui eu vou listar algumas delas.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fnrlnpus2ja&quot;&gt;Compilador Just In Time (JIT)&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;/php-8-jit/&quot;&gt;Eu escrevi um artigo sobre o que é o JIT e como ele funciona no PHP&lt;/a&gt;. Recomendo fortemente que você dê uma lida, ele vai te dar uma ideia melhor sobre como o PHP funciona internamente e quais benefícios um compilador Just In Time pode trazer à linguagem.&lt;/p&gt;
&lt;p&gt;Resumão do ENEM: o JIT pode aumentar a performance das nossas aplicações PHP, pode ser otimizado para melhores resultados e constrói uma fundação para aplicações PHP diferentes do que estamos acostumados a ver.&lt;/p&gt;
&lt;p&gt;Mas isto não vai acontecer em toda aplicação PHP. Há casos de uso muito específicos para o JIT e eu acho que o que você pode fazer de melhor é &lt;a href=&quot;https://wiki.php.net/rfc/jit&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;verificar a RFC&lt;/a&gt; e &lt;a href=&quot;/php-8-jit/&quot;&gt;ler o post que eu mencionei acima&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Uma coisa interessante sobre esta funcionalidade é que ela foi implementada antes da RFC de attributes ser aprovada. Então uma das opções disponíveis é compilar apenas funções/métodos anotados com um doc-comment &lt;code&gt;@jit&lt;/code&gt;. Isto poderá mudar no futuro ao adicionar uma opção nativa &lt;code&gt;#[jit]&lt;/code&gt; usando Attributes em vez de doc-comments.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fnrlnpus2jb&quot;&gt;Weak Maps&lt;/h3&gt;
&lt;p&gt;O PHP 7.4 nos trouxe uma classe weak-reference (referência fraca), que nos permite criar uma referência a um objeto sem que ele fique impedido de ser coletado pelo Garbage Colelctor.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://wiki.php.net/rfc/weak_maps&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Agora no PHP 8.0 a classe WeakMap foi adicionada&lt;/a&gt;. Weak Maps usam o mesmo conceito de Weak References mas implementam as interfaces &lt;em&gt;ArrayAccess&lt;/em&gt;, &lt;em&gt;Countable&lt;/em&gt; e &lt;em&gt;Traversable&lt;/em&gt;. Isto nos permite criar coleções (maps) que não impedem que seus objetos sejam destruidos quando todas as outras referências forem removidas.&lt;/p&gt;
&lt;p&gt;Eu pretendo escrever melhor sobre Garbage Collection no PHP no futuro, mas se você quiser botar uma pressão pra ver este conteúdo logo me dá um alô lá no Twitter ou abre uma issue pra que eu dê prioridade a este assunto.&lt;/p&gt;
&lt;p&gt;Aqui vai um exemplo de como utilizar WeakMaps:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

$bag = new WeakMap();
$obj = new stdClass();

$bag[$obj] = 42;

// int(1)
var_dump($bag-&amp;gt;count());

// deleta $obj da memória
// $bag está vazia agora
unset($obj);

// int(0)
var_dump($bag-&amp;gt;count());
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;mcetoc_1fnrlnpus2jc&quot;&gt;Erros e Alertas&lt;/h3&gt;
&lt;p&gt;Esta RFC mudou a forma como o PHP se comporta e é importante que a gente preste bastante atenção nela!&lt;/p&gt;
&lt;p&gt;Muitas mensagens de erro e nível de criticidade mudaram para que fiquem mais consistentes. Nenhum nível de criticidade caiu, apenas cresceram. Alguns Notices se tornarão Warnings, e alguns Warnings se tornarão Errors (lançarão exceção).&lt;/p&gt;
&lt;p&gt;A lista completa você consegue encontrar &lt;a href=&quot;https://wiki.php.net/rfc/engine_warnings&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;na página da RFC&lt;/a&gt; e eu recomendo fortemente que você dê uma lida já que este tipo de problema pode aparecer de forma bem silenciosa se você não tiver um bom monitoramento configurado.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fnrlnpus2jd&quot;&gt;Verificações das Assinaturas de Métodos Mágicos&lt;/h3&gt;
&lt;p&gt;Esta mudança foi introduzida pelo querido Gabriel Caruso, do PHPSP, que tive o prazer de conhecer neste ano! Ele adicionou verificações de tipos nas assinaturas dos métodos mágicos do PHP da forma definida na documentação.&lt;/p&gt;
&lt;p&gt;Toda classe implementando métodos mágicos que não forem escritas de accortdo com a assinatura irá gerar um &lt;code&gt;FatalError&lt;/code&gt; como você pode verificar &lt;a href=&quot;https://wiki.php.net/rfc/magic-methods-signature&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;na página da RFC&lt;/a&gt;. Mesmo sendo uma breaking change, apenas 7 dos top 1000 pacotes no Packagist seriam afetados por esta mudança.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fnrlnpus2je&quot;&gt;Correções em Strings Numéricas&lt;/h3&gt;
&lt;p&gt;O PHP consegue converter strings numéricas em inteiros quando necessário. Este cast pode acontecer manualmente ou de forma implícita dependendo de qual operação você executar (por exemplo, expressões e chamadas de função).&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

// int(123)
var_dump((int) &quot;123&quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ainda mais, o PHP é uma mãe quando se trata de strings numéricas: perdoa tudo! Strings como &lt;code&gt;&quot;2 bananas&quot;&lt;/code&gt; ou &lt;code&gt;&quot;5 maçãs&quot;&lt;/code&gt; podem ser convertidas para números normalmente. Mais do que isso, algumas strings podem ser interpretadas como numéricas quando não deveriam (como em hashes que começam com um zero, por exemplo).&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://wiki.php.net/rfc/saner-numeric-strings&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;A RFC saner numeric strings&lt;/a&gt; veio corrigir este problema, normalizadno a forma como nós lidamos com strings numéricas e gerando Type Errors quando tipos numéricos são requeridos mas uma string não numérica é passada.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fnrlnpus2jf&quot;&gt;Mudanças na Comparação de String Numéricas&lt;/h3&gt;
&lt;p&gt;O PHP tem dois modos de comparação: estrito (&lt;code&gt;===&lt;/code&gt;, &lt;code&gt;!==&lt;/code&gt;) e não estrito (todo o resto). Sempre que fazemos uma comparação não estrita entre uma string e um número, o PHP vai tentar converter a string em um número para só então comparar dois inteiros. &lt;a href=&quot;/tipos-em-php/&quot;&gt;Eu explico este processo em detalhe neste post aqui&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Este comportamento criou distorções bem estranhas como a expressão &lt;code&gt;0 == &apos;nawarian&apos;&lt;/code&gt; retornando &lt;code&gt;bool(TRUE)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://wiki.php.net/rfc/string_to_number_comparison&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;A RFC de comparações de strings numéricas&lt;/a&gt; melhora estas comparações ao inverter a lógica de conversão: em vez de converter a string em número e então comparar os dois números, o PHP irá transformar o número em string e então comparar as duas strings.&lt;/p&gt;
&lt;p&gt;Uma nova tabela de comparação foi disponibilizada na RFC e eu trouxe uma cópia pra cá:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Comparação&lt;/th&gt;
&lt;th&gt;Antes&lt;/th&gt;
&lt;th&gt;Depois&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0 == &quot;0&quot;&lt;/td&gt;
&lt;td&gt;true&lt;/td&gt;
&lt;td&gt;true&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0 == &quot;0.0&quot;&lt;/td&gt;
&lt;td&gt;true&lt;/td&gt;
&lt;td&gt;true&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0 == &quot;foo&quot;&lt;/td&gt;
&lt;td&gt;true&lt;/td&gt;
&lt;td&gt;false&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0 == &quot;&quot;&lt;/td&gt;
&lt;td&gt;true&lt;/td&gt;
&lt;td&gt;false&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;42 == &quot; 42&quot;&lt;/td&gt;
&lt;td&gt;true&lt;/td&gt;
&lt;td&gt;true&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;42 == &quot;42foo&quot;&lt;/td&gt;
&lt;td&gt;true&lt;/td&gt;
&lt;td&gt;false&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;mcetoc_1fnrlnpus2jg&quot;&gt;Agora é aproveitar e aguardar as próximas&lt;/h2&gt;
&lt;p&gt;É claro que tem muito mais coisas que o PHP 8.0 trouxe e eu gostaria muito de ter tido o tempo e vontade para escrever todas aqui. Mas esta pequena lista já deixa claro que o PHP, morrendo desde 1994, mais uma vez se torna melhor e mais poderoso.&lt;/p&gt;
&lt;p&gt;Eu atualmente não conheço nenhum benchmark sobre o PHP 8.0 rodando aplicações de verdade que possam dizer que esta versão é mais rápida, a mesma coisa ou mais lenta. Mas eu confio que as ferramentas que a comunidade nos deu irão nos permitir continuar criando aplicações incríveis e rápidas.&lt;/p&gt;
&lt;p&gt;A adição do compilador Just In Time é uma boa oportunidade para olhar com mais carinho para ferramentas que nós poderíamos explorar bem melhor como, por exemplo, a Extensão Swoole.&lt;/p&gt;
&lt;p&gt;Agora é momento de celebrar esta incrível vitória da Comunidade PHP e agradecer todas as pessoas que se envolveram (você também está nesta lista 😉). A versão 8.1 alpha já iniciou o desenvolvimento e eu mal posso esperar por o que vem pela frente!&lt;/p&gt;
&lt;p&gt;Por favor, não se esqueça de compartilhar com seus amigos e colegas, e me dê um toque se você encontrou alguma coisa estranha aqui ou gostaria de adicionar você mesmo alguma coisa estranha.&lt;/p&gt;</content:encoded><category>php</category></item><item><title>Como subir arquivos pro seu projeto no Github</title><link>https://codamos.com.br/subindo-arquivos-no-github/</link><guid isPermaLink="true">https://codamos.com.br/subindo-arquivos-no-github/</guid><description>Subir arquivos para o GitHub é um processo simples que envolve o uso de alguns comandos no terminal como git status, add, commit, remote entre outros que veremos aqui. Ao fim deste post há também um v</description><pubDate>Fri, 06 Nov 2020 11:10:00 GMT</pubDate><content:encoded>&lt;p&gt;Subir arquivos para o GitHub é um processo simples que envolve o uso de alguns comandos no terminal como git status, add, commit, remote entre outros que veremos aqui.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ao fim deste post há também um vídeo pra te auxiliar visualmente a entender como subir arquivos no github.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Preparação&lt;/h2&gt;
&lt;p&gt;Para esse tutorial você precisará ter o Git instalado em sua máquina e uma conta no GitHub.&lt;/p&gt;
&lt;p&gt;Para instalarmos o Git no windows basta entrar no &lt;a href=&quot;https://git-scm.com/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;site do git scm&lt;/a&gt; e fazer o download. No linux e no mac basta colocar o comando abaixo no terminal.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# No linux
$ sudo apt-get install git

# No mac
$ brew install git
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Iniciando seu repositório&lt;/h2&gt;
&lt;p&gt;Precisaremos criar o repositório no GitHub, faça login na sua conta, no seu perfil vá em Repositories e New.&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/13/01-new-repository.png&quot; alt=&quot;Criando um repositório no Github.&quot; width=&quot;601&quot; height=&quot;529&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Criando um repositório no Github.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Coloque o nome desejado no campo Repository Name e uma breve descrição (não é obrigatório), no nosso exemplo vamos utilizar o thePHP.&lt;/p&gt;
&lt;h2&gt;Configurações iniciais&lt;/h2&gt;
&lt;p&gt;Antes de iniciarmos um repositório local é necessário definir seu nome e endereço de e-mail, essa configuração inicial é importante porque todos os commits do git utilizará essas informações, para isso use os comandos abaixo no terminal.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ git config --global user.name &quot;&amp;lt;nome&amp;gt;&quot;
$ git config --global user.email &quot;&amp;lt;email&amp;gt;&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Caso você queira verificar as configurações é só utilizar o comando:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ git config user.name
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Para iniciarmos um repositório git, no terminal execute o comando abaixo (certifique-se que você está dentro do seu repositório utilizando o comando cd) ou com o botão direito do mouse dentro da pasta onde ficará o seu projeto clique em Git Bash Here:&lt;/p&gt;
&lt;p&gt;&lt;img class=&quot;post__image&quot; src=&quot;/media/posts/13/02-git-bash-here.png&quot; alt=&quot;Git Bash Here no Windows.&quot; width=&quot;601&quot; height=&quot;444&quot;&gt;&lt;/p&gt;
&lt;p&gt;E execute o comando:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ git init
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Git status&lt;/h2&gt;
&lt;p&gt;O Git utiliza estados para monitorar seus arquivos, com o “git status” é possível ter um controle do que está se passando em seu repositório, para entendermos melhor como funciona, temos o exemplo abaixo que criará um arquivo Hello World.txt contendo dentro dele um simples texto “hello world” e mostrará o estado do arquivo.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ echo Hello World &amp;gt; helloWorld.txt
$ git status

on branch master
No commits yet
Untracket files:
      (use &quot;git add &amp;lt;file&amp;gt;...&quot; to include in what will be commited)
            hellowWorld.txt
nothing add to commit but untracked files present (use &quot;git add&quot; to track);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Podemos observar que o arquivo helloWorld.txt está com o estado de untracked file, isso quer dizer que o arquivo não está sendo monitorado pelo git, então qualquer coisa que acontecer com ele o git não será “responsável”.&lt;/p&gt;
&lt;h2&gt;Git add&lt;/h2&gt;
&lt;p&gt;O comando “git add ” ou “git add .” (para todos os arquivos no repositório) monitora os arquivos e adiciona uma alteração dele no diretório à staging area, que é o local onde prepara os arquivos para o próximo commit.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ git add helloWorld.txt
$ git status

on branch master
No commits yet
Changes to be committed:
         (use &quot;git rm --cached &amp;lt;file&amp;gt;...&quot; to unstage)
                   new file:      helloWorld.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Git commit&lt;/h2&gt;
&lt;p&gt;O “git commit” captura o estado atual do arquivo e adiciona as alterações para o histórico do repositório local atribuindo um hash como identificação, com o “-m” podemos adicionar uma descrição das mudanças realizadas.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ git commit -m &quot;&amp;lt;descrição&amp;gt;&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Utilizando o comando “git status&quot; podemos observar que os arquivos estão prontos para serem encaminhados para o diretório remoto.&lt;/p&gt;
&lt;h2&gt;Git remote&lt;/h2&gt;
&lt;p&gt;O “git remote” é utilizado para gerenciar os repositórios monitorados, o exemplo abaixo registra o repositório remoto e adiciona o endereço em “origin” onde passaremos o link que pode ser encontrado na aba code do nosso repositório no GitHub.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ git remote add origin &amp;lt;endereço&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Git Push&lt;/h2&gt;
&lt;p&gt;Com o “git push -u origin ” podemos encaminhar as mudanças commitadas para o GitHub, nesse exemplo utilizaremos o branch padrão master.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ git push -u origin master
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Depois que recarregar a página do seu repositório remoto você verá seus arquivos atualizados.&lt;/p&gt;
&lt;h2&gt;Conclusão&lt;/h2&gt;
&lt;p&gt;Vimos que para utilizar uma ferramenta tão poderosa como o git e subir seus arquivos para um repositório remoto é mais simples do que parece, com apenas alguns comandos aprendemos a versionar nossos arquivos e deixá-los em um local acessível e seguro para serem utilizados a qualquer momento.&lt;/p&gt;
&lt;p&gt;Como material de apoio, deixo aqui também o vídeo do Jeterson que vai te ajudar a visualizar melhor como subir arquivos no github.&lt;/p&gt;
&lt;p&gt;&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/O2DFKHla80A&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;allowfullscreen&quot; data-mce-fragment=&quot;1&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Esta publicação foi uma contribuição de autoria de João Apostulo Neto. Você pode entrar em contato com ele em seu Github &lt;a href=&quot;https://github.com/japostulo&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;@japostulo&lt;/a&gt; ou LinkedIn &lt;a href=&quot;https://linkedin.com/in/joaoapostulo&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;/joaoapostulo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Envie você também a sua, veja mais detalhes na &lt;a href=&quot;https://github.com/codamos-com-br&quot; rel=&quot;nofollow noopener&quot; target=&quot;_blank&quot;&gt;nossa página do Github&lt;/a&gt;.&lt;/p&gt;</content:encoded><category>git</category></item><item><title>Tudo sobre tipos em PHP</title><link>https://codamos.com.br/tipos-em-php/</link><guid isPermaLink="true">https://codamos.com.br/tipos-em-php/</guid><description>PHP é uma linguagem dinamicamente tipada e até o ano de 2015 quase não tinha suporte para declarar tipos de forma estática. Já era possível realizar um cast para tipos escalares de forma explícita no </description><pubDate>Wed, 29 Jul 2020 10:09:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;PHP é uma linguagem dinamicamente tipada&lt;/strong&gt; e até o ano de 2015 quase não tinha suporte para declarar tipos de forma estática. Já era possível realizar um cast para tipos escalares de forma explícita no código, mas declarar tipos escalares em assinaturas de métodos e funções não era possível até a chegada do PHP 7.0 com as RFCs &lt;a href=&quot;https://wiki.php.net/rfc/scalar_type_hints_v5&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Scalar Type Declarations&lt;/a&gt; e &lt;a href=&quot;https://wiki.php.net/rfc/return_types&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Return Type Declarations&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Mas isso não significa que a partir da versão 7.0 o PHP passou a ser estaticamente tipado. &lt;strong&gt;O PHP possui type hints que podem ser analisados de forma estática&lt;/strong&gt; mas &lt;strong&gt;ainda oferece suporte a tipos dinâmicos&lt;/strong&gt; e, inclusive, nos permite misturar os dois formatos.&lt;/p&gt;
&lt;p&gt;Veja o exemplo abaixo:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

function retornaInt(): int
{
  return &apos;100&apos;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Sem sombra de dúvidas &lt;strong&gt;tem um conflito de tipos aí em cima&lt;/strong&gt;. O retorno deveria ser um &lt;em&gt;int&lt;/em&gt; e o valor retornado é na verdade uma &lt;em&gt;string&lt;/em&gt;. O que o PHP faz internamente é automaticamente transformar o token &apos;100&apos; num inteiro para poder retornar o tipo necessário. Mesmo que pareça trazer um custo extra, não é o caso. O type juggling (malabarismo de tipos) do php é &lt;em&gt;quase&lt;/em&gt; livre de processamento extra em muitos casos.&lt;/p&gt;
&lt;p&gt;Para esclarecer de uma vez por todas como a linguagem lida com tipos, eu escrevi este arquivo em secções distintas para você:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tipos de tipos no PHP&lt;/li&gt;
&lt;li&gt;&quot;Operações&quot; com tipos no PHP&lt;/li&gt;
&lt;li&gt;Os Union Types&lt;/li&gt;
&lt;li&gt;Malabarismo de tipos, ou type juggling&lt;/li&gt;
&lt;li&gt;Os modos de tipagem&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Se você tiver alguma sugestão de o que adicionar aqui, sinta-se livre pra &lt;a href=&quot;https://twitter.com/nawarian&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;me dar um toque no twitter&lt;/a&gt; ou abrir uma issue no github.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Aahh!! Se você curte este tipo de conteúdo mais aprofundado e tal, dá uma ligadinha nesse artigo que eu escrevi sobre &lt;a href=&quot;/php-8-jit/&quot;&gt;como funciona o Just In Time compiler&lt;/a&gt; que vai entrar no PHP 8.0! Abre numa abinha aí e lê em seguida, tu não vai se arrepender! 😉&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;post__toc&quot;&gt;
&lt;h3&gt;Conteúdo&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#tipos-de-tipos-no-php&quot;&gt;Tipos de tipos no PHP&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fnrmn5dc3hb&quot;&gt;Tipos escalares&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fnrmn5dc3hc&quot;&gt;Tipos compostos&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#tipo-composto-array&quot;&gt;O tipo composto Array&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#compound-type-object&quot;&gt;O tipo composto Object&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#tipo-composto-callable&quot;&gt;O tipo composto callable&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#tipo-composto-iterable&quot;&gt;O tipo composto iterable&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fnrmn5dc3hd&quot;&gt;Tipos Especiais&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fnrmn5dc3he&quot;&gt;E as instâncias de classe?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#operacoes-com-tipos-no-php&quot;&gt;&quot;Operações&quot; com tipos no PHP&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fnrmn5dc3hf&quot;&gt;Malabarismo de tipos (type juggling): cast e coerção de tipos&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fnrmn5dc3hg&quot;&gt;Cast de tipos&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fnrmn5dc3hh&quot;&gt;Coerção de tipos&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fnrmn5dc3hi&quot;&gt;Type hints&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#union-types&quot;&gt;Union Types&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#malabarismo-de-tipos&quot;&gt;Malabarismo de tipos, ou type juggling&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#modos-de-tipagem&quot;&gt;Os modos de tipagem&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1fnrmn5dc3hj&quot;&gt;Conclusão&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2 id=&quot;tipos-de-tipos-no-php&quot;&gt;Tipos de tipos no PHP&lt;/h2&gt;
&lt;p&gt;O sistema de tipos do PHP é bem simplificado quando se trata de funcionalidades da linguagem. Por exemplo, não existe um tipo &lt;em&gt;char&lt;/em&gt;, ou valores &lt;em&gt;unsigned&lt;/em&gt; (sem sinal) ou mesmo as variações de inteiro &lt;em&gt;int8&lt;/em&gt;, &lt;em&gt;int16&lt;/em&gt;, &lt;em&gt;int32&lt;/em&gt;, &lt;em&gt;int64&lt;/em&gt;...&lt;/p&gt;
&lt;p&gt;O tipo &lt;em&gt;char&lt;/em&gt; é simplificado para tornar-se &lt;em&gt;string&lt;/em&gt; e todos inteiros são simplificados em um tipo &lt;em&gt;integer&lt;/em&gt;. Se isso for ou não uma coisa boa fica a seu critério.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Caso esteja se perguntando: o equivalente em PHP ao typeof do JS é a função &lt;em&gt;gettype()&lt;/em&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Você sempre pode inspecionar o tipo de uma variável usando a função &lt;a href=&quot;https://www.php.net/manual/en/function.gettype&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;gettype()&lt;/a&gt; ou a função &lt;a href=&quot;https://www.php.net/manual/en/function.var-dump&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;var_dump()&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;O PHP vem com três tipos de tipos: &lt;strong&gt;tipos escalares&lt;/strong&gt;, &lt;strong&gt;tipos compostos&lt;/strong&gt; e &lt;strong&gt;tipos especiais&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fnrmn5dc3hb&quot;&gt;Tipos escalares&lt;/h3&gt;
&lt;p&gt;Tipos escalares são fundamentais na linguagem e são no total quatro:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Boolean (&lt;code&gt;bool&lt;/code&gt; | &lt;code&gt;boolean&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Integer (&lt;code&gt;int&lt;/code&gt; | &lt;code&gt;integer&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Float (&lt;code&gt;float&lt;/code&gt; | &lt;code&gt;double&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;String (&lt;code&gt;string&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Por definição, um tipo escalar não possui comportamento ou estado. Expressões como &lt;code&gt;100-&amp;gt;toString()&lt;/code&gt; ou &lt;code&gt;&apos;thephp.website&apos;::length()&apos;&lt;/code&gt; são ilegais!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Resumão do ENEM: tipos escalares não possuem comportamento ou estado, eles só representam um valor.&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fnrmn5dc3hc&quot;&gt;Tipos compostos&lt;/h3&gt;
&lt;p&gt;Tipos compostos são muito mais interessantes porque mesmo que eles sejam similares aos tipos escalares, &lt;strong&gt;cada um dos quatro tipos compostos possui diferentes sintaxes&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Os quatro tipos compostos são:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;array&lt;/li&gt;
&lt;li&gt;object&lt;/li&gt;
&lt;li&gt;callable&lt;/li&gt;
&lt;li&gt;iterable&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;tipo-composto-array&quot;&gt;O tipo composto Array&lt;/h4&gt;
&lt;p&gt;Um array na realidade é um hashmap, que vem por padrão com a linguagem PHP. Isto significa que seus valores são guardados no formato &lt;strong&gt;chave =&amp;gt; valor&lt;/strong&gt; mesmo que você o utilize como um vetor.&lt;/p&gt;
&lt;p&gt;Arrays são estruturas muito flexíveis quando se trata de tamanho, tipos internos e mapeamento chave-valor. Os exemplos abaixo são todos arrays válidos:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

$vec = [0, 1, 2];
// $vec[1] é int(1)

$map = [&apos;a&apos; =&amp;gt; 1, &apos;b&apos; =&amp;gt; 2];
// $map[&apos;a&apos;] é int(1)

$quase_map = [&apos;a&apos; =&amp;gt; 1, 0 =&amp;gt; 2];
// $quase_map[&apos;a&apos;] é int(1)
// $quase_map[0] =&amp;gt; é int(2)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Diferente do C, o PHP não vai te obrigar a definir o tamanho dos arrays antes de criá-los. Isto, como era de se esperar, traz um custo em memória: o quão maior for o tamanho do seu array, mais memória você consumirá em proporções absurdas (na real, arrays são alocados em potências de 2). Como este consumo de memória acontece está fora do escopo deste artigo, &lt;a href=&quot;https://twitter.com/nawarian&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;me dá um toque se tu quiser saber mais sobre este tópico em particular&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Caso você esteja curioso sobre o que eu disse acima, &lt;a href=&quot;https://www.youtube.com/embed/JBWgvUrb-q8?start=1000&quot; target=&quot;null&quot; rel=&quot;nofollow&quot;&gt;tem uma apresentação muito interessante do Nikita Popov sobre o consumo de memória entre arrays e objetos.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Como você poderá verificar abaixo, arrays também são considerados como sendo do tipo &lt;em&gt;iterable&lt;/em&gt;, isto significa que você pode iterar sobre eles usando um laço &lt;em&gt;foreach&lt;/em&gt;. Mas eles também oferecem &lt;a href=&quot;https://www.php.net/manual/en/ref.array.php&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;funções específicas que podem manipular seus ponteiros internos&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Resumão do ENEM: O tipo array é um tipo composto extremamente flexível e pode ser considerado um HashMap e também é um tipo &lt;em&gt;iterable&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h4 id=&quot;compound-type-object&quot;&gt;O tipo composto Object&lt;/h4&gt;
&lt;p&gt;Por conta da arquitetura do PHP, o tipo composto &lt;em&gt;object&lt;/em&gt; normalmente tem um perfil de consumo de memória bem menor quando comparado aos arrays. Isto porque &lt;em&gt;normalmente&lt;/em&gt; uma pessoa usaria o tipo object criando instâncias de classes.&lt;/p&gt;
&lt;p&gt;Objetos podem carregar estado e comportamento consigo. Significa que o php oferece sintaxes para desreferenciar as entranhas de um objeto. O snippet abaixo ilustra como a operação de desreferência funciona:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

class MinhaClasse
{
  private const A = 1;
  public int $propriedade = 0;
  public function metodo(): void {}
}

$obj = new MinhaClasse();
// $obj é object(MyClass)
// $obj::A é int(1)
// $obj-&amp;gt;propriedade é int(0)
// $obj-&amp;gt;metodo() é null
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Um objeto também pode ser criado normalmente como resultado de um type cast a partir de um array. Transformando as chaves do array em nomes de propriedades. Este tipo de cast vai resultar em um tipo &lt;code&gt;object(stdClass)&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

$obj = (object) [&apos;a&apos; =&amp;gt; 1];
// $obj é object(stdClass)
// $obj-&amp;gt;a é int(1)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Vale ressaltar que converter um array com chaves numéricos em um objeto é válido, mas não é possível desreferenciar o seu valor porque propriedades de objetos não podem começar com números.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

$obj = (object) [0, 1]; // Legal
$obj-&amp;gt;0; // Ilegal
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Resumão do ENEM: objetos normalmente têm um perfil de memória menor que o dos arrays, carregam consigo estado e comportamento, e podem ser criados ao converter um array.&lt;/strong&gt;&lt;/p&gt;
&lt;h4 id=&quot;tipo-composto-callable&quot;&gt;O tipo composto callable&lt;/h4&gt;
&lt;p&gt;Um callable (chamável) no php é qualquer coisa que pode ser chamada (é mermo é?) usando parêntesis ou com a função &lt;a href=&quot;https://www.php.net/manual/en/function.call-user-func.php&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;call_user_func()&lt;/a&gt;. Ou sejE, um callable é capaz de cumprir o papel de o que conhecemos como funções. Funções e métodos sempre são callables. Objetos e classes também podem se tornar callables.&lt;/p&gt;
&lt;p&gt;Um callable pode, por definição, ser guardado numa variável. Como a seguir:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

$callable = &apos;strlen&apos;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Quê?! Mas isso não é uma string, doido!?&lt;/p&gt;
&lt;p&gt;Até que é. Mas ele pode ser coagido (coerced) num callable se for necessário. Como abaixo:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

function chameUmCallable(
  callable $f
): int {
  return $f(&apos;thephp.website&apos;);
}

$callable = &apos;strlen&apos;;

var_dump(
  $callable(&apos;thephp.website&apos;)
);
// int(14)

var_dump(
  chameUmCallable($callable)
);
// int(14)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Callables também podem apontar para um método de um objeto:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

class MinhaClasse
{
  public function meuMetodo(): int
  {
    return 1;
  }
}

$obj = new MinhaClasse();
var_dump([$obj, &apos;meuMetodo&apos;]());
// int(1)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Parece estranho? Eu sei que tem cara de array. Na real é um array mesmo. A não ser que você o trate como um callable 👀&lt;/p&gt;
&lt;p&gt;Este tipo de callable acima (referência de método de objeto) é muito interessante porque &lt;strong&gt;você pode chamar métodos privados ou protegidos&lt;/strong&gt; com ele &lt;strong&gt;se você estiver dentro do escopo da classe.&lt;/strong&gt; Caso contrário, você pode somente chamar métodos públicos.&lt;/p&gt;
&lt;p&gt;E também as classes que implementam &lt;a href=&quot;https://www.php.net/manual/en/language.oop5.magic.php#object.invoke&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;o método mágico __invoke()&lt;/a&gt;, automaticamente transforma suas instâncias em callables. Como a seguir:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

class MinhaClasseCallable
{
  public function __invoke(): int
  {
    return 1;
  }
}

$obj = new MinhaClasseCallable();
var_dump($obj());
// int(1)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Resumão do ENEM: callables são referências para funções ou métodos e podem ser construídos de maneiras distintas.&lt;/strong&gt;&lt;/p&gt;
&lt;h4 id=&quot;tipo-composto-iterable&quot;&gt;O tipo composto iterable&lt;/h4&gt;
&lt;p&gt;Iterables são muito mais simples de explicar: eles são, por definição, um array ou uma instância de &lt;a href=&quot;https://www.php.net/manual/en/class.traversable.php&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Traversable interface&lt;/a&gt;. A coisa mais importante de um iterable é que ele pode ser usado num &lt;a href=&quot;https://www.php.net/manual/en/control-structures.foreach.php&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;laço foreach()&lt;/a&gt;, num &lt;a href=&quot;https://www.php.net/manual/en/language.generators.syntax.php#control-structures.yield.from&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;yield from&lt;/a&gt; ou com o &lt;a href=&quot;https://wiki.php.net/rfc/spread_operator_for_array&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;operador de propagação (spread operator)&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Exemplos de iterables são:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

function funcao_generator(): Generator
{
  // ...
};

// Todas variáveis aqui são iterables
$a = [0, 1, 2];
$b = funcao_generator();
$c = new ArrayObject();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Resumão do ENEM: se você pode colocar num foreach(), é um iterable.&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fnrmn5dc3hd&quot;&gt;Tipos Especiais&lt;/h3&gt;
&lt;p&gt;Existem dois tipos especiais. E a maior razão pela qual eles são chamados &quot;especiais&quot; é que &lt;strong&gt;não é possível converter para estes tipos&lt;/strong&gt;. Os tipos especiais são o tipo &lt;strong&gt;resource&lt;/strong&gt; e o tipo &lt;strong&gt;NULL&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Um resource representa um conector para um recurso externo&lt;/strong&gt;. Que pode ser um conector para um arquivo, um fluxo de E/S ou uma conexão com banco de dados. Você talvez possa adivinhar o motivo de não poder fazer um cast para qualquer outro tipo de resource.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;O tipo null representa um valor nulo&lt;/strong&gt;. Isto significa que uma variável com NULL não foi inicializada, foi atribuída com o valor NULL ou apagada em tempo de execução.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Resumão do ENEM: uma variável de tipo especial não pode ser convertida para qualquer outro tipo.&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fnrmn5dc3he&quot;&gt;E as instâncias de classe?&lt;/h3&gt;
&lt;p&gt;Instâncias possuem o tipo &lt;code&gt;object&lt;/code&gt; e serão sempre representadas desta forma. Chamar a função &lt;a href=&quot;https://www.php.net/manual/en/function.gettype&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;gettype()&lt;/a&gt; num objeto sempre irá retornar o valor &lt;code&gt;string(&quot;object&quot;)&lt;/code&gt; e chamar a função &lt;a href=&quot;https://www.php.net/manual/en/function.var-dump&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;var_dump()&lt;/a&gt; no mesmo objeto sempre irá imprimir seu valor usando a notação &lt;code&gt;object(NomeDaClasse)&lt;/code&gt;. Se você precisar pegar a classe de um objeto no formato string, utilize a função &lt;a href=&quot;https://www.php.net/manual/en/function.get-class&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;get_class()&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

$obj = new stdClass();

echo gettype($obj);
// object

var_dump($obj);
// object(stdClass)#1 (0) {
// ...

echo get_class($obj);
// \stdClass
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;operacoes-com-tipos-no-php&quot;&gt;&quot;Operações&quot; com tipos no PHP&lt;/h2&gt;
&lt;p&gt;Existem diferentes &quot;operações&quot; que podem ser feitas com tipos no PHP. Eu acho que é importante deixar bem claro estas operações aqui para que não misturemos as bolas depois.&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fnrmn5dc3hf&quot;&gt;Malabarismo de tipos (type juggling): cast e coerção de tipos&lt;/h3&gt;
&lt;p&gt;Antes de a gente se aprofundar, aqui vão três definições importantíssimas:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Conversão de tipo&lt;/strong&gt; significa transformar um tipo de A para B. Por exemplo: de um inteiro para um float.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cast de tipos&lt;/strong&gt; significa converter &lt;strong&gt;manual&lt;/strong&gt; ou &lt;strong&gt;explicitamente&lt;/strong&gt; um tipo de A para B. Como em &lt;code&gt;$cem = (int) 100.0&lt;/code&gt;. (&lt;code&gt;float(100.0)&lt;/code&gt; virou &lt;code&gt;int(100)&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Coerção de tipo&lt;/strong&gt; significa converter &lt;strong&gt;implicitamente&lt;/strong&gt; um tipo de A para B. Como em &lt;code&gt;$vinte = 10 + &apos;10 bananas&apos;;&lt;/code&gt;. (&lt;code&gt;string(&quot;10 bananas&quot;)&lt;/code&gt; virou &lt;code&gt;int(10)&lt;/code&gt;)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Tendo isto em mente, as próximos secções vão explicar como isso funciona no php. E mais pra frente você encontrará mais informações sobre o malabarismo de tipos (type juggling).&lt;/p&gt;
&lt;h4 id=&quot;mcetoc_1fnrmn5dc3hg&quot;&gt;Cast de tipos&lt;/h4&gt;
&lt;p&gt;De forma semelhante ao Java, o PHP nos permite fazer cast de tipos. Isto significa que quando uma variável aponta para um valor que pode ser transformado num tipo diferente, a linguagem nos permite uma conversão manual (explícita) de tipos.&lt;/p&gt;
&lt;p&gt;Pera, pera... É O QUE!? 🤨&lt;/p&gt;
&lt;p&gt;Ó: uma variável &lt;code&gt;$cem&lt;/code&gt; segurando &lt;code&gt;string(&quot;100&quot;)&lt;/code&gt; pode ser convertida manualmente (cast) para tornar-se &lt;code&gt;int(100)&lt;/code&gt; ou &lt;code&gt;float(100.0)&lt;/code&gt; - ou qualquer outro tipo escalar ou um dos tipos compostos &lt;em&gt;array&lt;/em&gt; ou &lt;em&gt;object&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;O snippet a seguir funciona perfeitamente no PHP e é bem parecido com o Java:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

$cem = (int) &apos;100&apos;;
// $cem agora é int(100)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Agora, uma coisa que o Java faz e é completamente ilegal no php, é converter (cast) um ponteiro de variável numa classe diferente. &lt;strong&gt;Isto significa que a gente só pode converter tipos escalares e alguns tipos compostos no php&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

class MinhaClasse {}

// Gera um parse error
$ilegal = (MinhaClasse) new stdClass();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Importante notar! No PHP só é possível fazer cast de tipos para tipos escalares*. Portanto fazer o cast de um objeto para uma classe diferente é ilegal, mas &lt;strong&gt;fazer um cast de objeto para um tipo escalar é completamente válido&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Também possível fazer o cast de valores para os tipos &lt;em&gt;array&lt;/em&gt; ou &lt;em&gt;object&lt;/em&gt;&lt;/strong&gt;, que não são tipos escalares mas sim compostos (dar nome pr&apos;esses coiso tudo é osso, né?).&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

class MinhaClasse {}

$obj = new MinhaClasse();
$um = (int) $obj; // int(1)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;O código acima gera alguns notices mas ainda assim é válido. Mais tarde eu explico de onde veio esse &lt;code&gt;int(1)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Resumão do ENEM: o php permite realizar cast de tipos para escalares, arrays ou objetos. Fazer o cast para classes não é permitido.&lt;/strong&gt;&lt;/p&gt;
&lt;h4 id=&quot;mcetoc_1fnrmn5dc3hh&quot;&gt;Coerção de tipos&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;A coerção de um tipo acontece como um efeito colateral de trabalhar com tipos incompatíveis ou não declarados.&lt;/strong&gt; Eu explico melhor mais pra frente neste artigo. Por agora apenas confia que o PHP vai automaticamente fazer o cast dos tipos o seu código em tempo de execução quando necessário.&lt;/p&gt;
&lt;p&gt;Um exemplo de coerção de tipos pode ser multiplicar um integer por um float. Na expressão &lt;code&gt;int(100)&lt;/code&gt; multiplicado por &lt;code&gt;float(2.0)&lt;/code&gt; o resultado é um &lt;code&gt;float(200)&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

var_dump(100 * 2.0);
// float(200)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Resumão do ENEM: o php tem um mecanismo para normalizar tipos em tempo de execução de forma implícita e você deve sempre prestar atenção nisso!&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;mcetoc_1fnrmn5dc3hi&quot;&gt;Type hints&lt;/h3&gt;
&lt;p&gt;O type hinting é um mecanismo de, ao mesmo tempo, reforçar a coerção de tipos e de import tipagem estrita. Isto foi introduzido ao php na versão 7.0 e transforma assinaturas de métodos e funções. &lt;a href=&quot;https://wiki.php.net/rfc/typed_properties_v2&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Desde o php 7.4 também é possível fazer type hint com propriedades de classes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Abaixo vai um exemplo de type hint:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

function somar(
  int $a,
  int $b
): int {
  return $a + $b;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As dicas (hints) aqui dizem que a variável &lt;code&gt;$a&lt;/code&gt; é do tipo &lt;em&gt;int&lt;/em&gt; naturalmente ou transformada pela linguagem, a variável &lt;code&gt;$b&lt;/code&gt; também é do tipo &lt;em&gt;int&lt;/em&gt; e o resultado desta função será do tipo &lt;em&gt;int&lt;/em&gt;, de forma natural ou transformada automaticamente pela linguagem (coerção).&lt;/p&gt;
&lt;p&gt;Reparou que eu disse que elas são de certo tipo &quot;de forma natural ou transformada automaticamente pela linguagem (coerção)&quot;? Isso porque o PHP não vai reclamar se você chamar esta função com valores que não são do tipo int. O que vai acontecer, aliás, é que o php vai tentar converter implicitamente (coerção) os parâmetros em inteiros se o tipo não for o esperado.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;No corpo da função a seguir você pode sempre ter certeza de que &lt;code&gt;$a&lt;/code&gt; e &lt;code&gt;$b&lt;/code&gt; são inteiros. Mas de que os inteiros estão corretos somente quem chama função pode garantir.&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

function somar(
  int $a,
  int $b
): int {
  // $a é int(10)
  // $b é int(10)
  return $a + $b;
}

somar(&apos;10 maçãs&apos;, &apos;10 bananas&apos;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Também é possível ativar uma diretiva chamada &lt;code&gt;strict_types&lt;/code&gt; para evitar coerções e simplesmente gerar erros quando tipos inválidos são utilizados. Como à seguir:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

declare(strict_types=1);

function somar(
  int $a,
  int $b
): int {
  return $a + $b;
}

somar(&apos;10 bananas&apos;, &apos;10 maçãs&apos;);
// PHP Fatal error: Uncaught
// TypeError: Argument 1 passed
// to somar() must be of the type
// int, string given
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Isso não significa que o php é estaticamente tipado quando strict_types está ligado!&lt;/strong&gt; Na realidade, o type hinting apenas adiciona um processamento extra. Internamente ele sempre fará o malabarismo de tipos (type juggling) e nunca irá confiar nos type hints da sua variável.&lt;/p&gt;
&lt;p&gt;Type hints servem a dois propósitos: definir em quais tipos um valor deveria ser coagido OU gerar erros fatais quando os strict types estiver ligado.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Resumão do ENEM: type hints apenas dão dicas sobre os tipos para o php, não ordens! Usar strict types é uma escolha que você pode tomar e trará um pequeno processamento extra consigo.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;union-types&quot;&gt;Union Types&lt;/h2&gt;
&lt;p&gt;Antes de a gente falar de malabarismo de tipos (type juggling) eu gostaria de falar rapidinho sobre os Union Types porque parece fazer mais sentido aqui.&lt;/p&gt;
&lt;p&gt;Além dos três tipos que o php tem (escalares, compostos e especiais) o manual do php também menciona um &lt;a href=&quot;https://www.php.net/manual/en/language.pseudo-types.php&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;pseudo-tipo que só existe para facilitar a leitura do manual&lt;/a&gt;. Este tipo não existe de verdade, é apenas uma convenção.&lt;/p&gt;
&lt;p&gt;Eu gostaria que você prestasse atenção num pseudo-tipo muito específico: o &lt;code&gt;array|object&lt;/code&gt; normalmente é utilizado na documentação para especificar parâmetros ou tipos de retorno.&lt;/p&gt;
&lt;p&gt;O tipo &lt;code&gt;iterable&lt;/code&gt; também é um tipo de Union Type. E pode ser definido como &lt;code&gt;array|Traversable&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Desde o php 7.1 a linguagem traz um meio-que suporte a Union Types ao ter introduzido o &lt;a href=&quot;https://wiki.php.net/rfc/nullable_types&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;nullable type&lt;/a&gt;. Se você parar pra pensar, um tipo nullable é apenas um Union de &lt;code&gt;T|null&lt;/code&gt;. Por exemplo, &lt;code&gt;?int&lt;/code&gt; significa &lt;code&gt;int|null&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Aposto que tu não pensou sobre isso antes! 😝&lt;/p&gt;
&lt;p&gt;Então depois de tantos Union Types desconhecidos, &lt;a href=&quot;https://wiki.php.net/rfc/union_types_v2&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;o php 8.0 formalmente implementou os Union Types&lt;/a&gt;. Onde você pode definir qualquer Union Type que precisar sem depender de pseudo-types ou convenções. Funciona mais ou menos assim:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

declare(strict_types=1);

function dividir(
  int $a,
  int $b
): int|float {
  return $a / $b;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A função acima pode retornar integer ou float. Mas nunca outro tipo.&lt;/p&gt;
&lt;h2 id=&quot;malabarismo-de-tipos&quot;&gt;Malabarismo de tipos, ou type juggling&lt;/h2&gt;
&lt;p&gt;Provavelmente não é a primeira vez que você ouviu falar no termo Type Juggling, certo? Esta é uma das funcionalidades mais importantes do php e, ainda assim, é uma das menos compreendidas.&lt;/p&gt;
&lt;p&gt;Eu não posso culpar ninguém por não entendê-la bem. A gente chama isso de &quot;malabarismo&quot; por um bom motivo. Uma variável pode assumir tanto tipo diferente em cada contexto que pode ser um tanto complicado entender com qual tipo você está lidando.&lt;/p&gt;
&lt;p&gt;Vamos começar com o seguinte: &lt;strong&gt;o php não permite definir tipos explicitamente na declaração de variáveis&lt;/strong&gt;. E isso é muito poderoso!&lt;/p&gt;
&lt;p&gt;Sempre que você declara uma variável, o php vai inferir o tipo que ela possui baseado no valor que você a deu. Enquanto &lt;code&gt;$var;&lt;/code&gt; cria uma variável com valor NULL, &lt;code&gt;$one = 1&lt;/code&gt; cria um inteiro e &lt;code&gt;$obj = new stdClass()&lt;/code&gt; cria um &lt;code&gt;object(stdClass)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Aí não tem definição de tipo em canto algum! O php vai tomar conta de adivinhar qual o tipo melhor se adequa a sua variável.&lt;/p&gt;
&lt;p&gt;As variáveis do php são muito dinâmicas, de forma que elas podem mudar de tipo em tempo de execução sem problema algum! O código abaixo é válido:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

$var;
// $var é NULL

$var = 1;
// $var é int(1)

$var = &apos;thephp.website&apos;;
// $var é string(&quot;thephp.website&quot;)

$var = new stdClass();
// $var é object(stdClass)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;E por as variáveis serem tão dinâmicas, várias operações no php exigem que os valores sejam verificados baseado no contexto da operação. Uma expressão como a soma (a + b) internamente irá verificar o tipo do primeiro operando e depois tentar adivinhar o tipo do segundo operando.&lt;/p&gt;
&lt;p&gt;Dê uma sacada &lt;a href=&quot;https://github.com/php/php-src/blob/PHP-7.4/Zend/zend_vm_def.h#L47-L84&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;nesse snippet do código fonte do php&lt;/a&gt;. Se &lt;code&gt;op1&lt;/code&gt; for long (a é um inteiro) então verifique se &lt;code&gt;op2&lt;/code&gt; também é long (b é inteiro). Se sim, faça uma soma de longs. Se não, verifique se &lt;code&gt;op2&lt;/code&gt; é um double e faça uma soma de doubles se sim. E esta expressão &lt;a href=&quot;https://github.com/php/php-src/blob/PHP-7.4/Zend/zend_vm_def.h#L61&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;pode retornar um inteiro&lt;/a&gt; ou &lt;a href=&quot;https://github.com/php/php-src/blob/PHP-7.4/Zend/zend_vm_def.h#L74&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;um float&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;E é por isso que eu te garanto que o malabarismo de tipos (type juggling) vai acontecer automaticamente.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Isso também significa que coerção de tipos (conversões implícitas) vão acontecer automaticamente. Mas elas não deveriam ser uma surpresa! Há momentos muito específicos onde uma coerção de tipos deve acontecer.&lt;/p&gt;
&lt;p&gt;Coerção de tipos (e, portanto, malabarismo de dados) ocorrem quando:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;resolvem-se expressões&lt;/li&gt;
&lt;li&gt;passam-se argumentos para uma função ou método&lt;/li&gt;
&lt;li&gt;retorna-se de uma função ou método&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Você pode estar se perguntando: ué, se coerção acontece em todo canto então como o php lida com tipos incompatíveis? Converter um inteiro para boolean parece normal, mas um array para inteiro já começa a ficar estranho.&lt;/p&gt;
&lt;p&gt;Bem, o php tem regras muito bem definidas para fazer conversão de tipos. Primeiro entende-se qual o tipo que o resultado deveria ter e só então é feita a conversão.&lt;/p&gt;
&lt;p&gt;Por exemplo, se uma expressão ocorrer dentro de um &lt;code&gt;if()&lt;/code&gt; a gente pode perceber rapidinho que aquela expressão deve resultar em um tipo boolean.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

$var = 100;
// $var é int(100)

// $var é tratado como
// boolean e resulta
// em TRUE
if ($var) {
  // $var ainda é int(100)
}

// $var ainda é int(100)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Repare como $var era &lt;code&gt;int(100)&lt;/code&gt; durante todo seu ciclo de vida, mas foi tratada como &lt;code&gt;bool(TRUE)&lt;/code&gt; dentro daquele &lt;em&gt;if()&lt;/em&gt;. Isto ocorre porque o &lt;em&gt;if()&lt;/em&gt; espera uma expressão que retorna um boolean. O malabarismo de tipos (type juggling) é justamente o que o php fez por debaixo dos panos para você.&lt;/p&gt;
&lt;p&gt;Para ilustrar, aqui vai a lista de verificações ao converter um tipo em boolean. &lt;strong&gt;Uma conversão para boolean retorna false quando o valor original for&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;um bool(FALSE)&lt;/li&gt;
&lt;li&gt;um &lt;code&gt;int(0)&lt;/code&gt; ou &lt;code&gt;int(-0)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;um &lt;code&gt;float(0)&lt;/code&gt; ou &lt;code&gt;float(-0)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;uma string vazia &lt;code&gt;string(&quot;&quot;)&lt;/code&gt; ou a string zero &lt;code&gt;string(&quot;0&quot;)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;um array vazio &lt;code&gt;array()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;um NULL&lt;/li&gt;
&lt;li&gt;uma instância de SimpleXML criada a partir de tags vazias&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;E irá retornar true para qualquer outro valor.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A tabela acima pode ser encontrada na &lt;a href=&quot;https://www.php.net/manual/en/language.types.boolean.php#language.types.boolean.casting&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;seção &quot;Converting to boolean&quot; do manual&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A documentação completa sobre as comparações de tipos e tabelas de conversões &lt;a href=&quot;https://www.php.net/manual/en/types.comparisons.php&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;também podem ser encontradas no manual da linguagem&lt;/a&gt;. Eu não tomei coragem de ler, mas faz parte do meu trabalho dizer que elas existem e te mostrar onde 🤷🏻‍♀️&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nota importante aqui&lt;/strong&gt;: no php 8.0 os union types foram introduzidos e trouxeram consigo uma camada extra de complexidade. O malabarismo de dados (type juggling) quando lida com Union Types precisa seguir uma regra de precedência. E essa precedência é pré-definida em vez de depender da ordem dos tipos declarados.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://wiki.php.net/rfc/union_types_v2#coercive_typing_mode&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Então se você não estiver usando strict_types os seus Union Types vão seguir esta regra&lt;/a&gt;. Se o Union Type não contém o tipo do resultado, ele poderá fazer a coerção deste valor na seguinte ordem de precedência: &lt;code&gt;int&lt;/code&gt;, &lt;code&gt;float&lt;/code&gt;, &lt;code&gt;string&lt;/code&gt; e &lt;code&gt;bool&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Por exemplo:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

function f(
  int|string $v
): void {
  var_dump($v);
}

f(&quot;&quot;); // string ESTÁ no union type
// string(&quot;&quot;)

f(0); // int ESTÁ no union type

f(0.0); // float NÃO ESTÁ no union type
// int(0)

f([]); // array NÃO ESTÁ no union type
// Uncaught TypeError:
// f(): Argument #1 ($v)
// must be of type string|int
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No exemplo acima algo interessantíssimo acontece! O tipo array não será convertido para um &lt;code&gt;bool(FALSE)&lt;/code&gt;. Ele gera um TypeError em vez disso!&lt;/p&gt;
&lt;h2 id=&quot;modos-de-tipagem&quot;&gt;Os modos de tipagem&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Você já deve ter percebido que existem duas formas de o php lidar com tipos&lt;/strong&gt;. Uma delas é chamada &lt;strong&gt;&quot;Coercive Type Mode&quot;&lt;/strong&gt; onde acontece todo aquele malabarismo e adivinhações de tipos. A outra é o &lt;strong&gt;&quot;Strict Type Mode&quot;&lt;/strong&gt; onde &lt;strong&gt;o malabarismo e a adivinhação ainda acontecem&lt;/strong&gt;, mas &lt;strong&gt;quando os tipos são definidos explicitamente&lt;/strong&gt; alguns &lt;strong&gt;TypeErrors serão lançados quando os tipos não forem compatíveis&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Agora, eu vejo como algo normal que pessoas programadoras de php possam esperar que a linguagem respeite a Lei da Troca Equivalente (等価交換法) e lhe pague com ganho de performance o esforço de usar strict types porque ela será então capaz de pular todas as verificações de tipos e executar as operações diretamente.&lt;/p&gt;
&lt;p&gt;Ao passo que eu entendo o motivo de alguém pensar desta forma, eu preciso lhe dizer: está completamente errado! O código a seguir contém &lt;a href=&quot;https://github.com/php/php-src/blob/PHP-7.4/Zend/zend_vm_def.h#L8056-L8105&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;a lógica da função strlen() no código fonte do php&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Toda vez que é necessário verificar se o php está operando no modo &quot;Strict Type&quot;, pode-se buscar o boolean a partir da chamada &lt;code&gt;EX_USES_STRICT_TYPES()&lt;/code&gt;. Se true, o strict types está ligado. Se não, o modo coercivo está.&lt;/p&gt;
&lt;p&gt;Agora, veja o snippet novamente! Ele começa assim:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;// ...
zval *value;

value = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
// value é o parâmetro
// de strlen()

if (EXPECTED(
  Z_TYPE_P(value) == IS_STRING
)) {
  ZVAL_LONG(
    EX_VAR(
      opline-&amp;gt;result.var
    ),
    Z_STRLEN_P(value)
  );
  FREE_OP1();
  ZEND_VM_NEXT_OPCODE();
} else {
  // ...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Reparou naquele primeiro &lt;em&gt;if()&lt;/em&gt; alí? Adivinha o que ele tá fazendo... EXATO! Ele verifica pra ti o tipo do parâmetro!!&lt;/p&gt;
&lt;p&gt;Sabe o que esse mesmo trecho de código está fazendo com o seu type hint? NADINHA! 🤣&lt;/p&gt;
&lt;p&gt;A cláusula &lt;em&gt;else&lt;/em&gt; possui o código TALVEZ vá usar strict types ou não.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;// ...
} else {
  // Ok, estamos progredindo
  zend_bool strict;

  // 😭
  if (
    (OP1_TYPE &amp;amp; (IS_VAR|IS_CV)) &amp;amp;&amp;amp;
    Z_TYPE_P(value) == IS_REFERENCE
  ) {
      // ...
  }

  // ...

  // OPA! 👀
  strict = EX_USES_STRICT_TYPES();
  do {
    if (EXPECTED(!strict)) {
      // ...
    }
    zend_internal_type_error(
      strict,
      /*...*/
    );
    ZVAL_NULL(
      EX_VAR(opline-&amp;gt;result.var)
    );
  } while (0);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No trecho acima podemos ver um exemplo de como o modo strict type não corta nenhum processamento. Na verdade, acabou criando algumas verificações a mais com um único propósito: gerar erros fatais.&lt;/p&gt;
&lt;p&gt;Eu não quero dizer que esta é uma implementação ruim. Eu pessoalmente estou bem contente com a forma que o php funciona. Mas eu acho que é importante deixar claro que isto não irá afetar a performance de forma positiva.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Resumão do ENEM: strict types não tornarão seu código mais rápido!&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;mcetoc_1fnrmn5dc3hj&quot;&gt;Conclusão&lt;/h2&gt;
&lt;p&gt;Esse artigo deu trabalho ein! Me fez considerar um bom tanto a ideia de escrever um livro. Só este artigo já daria uns 15% de um livro bacana 😂&lt;/p&gt;
&lt;p&gt;Eu espero que a informação que eu coletei aqui foi útil pra ti. E se não foi, que tenha sido ao menos interessante.&lt;/p&gt;
&lt;p&gt;Eu acredito que o sistema de tipos do PHP é incrivelmente rico e carrega várias funcionalidades legadas e também inovadoras e todas elas fazem muito sentido quando você olha para a história do desenvolvimento da linguagem.&lt;/p&gt;
&lt;p&gt;Como sempre, sinta-se livre para me dar um alô no twitter se você tiver algo a dizer. Você também pode abrir uma issue ou pull request no github e ser feliz.&lt;/p&gt;
&lt;p&gt;Até a próxima! Valeu!&lt;/p&gt;</content:encoded><category>php</category></item><item><title>Como fazer web crawling e scrapping com PHP</title><link>https://codamos.com.br/crawlers-com-php/</link><guid isPermaLink="true">https://codamos.com.br/crawlers-com-php/</guid><description>Você provavelmente já viu vários posts sobre como escrever crawlers com php. O que difere este post dos outros? É que eu garanto que você não precisa se malucar com expressões regulares, variáveis glo</description><pubDate>Mon, 20 Jul 2020 10:06:00 GMT</pubDate><content:encoded>&lt;p&gt;Você provavelmente já viu vários posts sobre como escrever crawlers com php. O que difere este post dos outros? É que eu garanto que você não precisa se malucar com expressões regulares, variáveis globais e todo esse tipo de coisa irritante.&lt;/p&gt;
&lt;p&gt;Nós vamos usar uma ferramenta maravilhosa chamada &lt;code&gt;spatie/crawler&lt;/code&gt; que vai nos fornecer uma ótima interface para escrever crawlers sem ir a loucura!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Abaixo tem um vídeo meu codificando este crawler. É só rolar a página até o vídeo se tu quiser pular direto pra ação. 😉&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Nosso caso de uso&lt;/h2&gt;
&lt;p&gt;Este crawler vai ser bem simplão e pretende buscar nomes, apelidos e e-mails do diretório oficial do PHP sobre pessoas que contribuíram com a linguagem de alguma forma.&lt;/p&gt;
&lt;p&gt;Você pode olhar o repositório nesta url aqui: &lt;a href=&quot;https://people.php.net/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;https://people.php.net&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Configurando o ambiente de desenvolvimento&lt;/h2&gt;
&lt;p&gt;Montar o ambiente vai ser bem rápido, eu vou só copiar as secções &lt;em&gt;composer&lt;/em&gt; e &lt;em&gt;php&lt;/em&gt; desse outro post que eu escrevi sobre &lt;a href=&quot;/php-docker-setup/&quot;&gt;como montar um ambiente com docker rapidex&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Meu arquivo &lt;em&gt;docker-compose.yml&lt;/em&gt; ficou assim:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;version: &apos;3&apos;
services:
  composer:
    image: composer:1.9.3
    environment:
      - COMPOSER_CACHE_DIR=/app/.cache/composer
    volumes:
      - .:/app
    restart: never

  php:
    image: php:7.4-cli
    restart: never
    volumes:
      - .:/app
    working_dir: /app
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Agora vamos instalar os pacotes:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ docker-compose run \
  composer require \
    spatie/crawler \
    symfony/css-selector
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Tudo o que a gente precisa agora é um arquivo pra executar, vamos criar um arquivo &lt;code&gt;bin/crawler.php&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ mkdir bin
$ touch bin/crawler.php
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Massa! Agora vamos adicionar o autoload nesse arquivo e estamos prontos pra começar:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;// bin/crawler.php
&amp;lt;?php

require_once __DIR__ . 
  &apos;/../vendor/autoload.php&apos;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;De agora em diante a gente pode rodar nosso crawler com o seguinte comando:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ docker-compose run php \
  php bin/crawler.php
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Vamos analizar o site alvo&lt;/h2&gt;
&lt;p&gt;Normalmente a gente deveria navegar pelo website e entender como ele funciona: padrões de url, chamadas ajax, tokens csrf, se feeds ou APIs estão disponíveis.&lt;/p&gt;
&lt;p&gt;Neste caso nem feeds e nem APIs estão disponíveis. A gente precisa criar um crawler cruzão mesmo que vai buscar páginas em HTML e interpretá-las.&lt;/p&gt;
&lt;p&gt;Eu vejo alguns padrões de URL: * Página de perfil: people.php.net/{nickname} * Página de diretório: people.php.net/?page={number} * Links externos&lt;/p&gt;
&lt;p&gt;Parece simples! A gente só precisa se preocupar em interpretar o HTML dentro de páginas de perfil e ignorar o restante.&lt;/p&gt;
&lt;p&gt;Ao verificar a página de perfil podemos perceber rapidamente que os seletores importantes pra gente são: * Nome: &lt;code&gt;h1[property=foaf:name]&lt;/code&gt; * Apelido: &lt;code&gt;h1[property=foaf:nick]&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;A gente também pode confiar que o e-mail das pessoas segue o padrão &quot;{apelido}@php.net&quot;.&lt;/p&gt;
&lt;p&gt;Com essa informação, bora codar!&lt;/p&gt;
&lt;h2&gt;Obtendo dados públicos de todas as pessoas que contribuíram com o PHP&lt;/h2&gt;
&lt;p&gt;Abaixo você encontra o código, mas se você prefere mais vídeos, dá uma ligadinha nesse aqui que eu fiz pra ti:&lt;/p&gt;
&lt;p&gt;&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/HaMoYhTV1hI?start=21&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;allowfullscreen&quot; data-mce-fragment=&quot;1&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;h2&gt;Mãos à massa!&lt;/h2&gt;
&lt;p&gt;O pacote &lt;code&gt;spatie/crawler&lt;/code&gt; traz duas classes abstratas muito importantes - que eu adoraria que fossem interfaces 👀.&lt;/p&gt;
&lt;p&gt;Uma delas é a classe &lt;code&gt;CrawlObserver&lt;/code&gt;, onde a gente pode se conectar aos passos de obter uma página e manipular respostas http. A nossa lógica entra aqui.&lt;/p&gt;
&lt;p&gt;Eu vou escrever um observer rapidinho com uma classe anônima abaixo:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;$observer = new class
  extends CrawlObserver
{
  public function crawled(
    $url,
    $response,
    $foundOnurl
  ) {
    $domCrawler = new DomCrawler(
      (string) $response-&amp;gt;getBody()
    );

    $name = $domCrawler
      -&amp;gt;filter(&apos;h1[property=&quot;foaf:name&quot;]&apos;)
      -&amp;gt;first()
      -&amp;gt;text();
    $nick = $domCrawler
      -&amp;gt;filter(&apos;h2[property=&quot;foaf:nick&quot;]&apos;)
      -&amp;gt;first()
      -&amp;gt;text();
    $email = &quot;{$nick}@php.net&quot;;

    echo &quot;[{$email}] {$name} - {$nick}&quot; . PHP_EOL;
  }
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A lógica acima vai buscar as propriedades que esperamos das páginas de perfil. É claro que a gente deveria também verificar se estamos na página correta ou não.&lt;/p&gt;
&lt;p&gt;Agora, o próximo passo importante é a classe abstrata &lt;code&gt;CrawlProfile&lt;/code&gt;. Com esta classe a gente consegue decidir se uma URL deveria ou não ser acessada por um observer. Vamos criar também como classe anônima:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;$profile = new class
  extends CrawlProfile
{
  public function shouldCrawl(
    $url
  ): bool {
    return $url-&amp;gt;getHost() ===
      &apos;people.php.net&apos;;
  }
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Acima a gente definiu que queremos seguir apenas links internos. Isso porque esse website cria links pra vários outros repositórios. E a gente não quer crawlear todo o universo php, certo?&lt;/p&gt;
&lt;p&gt;Com essas duas instâncias em mãos, podemos já preparar o crawler e iniciar a busca:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;Crawler::create()
  -&amp;gt;setCrawlObserver($observer)
  -&amp;gt;setCrawlProfile($profile)
  -&amp;gt;setDelayBetweenRequests(500)
  -&amp;gt;startCrawling(
    &apos;https://people.php.net/&apos;
  );
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Importante!&lt;/strong&gt; Reparou naquele &lt;code&gt;setDelayBetweenRequests(500)&lt;/code&gt;? Ele faz com que o crawler vá buscar apenas uma URL a cada 500 milisegundos. Isso é porque a gente não quer derrubar esse site, certo? (Sérião, não derruba esse site. Se tu quer fazer maldade, busca um site do governo ou coisa do gênero 👀)&lt;/p&gt;
&lt;h2&gt;E é isso!&lt;/h2&gt;
&lt;p&gt;Rápido e prático, e mais importante de tudo: sem loucuras! O &lt;code&gt;spatie/crawler&lt;/code&gt; tem uma interface muito massa que simplifica demais o processo.&lt;/p&gt;
&lt;p&gt;Se você juntar essa ferramenta com uma injeção de dependências e enfileiramento você terá resultados profissionais.&lt;/p&gt;
&lt;p&gt;Me dá um toque no twitter se você tiver dúvidas! Uma abraço! 👋&lt;/p&gt;</content:encoded><category>php</category></item><item><title>Como escrever jogos na linguagem PHP</title><link>https://codamos.com.br/jogos-em-php/</link><guid isPermaLink="true">https://codamos.com.br/jogos-em-php/</guid><description>Sim, você leu certo! Um jogo. Escrito na linguagem PHP. Antes de eu te mostrar o código em si, gostaria de mostrar o resultado! Não está bem acabado, então abaixemos as expectativas por agora. Eu só q</description><pubDate>Mon, 20 Apr 2020 10:03:00 GMT</pubDate><content:encoded>&lt;p&gt;Sim, você leu certo!&lt;/p&gt;
&lt;p&gt;Um jogo. Escrito na linguagem PHP.&lt;/p&gt;
&lt;p&gt;Antes de eu te mostrar o código em si, gostaria de mostrar o resultado! Não está bem acabado, então abaixemos as expectativas por agora. Eu só queria montar uma POC boa o suficiente pra mostrar aqui 😬&lt;/p&gt;
&lt;p&gt;Você pode ver o gameplay no vídeo abaixo.&lt;/p&gt;
&lt;p&gt;&lt;iframe width=&quot;100%&quot; height=&quot;400&quot; src=&quot;https://player.vimeo.com/video/406784115&quot; frameborder=&quot;0&quot; allow=&quot;autoplay; fullscreen&quot; allowfullscreen=&quot;allowfullscreen&quot; data-mce-fragment=&quot;1&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p&gt;Massa, né!? E isso é só uma POC, mas com o que já existe nesta extensão você já pode brincar com diferentes texturas, audios e etc..&lt;/p&gt;
&lt;p&gt;Eu vou te mostrar como ficou o código e quais ferramentas eu utilizei! Espero que isso tome sua atenção suficientemente para vermos esta extensão ganhar tração.&lt;/p&gt;
&lt;p&gt;Antes de qualquer coisa, deixa eu te falar um pouco sobre a raylib.&lt;/p&gt;
&lt;h2&gt;Raylib&lt;/h2&gt;
&lt;p&gt;Escrita na linguagem C, Raylib é definida como &quot;uma biblioteca simples e de fácil utilização para curtir a programação de jogos&quot;.&lt;/p&gt;
&lt;p&gt;Ela oferece funções muito simplistas para manipular vídeo, áudio, ler entradas de teclado, mouse ou joysticks. Ela também suporta renderização 2d e 3d. É uma biblioteca bem completinha.&lt;/p&gt;
&lt;p&gt;Aqui vai uma visão geral da arquitetura da Raylib. Ela espera que você vá escrever seu jogo, engine ou ferramentas em cima dos módulos da Raylib. Os módulos oferecem funcionalidades para controlar coisas como câmera, texturas, texto, formas, modelos, áudio, matemática...&lt;/p&gt;
&lt;figure class=&quot;post__image&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/10/raylib_architecture_v4.0.png&quot; alt=&quot;&quot; width=&quot;1700&quot; height=&quot;1440&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Visão geral da arquitetura da Raylib. Fonte: https://www.raylib.com/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Ela não vem com coisas de engine, como detecção complexa de colisão ou física. Se você precisar de algo desse tipo, precisará escrever por si. Ou encontrar algo já escrito por outra pessoa e que esteja preparado para rodar com a Raylib.&lt;/p&gt;
&lt;h2&gt;Extensão Raylib PHP&lt;/h2&gt;
&lt;p&gt;Recentemente uma extensão PHP chamou a minha atenção. Desenvolvida por &lt;a href=&quot;https://github.com/joseph-montanez&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;@joseph-montanez&lt;/a&gt; há um certo tempo atrás, a extensão &lt;a href=&quot;https://github.com/joseph-montanez/raylib-php&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;&lt;strong&gt;raylib-php&lt;/strong&gt;&lt;/a&gt; teve seu primeiro lançamento alpha pouco menos de um mês atrás.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Se você precisa saber como compilar e rodar&lt;/strong&gt; por favor acesse o arquivo README.md do repositório oficial. No MacOS os seguintes passos funcionaram de boa pra mim:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ git clone git@github.com:joseph-montanez/raylib-php.git
$ cd raylib-php/
$ phpize
$ ./configure
$ make
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Somente compilou tranquilo com o PHP 7.4 na minha máquina. Então bota aí a versão correta do PHP.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Essa extensão quer oferecer a mesma interface que a biblioteca em C, então a gente poderá desenvolver os jogos mais ou menos da mesma forma.&lt;/p&gt;
&lt;p&gt;Claro que já que a biblioteca em C não traz coisas específicas de jogos como física e outras paradinhas, você precisará implementar essas coisas em PHP.&lt;/p&gt;
&lt;p&gt;Esta extensão ainda não está completa. Você pode dar uma olhada no MAPPING.md do repositório oficial pra entender o que já foi feito e o que falta.&lt;/p&gt;
&lt;p&gt;Mesmo não estando completa, eu decidi brincar um pouco com a extensão e, até onde consegui ver, já está bem funcional.&lt;/p&gt;
&lt;h2&gt;Um jogo da cobrinha simplão&lt;/h2&gt;
&lt;p&gt;Mesmo sendo &quot;Snake&quot; (ou &quot;jogo da cobrinha&quot;) um jogo bem simples eu decidi não implementá-lo completamente. Meu principal objetivo aqui era ter um jogo bom o suficiente pra eu poder testar algumas coisas básicas da extensão.&lt;/p&gt;
&lt;p&gt;Então eu resolvi pegar alguns requisitos pra implementar:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A cobrinha precisa mover-se constantemente, mas pode mudar de direção&lt;/li&gt;
&lt;li&gt;Deverá existir apenas uma frutinha na tela, posicionada aleatóriamente&lt;/li&gt;
&lt;li&gt;Quando a cabeça da cobrinha toca numa fruta, cinco coisas devem acontecer: a fruta tem de ser destruída, o corpo da cobrinha deve crescer, outra fruta deve ser criada, o contador de pontos deve aumentar em 1 e a velocidade da cobrinha também deverá aumentar&lt;/li&gt;
&lt;li&gt;Quando a cobrinha toca na borda da tela, ela deverá aparecer do outro lado&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Deveria ser claro, mas também é requisito que o jogador possa mudar a direção em que a cobrinha anda usando alguma ferramenta de entrada como o teclado.&lt;/p&gt;
&lt;p&gt;Tem também dois requisitos bem importantes que eu decidi não implementar aqui: 1) a cobrinha não pode morder a si mesma. Ou seja, se a cobrinha bater em seu próprio corpo, o jogo deve acabar. 2) a cobrinha não pode mudar de direção para um sentido diretamente oposto ao atual. Então quando se está andando para a direita, mudar para a esquerda requer que primeiro se vá para cima ou para baixo.&lt;/p&gt;
&lt;p&gt;Estes dois requisitos não foram implementados pois se tratam de algorítmo e não adicionariam muito para o experimento em si.&lt;/p&gt;
&lt;h3&gt;Implementação&lt;/h3&gt;
&lt;p&gt;Essa implementação tem dois componentes: o Game Loop e o Game State.&lt;/p&gt;
&lt;p&gt;O game loop é responsável por atualizar o estado do jogo baseado nas entradas do(a) jogador(a) e cálculos e mais tarde por pintar este estado na tela. Para isto eu criei uma classe chamada &quot;&lt;em&gt;GameLoop&lt;/em&gt;&quot;.&lt;/p&gt;
&lt;p&gt;O game state mantém o estado atual do jogo (snapshot). Ele guarda coisas como a pontuação do(a) jogador(a), as coordenadas x,y da fruta, as coordenadas x,y da cobrinha e todos os quadradinhos que formam o corpo da cobrinha. Para esta eu criei uma classe “&lt;em&gt;GameState&lt;/em&gt;”.&lt;/p&gt;
&lt;p&gt;Veja a seguir como estas classes são.&lt;/p&gt;
&lt;h3&gt;Game Loop&lt;/h3&gt;
&lt;p&gt;A classe GameLoop inicializa o sistema, e cria um loop que executa dois passos em cada iteração: atualizar o estado (update) e desenhar o estado na tela (draw).&lt;/p&gt;
&lt;p&gt;Então no construtor eu inicializei o canvas com largura e altura e instanciei o GameState.&lt;/p&gt;
&lt;p&gt;Como parâmetros ao GameState eu passei largura e altura divididos por um tamanho de célula (30 pixels no meu caso). Estes valores representam os valores máximos de coordenadas X e Y que o GameState poderá trabalhar. A gente vai ver isso depois.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;// GameLoop.php
final class GameLoop
{
  // ...
  public function __construct(
    int $width,
    int $height
  ) {
    $this-&amp;gt;width = $width;
    $this-&amp;gt;height = $height;

  // 30
  $s = self::CELL_SIZE;
  $this-&amp;gt;state = new GameState(
      (int) ($this-&amp;gt;width / $s),
      (int) ($this-&amp;gt;height / $s)
    );
  }
  // ...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Mais tarde, um método público chamado &lt;em&gt;start()&lt;/em&gt; vai criar uma Janela, definir a taxa de frames e criar um loop infinito - sim, meio que um &lt;code&gt;while (true)&lt;/code&gt; - que vai primeiro chamar um método privado &lt;em&gt;update()&lt;/em&gt; e mais tarde um método &lt;em&gt;draw()&lt;/em&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;// ...
public function start(): void
{
  Window::init(
    $this-&amp;gt;width,
    $this-&amp;gt;height,
    &apos;PHP Snake&apos;
  );
  Timing::setTargetFPS(60);

  while (
    !$this-&amp;gt;shouldStop &amp;&amp;
    !Window::shouldClose()
  ) {
    $this-&amp;gt;update();
    $this-&amp;gt;draw();
  }
}
// ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;O método &lt;em&gt;update()&lt;/em&gt; será responsável por atualizar a instância de game state. Ele faz isso ao ler as entradas do(a) jogador(a) (ao pressionar teclas) e fazendo coisas como verificar colisão e por aí vai.&lt;/p&gt;
&lt;p&gt;Baseado nos cálculos realizados no método &lt;em&gt;update()&lt;/em&gt;, mudanças de estado são enviadas à instância de &lt;em&gt;GameState&lt;/em&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;private function update(): void
{
  $head = $this-&amp;gt;state-&amp;gt;snake[0];
  $recSnake = new Rectangle(
    (float) $head[&apos;x&apos;],
    (float) $head[&apos;y&apos;],
    1,
    1,
  );

  $fruit = $this-&amp;gt;state-&amp;gt;fruit;
  $recFruit = new Rectangle(
    (float) $fruit[&apos;x&apos;],
    (float) $fruit[&apos;y&apos;],
    1,
    1,
  );

  // Snake morde a fruta
  if (
    Collision::checkRecs(
      $recSnake,
      $recFruit
    )
  ) {
    $this-&amp;gt;state-&amp;gt;score();
  }

  // Controla velocidade do passo
  $now = microtime(true);
  if (
    $now - $this-&amp;gt;lastStep
    &amp;gt; (1 / $this-&amp;gt;state-&amp;gt;score)
  ) {
    $this-&amp;gt;state-&amp;gt;step();
    $this-&amp;gt;lastStep = $now;
  }

  // Atualiza a direção se necessário
  if (Key::isPressed(Key::W)) {
    $this-&amp;gt;state-&amp;gt;direction = GameState::DIRECTION_UP;
  } else if (Key::isPressed(Key::D)) {
    $this-&amp;gt;state-&amp;gt;direction = GameState::DIRECTION_RIGHT;
  } else if (Key::isPressed(Key::S)) {
    $this-&amp;gt;state-&amp;gt;direction = GameState::DIRECTION_DOWN;
  } else if (Key::isPressed(Key::A)) {
    $this-&amp;gt;state-&amp;gt;direction = GameState::DIRECTION_LEFT;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Por último vem o método &lt;em&gt;draw()&lt;/em&gt;. Ele vai ler as propriedades do &lt;em&gt;GameState&lt;/em&gt; e pintá-las. Aplicando proporções e escalas.&lt;/p&gt;
&lt;p&gt;Da forma como eu construí, este método espera que coordenadas X variem de 0 até (largura dividida pelo tamanho da célula) e coordenadas Y veriem de 0 até (altura dividida pelo tamanho da célula). Ao multiplicar cada coordenada por &quot;tamanho da célula&quot; a gente consegue desenhar com boas proporções sem precisar misturar o gerenciamento de estado e desenho.&lt;/p&gt;
&lt;p&gt;Bem simples. Fica assim:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;private function draw(): void
{
  Draw::begin();

  // Limpa a tela
  Draw::clearBackground(
    new Color(255, 255, 255, 255)
  );

  // Desenha a fruta
  $x = $this-&amp;gt;state-&amp;gt;fruit[&apos;x&apos;];
  $y = $this-&amp;gt;state-&amp;gt;fruit[&apos;y&apos;];
  Draw::rectangle(
    $x * self::CELL_SIZE,
    $y * self::CELL_SIZE,
    self::CELL_SIZE,
    self::CELL_SIZE,
    new Color(200, 110, 0, 255)
  );

  // Desenha o corpo da cobrinha
  foreach (
    $this-&amp;gt;state-&amp;gt;snake as $coords
  ) {
    $x = $coords[&apos;x&apos;];
    $y = $coords[&apos;y&apos;];
    Draw::rectangle(
      $x * self::CELL_SIZE,
      $y * self::CELL_SIZE,
      self::CELL_SIZE,
      self::CELL_SIZE,
      new Color(0,255, 0, 255)
    );
  }

  // Desenha a pontuação
  $score = &quot;Score: {$this-&amp;gt;state-&amp;gt;score}&quot;;
  Text::draw(
    $score,
    $this-&amp;gt;width - Text::measure($score, 12) - 10,
    10,
    12,
    new Color(0, 255, 0, 255)
  );

  Draw::end();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Tem algumas outras coisas que eu adicionei para depurar mas eu prefiro deixá-las de fora deste artigo.&lt;/p&gt;
&lt;p&gt;Depois disso, vem o gerenciamento de estado. Esta é a responsabilidade de GameState. Vamo vê!&lt;/p&gt;
&lt;h3&gt;Game State&lt;/h3&gt;
&lt;p&gt;O &lt;em&gt;GameState&lt;/em&gt; representa tudo que existe no game. Pontuação, objetos como o(a) jogador(a) e as frutas.&lt;/p&gt;
&lt;p&gt;Isto significa que sempre que o(a) jogador(a) precisar mover-se ou uma fruta for comida, isto ocorrerá dentro de &lt;em&gt;GameState&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Para o corpo da cobrinha eu decidi criar um array com coordenadas (x,y) dentro. E eu considerei o primeiro elemento (índice zero) como sendo a cabeça da cobrinha. Adicionar mais elementos (x,y) neste array então deveria aumentar o tamanho do corpo da cobrinha.&lt;/p&gt;
&lt;p&gt;Já a fruta é um simples par de coordenadas (x,y), pois eu espero ter apenas uma fruta na tela por vez.&lt;/p&gt;
&lt;p&gt;O construtor da classe &lt;em&gt;GameState&lt;/em&gt; inicializa estes objetos com coordenadas aleatórias. Ficou assim:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;// GameState.php
final class GameState
{
  public function __construct(
    int $maxX,
    int $maxY
  ) {
    $this-&amp;gt;maxX = $maxX;
    $this-&amp;gt;maxY = $maxY;

    $this-&amp;gt;snake = [
      $this-&amp;gt;craftRandomCoords(),
    ];

    $this-&amp;gt;fruit = $this-&amp;gt;craftRandomCoords();
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Para aumentar o tamanho do corpo da cobrinha, eu criei um método privado chamado &lt;em&gt;incrementBody()&lt;/em&gt; que vai adicionar uma nova cabeça ao corpo da cobrinha. Esta cabeça deverá considerar a direção em que a cobrinha estava andando. (esquerda, direita, acima ou abaixo)&lt;/p&gt;
&lt;p&gt;Para criar uma nova cabeça, eu só copio a cabeça atual, atualizo as coordenadas baseado na direção atual e mesclo esta cópia com o corpo ocupando o índice zero.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;private function incrementBody(): void
{
  $newHead = $this-&amp;gt;snake[0];

  // Ajusta a direção da cabeça
  switch ($this-&amp;gt;direction) {
    case self::DIRECTION_UP:
      $newHead[&apos;y&apos;]--;
    break;
    case self::DIRECTION_DOWN:
      $newHead[&apos;y&apos;]++;
    break;
    case self::DIRECTION_RIGHT:
      $newHead[&apos;x&apos;]++;
    break;
    case self::DIRECTION_LEFT:
      $newHead[&apos;x&apos;]--;
    break;
  }

  // Adiciona nova cabeça,
  // na frente do corpo todo
  $this-&amp;gt;snake = array_merge(
    [$newHead],
    $this-&amp;gt;snake
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Tendo o método &lt;em&gt;incrementBody()&lt;/em&gt; fica bem fácil implementar o método &lt;em&gt;score()&lt;/em&gt;, que apenas aumenta a pontuação e o tamanho do corpo da cobrinha. O &lt;em&gt;score()&lt;/em&gt; também vai criar uma nova fruta numa coordenada aleatória da tela.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;public function score(): void
{
  $this-&amp;gt;score++;
  $this-&amp;gt;incrementBody();
  $this-&amp;gt;fruit = $this-&amp;gt;craftRandomCoords();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;O mais interessante é o método &lt;em&gt;step()&lt;/em&gt;, que é responsável por mover a cobrinha.&lt;/p&gt;
&lt;p&gt;Se você bem se lembrar, a forma como Snake se mexe é que a cabeça vai constantemente andar em uma direção e o corpo a segue. Então se Snake tem tamanho 3 e seu corpo está andando para baixo, são necessários três passos para que ela ande para a esquerda completamente.&lt;/p&gt;
&lt;p&gt;A forma como eu fiz, foi basicamente aumentar o tamanho do corpo novamente (que adiciona uma nova cabeça na nova direção) e remover o último elemento do corpo da cobrinha. Desta forma o tamanho corpo continua o mesmo e as coordenadas antigas serão apagadas.&lt;/p&gt;
&lt;p&gt;Eu também adicionei uma lógica para aparecer do outro lado da tela quando a cabeça da cobrinha bater na borda da tela.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;public function step(): void
{
  $this-&amp;gt;incrementBody();

  // Remove o último elemento
  array_pop($this-&amp;gt;snake);

  // Move o corpo para o
  // outro lado da tela
  // se necessário
  foreach ($this-&amp;gt;snake as &amp;amp;$coords) {
    if ($coords[&apos;x&apos;] &amp;gt; $this-&amp;gt;maxX - 1) {
      $coords[&apos;x&apos;] = 0;
    } else if ($coords[&apos;x&apos;] &amp;lt; 0) {
      $coords[&apos;x&apos;] = $this-&amp;gt;maxX - 1;
    }

    if ($coords[&apos;y&apos;] &amp;gt; $this-&amp;gt;maxY - 1) {
      $coords[&apos;y&apos;] = 0;
    } else if ($coords[&apos;y&apos;] &amp;lt; 0) {
      $coords[&apos;y&apos;] = $this-&amp;gt;maxY - 1;
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Agora é só grudar tudo, instanciar as coisa e tamo pronto pra jogar!&lt;/p&gt;
&lt;h2&gt;Faz sentido desenvolver jogos em PHP?&lt;/h2&gt;
&lt;p&gt;Certamente faz mais sentido que antes. Espero que menos que amanhã.&lt;/p&gt;
&lt;p&gt;A extensão oferece interfaces bem bacanudas, mas ainda não está completa. Se você sabe um pouco de C, você também pode tornar o futuro um lugar melhor para desenvolvimento de jogos em PHP ao contribuir com esta extensão.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/joseph-montanez/raylib-php/blob/master/MAPPING.md&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Aqui tem uma lista onde você pode encontrar funções que ainda precisam de implementação&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;O PHP ainda é bloqueante por padrão, então operações de E/S precisam ser tratadas com cuidado. É possível utilizar esta biblioteca junto de um Event Loop our usando threads da extensão Parallel. Provavelmente você precisará escrever algo customizado pra isto.&lt;/p&gt;
&lt;p&gt;O que mais me deixa encucado até o momento é sobre o quão portáveis os jogos em PHP podem ser. Não tem uma forma simples de empacotar estes jogos em binários. Então jogadores precisariam instalar o PHP e compilar a extensão Raylib pra poder jogar algo.&lt;/p&gt;
&lt;p&gt;Mas como eu mencionei, os primeiros passos foram dados. Então tecnicamente já é mais fácil desenvolver jogos do que era antes.&lt;/p&gt;
&lt;p&gt;Agradeço muito ao Joseph Montanez. Sua extensão me inspirou muito e eu espero que esta publicação alcance e instigue mais desenvolvedores(as) para ajudar no desenvolvimento dela.&lt;/p&gt;</content:encoded><category>php</category></item><item><title>Comparando JSON e MessagePack</title><link>https://codamos.com.br/benchmark-messagepack-json/</link><guid isPermaLink="true">https://codamos.com.br/benchmark-messagepack-json/</guid><description>TL;DR Sim, tecnicamente o MessagePack ganha em todos testes. Mas a diferença é tão marginal que eu não consigo ver muitas vantagens em migrar do JSON para o MessagePack. Mas talvez faça sentido utiliz</description><pubDate>Sun, 15 Mar 2020 10:59:00 GMT</pubDate><content:encoded>&lt;h2&gt;TL;DR&lt;/h2&gt;
&lt;p&gt;Sim, tecnicamente o MessagePack ganha em todos testes. Mas a diferença é tão marginal que &lt;strong&gt;eu não consigo ver muitas vantagens em migrar do JSON para o MessagePack.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Mas talvez faça sentido utilizar MessagePack desde o início. &lt;strong&gt;MessagePack é um tiquinho mais rápido e leve se comparado ao JSON.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Utilizar MessagePack para trocar dados entre o navegador e servidor não parece parece fazer muito sentido na minha opinião.&lt;/strong&gt; O tamanho da resposta não faz muita diferença quando se aplica o filtro gzip (alguns poucos bytes), mas depurar as mensagens de rede passa a ser mais difícil. Por outro lado, isto pode lhe ajudar a evitar que sua API seja consumida por bots com tanta frequência.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/nawarian/msgpack-bm&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Você pode encontrar o código do benchmark e os números neste repositório que eu criei.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nota rápida:&lt;/strong&gt; Este artigo está HORRÍVEL em telas pequenas. Desculpem-me por isso, mas eu preciso apresentar tabelas para mostrar meus dados.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/nawarian&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Me dá um alô no twitter se você tiver uma forma melhor de representar esses dados em vez de tabular tudo.&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;O que é MessagePack?&lt;/h2&gt;
&lt;p&gt;Como descrito no &lt;a href=&quot;https://msgpack.org/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;site oficial do MessagePack&lt;/a&gt; ele é como JSON, mas rápido e leve.&lt;/p&gt;
&lt;p&gt;Em outras palavras, &lt;strong&gt;o MessagePack é um formato de serialização que transforma estruturas de dados em strings binárias.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;O motivo de ele ser tão eficiente é que as estruturas de dados são mapeadas utilizando uma notação pequenininha de binários em stream. O tamanho final é quase metade do tamanho de algo serializado em JSON.&lt;/p&gt;
&lt;p&gt;O exemplo do site oficial compara a mesma estrutura de dados sendo representada nos formatos JSON e MessagePack. O exemplo usado na home page mostra um map contendo duas chaves: &lt;code&gt;compact = true&lt;/code&gt; e &lt;code&gt;schema = 0&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A versão &lt;strong&gt;em JSON&lt;/strong&gt; deste map tem &lt;code&gt;27 bytes&lt;/code&gt; enquanto o &lt;strong&gt;MessagePack&lt;/strong&gt; o faz em apenas &lt;code&gt;18 bytes&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;// Map utilizado no
// exemplo oficial
$json = [
  &quot;compact&quot; =&amp;gt; true,
  &quot;schema&quot; =&amp;gt; 0,
];

// 27 bytes
json_encode($json);

// 18 bytes
msgpack_pack($json);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Eu aprendi sobre este formato muito recentemente e por um completo acidente, enquanto lia este &lt;a href=&quot;https://twitter.com/eminetto/status/1237510796948758535&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;tweet do @eminetto&lt;/a&gt; , mas aparentemente isso existe desde 2012.&lt;/p&gt;
&lt;p&gt;Me deixou encucado isso, já que eu trabalho com aplicações de muito tráfego que constante mente troca mensagens em JSON com diferentes serviços no back-end. Me cheira como se fosse algo simples de implementar e ganhar rios de performance.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Eu então decidi fazer um benchmark do MessagePack no PHP como extensão em C contra a extensão JSON nativa do PHP (também escrita em C).&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;O ambiente de benchmark&lt;/h2&gt;
&lt;p&gt;Pra testar isso tudo, eu montei um &lt;a href=&quot;https://github.com/nawarian/msgpack-bm&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;repositório simplão com três benchmarks diferentes&lt;/a&gt;. Um arquivo testa a serialização msgpack, e os outros dois testam a serialização JSON sendo que o último desserializa utilizando a opção &quot;assoc&quot; com valor true.&lt;/p&gt;
&lt;p&gt;Pra executar estes benchmarks, eu escolhi utilizar o Travis CI, já que qualquer pessoa pode reproduzir estes testes de forma simplificada. Os dados que consegui coletar do ambiente de execução são:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CPU: Intel(R) Xeon(R); 1 @ 2,8 GHz; Cache 33 MB&lt;/li&gt;
&lt;li&gt;RAM: 7,79 GB&lt;/li&gt;
&lt;li&gt;OS: linux/amd64 (Ubuntu 16.04.6 LTS - Xenial)&lt;/li&gt;
&lt;li&gt;Versão do PHP: 7.4.3&lt;/li&gt;
&lt;li&gt;Versão do MsgPack: 2.1.0&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Num futuro próximo eu vou atualizar o benchmark pra rodar contra o PHP 8 e o Just In Time compiler dele. &lt;a href=&quot;/php-8-jit/&quot;&gt;Como eu escrevi num outro post sobre como o JIT funciona&lt;/a&gt;, o JIT pode melhorar bastante a performance em oeprações de CPU.&lt;/p&gt;
&lt;p&gt;A entidade que eu utilizei pra serializar/desserializar é uma resposta real da API de issues do github. Ela tem 2321 linhas e 147 KB de tamanho. Me parece um exemplo bem decente pra representar dados reais de uma resposta de API.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Você pode verificar a entidade aqui:&lt;/strong&gt; &lt;a href=&quot;https://github.com/nawarian/msgpack-bm/blob/master/github-issues.json&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;https://github.com/nawarian/msgpack-bm/blob/master/github-issues.json&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;MessagePack é mais rápido e mais leve que o JSON&lt;/h2&gt;
&lt;p&gt;Como você pode notar, eu odeio esconder informação. Te digo logo de cara: &lt;strong&gt;O MessagePack ganha do JSON em cada teste.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Mas a diferença é bem pequetuxa, na real. Se liga:&lt;/p&gt;
&lt;h3&gt;Tamanho das saídas:&lt;/h3&gt;
&lt;p&gt;Ao falar sobre APIs, uma das coisas mais importantes é o tamanho do corpo da mensagem que está sendo transportada na rede. Os valores crus são bem impressionantes, but todo bom programador(a) sabe que na maioria dos casos &lt;strong&gt;devemos comprimir nossas APIs usando filtros como gzip ou brotli.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Então para esta comparação eu decidi mostrar o tamanho do conteúdo serializado nos dois formatos e adicionei também a versão comprimida com gzip.&lt;/p&gt;
&lt;p&gt;A comparação ficou assim:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Formato&lt;/th&gt;
&lt;th&gt;Serializado (bytes)&lt;/th&gt;
&lt;th&gt;Serializado + Gzip (bytes)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;JSON&lt;/td&gt;
&lt;td&gt;143025&lt;/td&gt;
&lt;td&gt;26214&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MessagePack&lt;/td&gt;
&lt;td&gt;120799 (-22226)&lt;/td&gt;
&lt;td&gt;26074 (-140)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Como pode-se notar, quando não há filtros de compressão o MessagePack é cerca de 22 KB mais leve que o JSON. Mas quando aplicamos o gzip nos dois valores, MessagePack passa a ganhar por míseros 140 bytes. &lt;strong&gt;Nada expressivo.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;Tempos de Serialização/Desserialização:&lt;/h3&gt;
&lt;p&gt;A outra parte importante no processo de serialização é quanto tempo leva pra transformar aquele formato. Para tal eu decidi &lt;strong&gt;serializar e desserializar a mesma entidade várias vezes&lt;/strong&gt; e tomar notas sobre o consumo de memória e &lt;strong&gt;tempos de processamento.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;O consumo de memória não parece mudar muito neste teste a não ser que você passe a desserializar a mesma entidade um milhão de vezes, o que eu espero não ser tão comum para a maioria das aplicações PHP. Portanto &lt;strong&gt;eu não vou apresentar os números sobre utilização de memória já que a variação foi de 0 bytes.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Enquanto eu coletava os números sobre JSON, &lt;strong&gt;eu descobri que desserializar uma entidade com assoc = true é um pouquinho mais rápido em comparação com assoc = false.&lt;/strong&gt; O que é um tanto interessante e até faz um certo sentido.&lt;/p&gt;
&lt;p&gt;Já que os resultados com assoc = true são melhores para o JSON, eu vou utilizar estes dados somente na comparação.&lt;/p&gt;
&lt;p&gt;O resultado:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Iterações&lt;/th&gt;
&lt;th&gt;Serialização JSON (s)&lt;/th&gt;
&lt;th&gt;Serialização MessagePack (s)&lt;/th&gt;
&lt;th&gt;Desserialização JSON (s)&lt;/th&gt;
&lt;th&gt;Desserialização MessagePack (s)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0.00064&lt;/td&gt;
&lt;td&gt;0.00019 (-0,00045)&lt;/td&gt;
&lt;td&gt;0.00164&lt;/td&gt;
&lt;td&gt;0.00051 (-0,00113)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;0.00340&lt;/td&gt;
&lt;td&gt;0.00082 (-0,00258)&lt;/td&gt;
&lt;td&gt;0.00866&lt;/td&gt;
&lt;td&gt;0.00194 (-0,00672)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;0.03135&lt;/td&gt;
&lt;td&gt;0.00732 (-0,02403)&lt;/td&gt;
&lt;td&gt;0.07905&lt;/td&gt;
&lt;td&gt;0.01700 (-0,06205)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;td&gt;0.30385&lt;/td&gt;
&lt;td&gt;0.07250 (-0,23135)&lt;/td&gt;
&lt;td&gt;0.77422&lt;/td&gt;
&lt;td&gt;0.16785 (-0,60637)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10000&lt;/td&gt;
&lt;td&gt;3.02723&lt;/td&gt;
&lt;td&gt;0.72503 (-2,95472)&lt;/td&gt;
&lt;td&gt;7.74523&lt;/td&gt;
&lt;td&gt;1.65804 (-6,08719)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;100000&lt;/td&gt;
&lt;td&gt;30.29353&lt;/td&gt;
&lt;td&gt;7.25324 (-23,04029)&lt;/td&gt;
&lt;td&gt;77.48423&lt;/td&gt;
&lt;td&gt;16.71792 (-60,76631)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;As &lt;strong&gt;iterações&lt;/strong&gt; aqui significam quantas vezes nós executamos a mesma operação. Sendo a operação um &lt;code&gt;json_encode&lt;/code&gt;, &lt;code&gt;msgpack_pack&lt;/code&gt;, &lt;code&gt;json_decode&lt;/code&gt; ou &lt;code&gt;msgpack_unpack&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Pessoalmente eu prestaria atenção nos números de 1 a 100 iterações. Acima deste número, começa a ficar menos realista para mim. Eu os deixei alí de toda forma, os resultados começam a ficar bem interessantes a partir de 10 mil iterações.&lt;/p&gt;
&lt;p&gt;Como você pode perceber, as diferenças são bem pequenas nas primeiras iterações.&lt;/p&gt;
&lt;p&gt;Quando uma única operação de serialização é chamada, &lt;strong&gt;MessagePack&lt;/strong&gt; é 0,45 ms mais rápido. &lt;strong&gt;Nada expressivo.&lt;/strong&gt; Quando o número de serializações passa a 100, a diferença começa a se tornar evidente e o &lt;strong&gt;MessagePack é 24 ms mais rápido que o JSON.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Desserializações são normalmente mais lentas para os dois formatos, mas o MessagePack ganha aqui novamente. Quando uma única desserialização ocorre, &lt;strong&gt;MessagePack é 1 ms mais rápido.&lt;/strong&gt; Enquanto 100 desserializações são &lt;strong&gt;62 ms mais rápidas com MessagePack em comparação com JSON.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Mesmo que a diferença seja grande o suficiente quando 100 items precisam ser desserializados, eu acredito que na maioria das aplicações PHP seja bem improvável de acontecer. Um número de operações entre 1 e 10 é bem plausível pra mim e &lt;strong&gt;o MessagePack é 2 ms mais rápido em serializações e 6 ms em desserializações quando executado 10 vezes.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Bons números, mas nada muito expressivo.&lt;/p&gt;
&lt;h2&gt;Devo migrar do JSON para o MessagePack?&lt;/h2&gt;
&lt;p&gt;Quando se trata de engenharia de software, a única resposta que podemos dar com certeza é: &lt;strong&gt;depende.&lt;/strong&gt; Toda aplicação tem diferentes desafios e situações.&lt;/p&gt;
&lt;p&gt;Por exemplo, se você estiver trocando arquivos entre diferentes sistemas e comprimir o seu conteúdo não é uma opção, então o MessagePack pode ser ótimo pra economizar espaçø em disco e reduzir a carga numa operação de stream.&lt;/p&gt;
&lt;p&gt;Uma aplicação comunicando com microsserviços no back-end pode se beneficiar da velocidade que o MessagePack traz se o número de interações for maior que 10 por requisição.&lt;/p&gt;
&lt;p&gt;Eu suspeito (apesar de não ter testado) que serializar/desserializar o MessagePack no JavaScript seja um tanto mais lento se comparado ao json, já que o MessagePack não roda como parte do motor JavaScript (Node, V8). Então possívelmente aplicações Front-End não se beneficiariam tanto do MessagePack ainda.&lt;/p&gt;
&lt;p&gt;Além disso, depurar respostas na aba Network do navegador se tornaria insuportável. Por outro lado, isto pode lhe ajudar a obfuscar sua API e evitar crawlers espertinhos já que o MessagePack ainda não é tão conhecido.&lt;/p&gt;
&lt;p&gt;Assim como qualquer outro benchmark, este aqui é bem inútil se você estiver buscando uma resposta de fácil utilização. Você precisará adaptar isso aqui para o seu cenário e ver como o MessagePack se comporta.&lt;/p&gt;
&lt;p&gt;Felizmente migrar de um formato para o outro deveria ser tão simples quanto trocar uma chamada de &lt;code&gt;json_encode&lt;/code&gt; para &lt;code&gt;msgpack_pack&lt;/code&gt; e de &lt;code&gt;json_decode&lt;/code&gt; para &lt;code&gt;msgpack_unpack&lt;/code&gt;. No caso de comunicar-se com microsserviços, um simples cabeçalho &lt;code&gt;Accept&lt;/code&gt; já deve lhe resolver a vida.&lt;/p&gt;
&lt;p&gt;Claro que quanto mais for necessário refatorar, maior o custo de implementar e testar essas mudanças. Portanto tenha certeza de que você analisou os possíveis ganhos antes de tentar mudar todos seus serviços e consumidores para este novo formato.&lt;/p&gt;
&lt;p&gt;Pra mim um trabalho de 30 minutos para 2 ms de performance parece ser justo. Mas gastar 3 semanas para os mesmos 2 ms não parece fazer muito sentido. Ao menos não na escala em que estou acostumado a trabalhar.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Utilizar o MessagePack desde o começo parece fazer muito sentido.&lt;/strong&gt; Já que ele ganha do JSON em todos os testes. Então se você for escrever algo novo, considere o MessagePack.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Não se esqueça de compartilhar isso com seus(uas) amigos(as) e colegas nerdões(onas). Eu tenho certeza de que o MessagePack será uma boa opção para muitos(as) deles(as).&lt;/p&gt;</content:encoded><category>php</category></item><item><title>Just In Time Compiler (JIT) e o PHP 8</title><link>https://codamos.com.br/php-8-jit/</link><guid isPermaLink="true">https://codamos.com.br/php-8-jit/</guid><description>TL;DR O Just In Time compiler do PHP 8 foi implementado como parte da extensão Opcache e tem como objetivo compilar Opcodes em instruções de máquina em tempo de execução. Significa que com o JIT algun</description><pubDate>Tue, 03 Mar 2020 10:45:00 GMT</pubDate><content:encoded>&lt;h2&gt;TL;DR&lt;/h2&gt;
&lt;p&gt;O Just In Time compiler do PHP 8 foi implementado como parte da &lt;a href=&quot;https://www.php.net/manual/en/book.opcache.php&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;extensão Opcache&lt;/a&gt; e tem como objetivo compilar Opcodes em instruções de máquina em tempo de execução.&lt;/p&gt;
&lt;p&gt;Significa que &lt;strong&gt;com o JIT alguns Opcodes não precisarão ser interpretados pela Zend VM e estas instruções serão executadas diretamente a nível de CPU.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;JIT e PHP&lt;/h2&gt;
&lt;p&gt;Uma das novidades mais comentadas sobre o PHP 8 é o Just In Time (JIT) compiler. Vários blogs e pessoas da comunidade estão falando sobre isso e com certeza é um dos tópicos mais relevantes desta versão. Porém até o momento eu não consegui achar muitos detalhes sobre o que o JIT realmente faz.&lt;/p&gt;
&lt;p&gt;Depois de pesquisar e desistir várias vezes, eu decidi verificar o código fonte do PHP por conta. Alinhando meu pouco conhecimento na linguagem C e toda informação espalhada que encontrei até o momento, eu compilei esta publicação e espero que lhe ajude a entender o JIT melhor também.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ultra simplificando: quando o JIT funciona como esperado, seu código não será executado através da Zend VM e sim diretamente a nível de instruções de CPU.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Essa é a ideia.&lt;/p&gt;
&lt;p&gt;Mas pra entender melhor a gente precisa pensar sobre como o PHP funciona internamente. Não é muito complicado, mas precisa de uma certa introdução ao assunto.&lt;/p&gt;
&lt;p&gt;Eu escrevi um post com uma &lt;a href=&quot;/como-php-funciona/&quot;&gt;visão ampla sobre como o php funciona&lt;/a&gt; . Se você perceber que este post aqui está ficando denso demais, verifique este outro e volta aqui mais tarde. As coisas farão sentido mais facilmente.&lt;/p&gt;
&lt;h2&gt;Como um código PHP é executado?&lt;/h2&gt;
&lt;p&gt;Sabemos que o php é uma linguagem interpretada. Mas o que isso realmente quer dizer?&lt;/p&gt;
&lt;p&gt;Sempre que você quiser executar um código PHP, sendo este um snippet ou uma aplicação web inteira, você precisará passar por um interpretador php. Os mais comumente utilizados são o PHP FPM e o interpretador de linha de comando.&lt;/p&gt;
&lt;p&gt;O trabalho destes interpretadores é bem direto: receber um código php, interpretar este código e cuspir o resultado.&lt;/p&gt;
&lt;p&gt;Isto normalmente acontece em toda linguagem interpretada. Algumas podem remover alguns passos, mas a ideia geral é a mesma. No PHP funciona assim:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;O código PHP é lido e transformado em uma série de palavras chave conhecidas como Tokens. Este processo permite que o interpretador possa entender que parte de código está escrito em qual parte do programa. &lt;strong&gt;Este primeiro passo é chamado de Lexing ou Tokenizing.&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Com os tokens em mãos, o interpretador PHP analisa esta coleção de tokens e tenta tomar algum sentido deles. Como resultado uma Árvore de Sintaxe Abstrata (Abstract Syntax Tree, ou AST) é gerada através de um processo chamado &lt;strong&gt;parsing&lt;/strong&gt;. Esta AST é uma série de nós (ou nodos) indicando quais operações deverão ser executadas. Por exemplo, &quot;echo 1 + 1&quot; deveria de fato significar &quot;apresente o resultado de 1 + 1&quot; ou de forma mais realista &quot;apresente uma operação, a operação é 1 + 1&quot;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Em posse do AST fica muito mais fácil entender as operações e suas precedências. Transformar esta árvore em algo que possa ser executado requer uma representação intermediária (Intermediate Representation, IR) que em PHP chamamos de Opcode. O processo de transformar a AST em Opcodes é chamada de &lt;strong&gt;compilação&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Agora, com os Opcodes em mãos vem a parte massa: &lt;strong&gt;execução&lt;/strong&gt; do código! O PHP tem um motor chamado Zend VM, que é capaz de receber uma lista de Opcodes e executá-la. Após executar todos os Opcodes, a Zend VM encerra a execução e o programa é terminado.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Eu montei um diagrama de fluxo pra tentar deixar um pouco mais claro pra ti:&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/8/zendvm-no-opcache.png&quot; alt=&quot;PHP code is transformed into tokens, parsed into an Abstract Syntax Tree and compiled into opcodes. Only after all these steps, code is executed by the virtual machine.&quot; width=&quot;311&quot; height=&quot;441&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Uma visão simplificada sobre como o PHP é interpretado.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure&gt;&lt;a href=&quot;https://thephp.website/assets/images/posts/10-php-8-jit/zendvm-no-opcache.png&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;Diretão, como tu pode reparar. Mas tem um gargalo aqui: pra quê fazer o lexing e parsing do código a cada vez que formos executar um script se o próprio código PHP não muda com frequência?&lt;/p&gt;
&lt;p&gt;No fim das contas a gente só se importa com os Opcodes, certo? Certo! E é por isso que a &lt;strong&gt;extensão Opcache&lt;/strong&gt; existe.&lt;/p&gt;
&lt;h2&gt;A extensão Opcache&lt;/h2&gt;
&lt;p&gt;A extensão Opcache é compilada com o PHP e normalmente não há motivos pra desativá-la. Se você usa PHP, você provavelmente deveria mantê-la ativa.&lt;/p&gt;
&lt;p&gt;O que essa extensão faz é adicionar uma camada de cache em memória para os Opcodes. Sua função é pegar os Opcodes recém gerados através da AST e jogá-los num cache para que as próximas execuções possam facilmente pular as fases de Lexing e Parsing.&lt;/p&gt;
&lt;p&gt;Aqui vai outro diagrama, desta vez considerando a extensão Opcache:&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/8/zendvm-opcache.png&quot; alt=&quot;Com a adição do OpCache, o processo de compilar o código PHP em Abstract Syntax Tree e depois em OpCodes pode ser pulado completamente caso já tenha acontecido uma vez.&quot; width=&quot;423&quot; height=&quot;551&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Fluxo de interpretação do PHP com Opcache. Se um arquivo já foi interpretado, o php busca o Opcode em cache em vez de realizar o parsing novamente.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Lindo ver como ele pula os passos de Lexing, Parsing e Compiling 😍.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nota:&lt;/strong&gt; aqui é justamente onde &lt;a href=&quot;https://wiki.php.net/rfc/preload&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;a função de preloading do PHP 7.4&lt;/a&gt; brilha! Ela permite que você diga ao PHP FPM pra fazer o parsing do seu código fonte, transformá-lo em Opcodes e jogar no cache antes mesmo de executar qualquer código seu.&lt;/p&gt;
&lt;p&gt;Você deve estar se perguntando onde o JIT entra nessa história, né?! Bom, espero que sim, é o motivo de eu ter gastado tanto tempo nesse texto no fim das contas...&lt;/p&gt;
&lt;h2&gt;O que o Just In Time compiler faz efetivamente?&lt;/h2&gt;
&lt;p&gt;Após escutar a explicação do Zeev no &lt;a href=&quot;https://phpinternals.news/7&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;episódio PHP and JIT do PHP Internals News&lt;/a&gt; eu consegui ter alguma ideia sobre o que o JIT deveria fazer...&lt;/p&gt;
&lt;p&gt;Se o Opcache faz com que a obtenção de Opcodes seja mais rápida para que possam ir direto para a Zend VM, o JIT faz com que eles executem sem Zend VM nenhuma.&lt;/p&gt;
&lt;p&gt;A Zend VM é um programa escrito em C que age como uma camada entre Opcodes e a CPU. &lt;strong&gt;O que o JIT faz é gerar código compilado em tempo de execução para que o php possa pular a Zend VM e executar diretamente na CPU.&lt;/strong&gt; Teóricamente a gente deveria ganhar em performance com isso.&lt;/p&gt;
&lt;p&gt;Isto me soou estranho num primeiro momento, porque pra compilar código de máquina é preciso escrever uma implementação beeem específica para cada tipo de arquitetura. Mas na realidade é bem plausível.&lt;/p&gt;
&lt;p&gt;A implementação do JIT em PHP usa uma biblioteca chamada &lt;a href=&quot;https://luajit.org/dynasm.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;DynASM (Dynamic Assembler)&lt;/a&gt;, que mapeia uma série de instruções de CPU de um formato específico em código assembly para vários tipos diferentes de CPU. Então o Just In Time compiler transforma Opcodes em código de máquina específico da arquitetura da CPU usando DynASM.&lt;/p&gt;
&lt;p&gt;Mas tem uma coisa me deixou encafifado por um tempão...&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Se o preloading é capaz de transformar PHP em Opcode antes de executar qualquer coisa e o DynASM pode compilar Opcodes em código de máquina (compilação Just In Time), por quê raios a gente não compila PHP em código de máquina usando a clássica Ahead of Time compilation?!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Uma das pistas que eu tive ao escutar o episódio do Zeev é que o PHP é fracamente tipado e, portanto, o PHP com frequência não sabe qual o tipo de uma certa variável até que a Zend VM tente executar um Opcode nela.&lt;/p&gt;
&lt;p&gt;Isto pode ser percebido ao olhar para o &lt;a href=&quot;https://github.com/php/php-src/blob/43443857b74503246ee4ca25859b302ed0ebc078/Zend/zend_types.h#L282-L300&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;union type zend_value&lt;/a&gt; , que possui vários ponteiros de diferentes representações para uma variável. Sempre que a Zend VM tenta obter um valor de um zend_value, ela utiliza macros como a &lt;a href=&quot;https://github.com/php/php-src/blob/43443857b74503246ee4ca25859b302ed0ebc078/Zend/zend_types.h#L794&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;ZSTR_VAL&lt;/a&gt; que tenta acessar o ponteiro de string através do union zend_value.&lt;/p&gt;
&lt;p&gt;Por exemplo, &lt;a href=&quot;https://github.com/php/php-src/blob/43443857b74503246ee4ca25859b302ed0ebc078/Zend/zend_vm_def.h#L722-L767&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;este handler da Zend VM&lt;/a&gt; deveria tratar uma expressão de &quot;Menor ou Igual&quot; (&amp;lt;=). Repare bem em como existe uma porrada de if conditions pra tentar adivinhar os tipos dos operandos.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Duplicar esta lógica de inferência de tipos com código de máquina não é uma tarefa trivial e potencialmente tornaria a execução mais lenta.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Compilar tudo depois de entender os tipos também não é a melhor opção, porque compilar algo para código de máquina requer muita CPU. Então compilar TUDO em tempo de execução também é ruim.&lt;/p&gt;
&lt;h2&gt;Como o Just In Time compiler se comporta?&lt;/h2&gt;
&lt;p&gt;Agora sabemos que não podemos inferir tipos para gerar uma compilação Ahead of Time boa o suficiente. Também sabemos que compilar em tempo de execução é custoso. Como pode então o JIT ser benéfico para o PHP?&lt;/p&gt;
&lt;p&gt;Para balancear esta equação, o JIT tenta compilar apenas alguns Opcodes que ele considera que o esforço valerá a pena. Para tal, &lt;strong&gt;o JIT faz um profiling dos Opcodes executados pela Zend VM e verifica quais fazem sentido ou não compilar. (baseado em suas configurações)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Quando determinado Opcode é compilado, ele então delega a execução a este código compilado em vez de delegar para a Zend VM. Se parece com o seguinte:&lt;/p&gt;
&lt;figure class=&quot;post__image post__image--center&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/media/posts/8/zendvm-opcache-jit.png&quot; alt=&quot;Com JIT habilitado, PHP é capaz de compilar alguns OpCodes para código de máquina em tempo de execução, pulando a máquina virtual.&quot; width=&quot;491&quot; height=&quot;541&quot;&gt;
&lt;figcaption contenteditable=&quot;true&quot;&gt;Fluxo de interpretação do PHP com JIT. Se compilado, Opcodes não executam através da Zend VM.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Então na extensão Opcache existem algumas instruções tentando detectar se determinados Opcodes deveriam ser compilados ou não. Caso sim, o compilador então transforma este Opcode em código de máquina utilizando DynASM e executa este código de máquina recém gerado.&lt;/p&gt;
&lt;p&gt;A coisa interessante nisso tudo é que existe um limite em megabytes para o código compilado nesta implementação (também configurável), e a execução de código deve ser capaz de alternar entre JIT e código interpretado sem diferença alguma.&lt;/p&gt;
&lt;p&gt;A propósito, &lt;a href=&quot;https://afup.org/talks/3015-php-8-et-just-in-time-compilation&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;esta palestra do Benoit Jacquemont sobre JIT no PHP&lt;/a&gt; me ajudou demais a entender essa coisa toda.&lt;/p&gt;
&lt;p&gt;Eu ainda não tenho muita certeza sobre quando a compilação efetivamente acontece, mas penso que por agora eu não quero saber, não.&lt;/p&gt;
&lt;h2&gt;Então provavelmente os ganhos em performance não serão enormes&lt;/h2&gt;
&lt;p&gt;Eu espero que agora esteja um tanto mais claro o motivo de todo mundo dizer que a maioria das aplicações PHP não receberem grandes melhorias em performance usando o Just In Time compiler. E o o motivo de o Zeev ter recomendado fazer experimentações com diferentes configurações de JIT em suas aplicações PHP.&lt;/p&gt;
&lt;p&gt;Os Opcodes compilados serão normalmente compartilhados entre várias requests se você estiver utilizando o PHP FPM, mas isto ainda não é grande coisa.&lt;/p&gt;
&lt;p&gt;O motivo é que o JIT otimiza operações de CPU, e a maior parte das aplicações PHP hoje em dia são mais focadas em operações de E/S (I/O) do que qualquer coisa. Não importa se o processamento das operações for compilado se você precisar acessar disco ou rede de qualquer forma. Os tempos de execução serão bem similares.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A não ser que...&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Você esteja fazendo algo que não envolve E/S, como processamento de imagens ou machine learning. Qualquer coisa que não toque I/O irá se beneficiar do Just In Time compiler.&lt;/p&gt;
&lt;p&gt;Esta também é a razão de algumas pessoas citarem que agora estamos mais próximos de poder escrever funções PHP nativas, escritas em PHP em vez de C. O peso adicional não será custoso se estas funções forem compiladas.&lt;/p&gt;
&lt;p&gt;Tempos interessantes para ser um(a) programador(a) PHP...&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Eu espero que este artigo lhe tenha sido útil e que você tenha conseguido entender melhor o que o JIT do PHP 8 faz.&lt;/p&gt;
&lt;p&gt;Sinta-se convidado(a) a me escrever no twitter se você gostaria de adicionar alguma coisa que eu possa ter esquecido e não se esqueça de compartilhar com seus(uas) coleguinhas programadores(as), isto com total certeza irá adicionar muito valor à conversa de vocês!&lt;/p&gt;</content:encoded><category>php</category></item><item><title>Set up rápido do PHP, PHPUnit e Docker</title><link>https://codamos.com.br/php-docker-setup/</link><guid isPermaLink="true">https://codamos.com.br/php-docker-setup/</guid><description>Neste texto eu vou lhe mostrar alguns snippets do meu setup básico pra iniciar aplicações PHP. Meu maior objetivo aqui é que você marque este post nos seus favoritos para que possa voltar, copiar e co</description><pubDate>Mon, 17 Feb 2020 10:40:00 GMT</pubDate><content:encoded>&lt;p&gt;Neste texto eu vou lhe mostrar alguns snippets do meu setup básico pra iniciar aplicações PHP.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Meu maior objetivo aqui é que você marque este post nos seus favoritos&lt;/strong&gt; para que possa voltar, copiar e colar as coisas daqui sempre que precisar criar ou alterar suas aplicações php. 😉&lt;/p&gt;
&lt;p&gt;A coisa legal de usar este setup é que você pode facilmente trocar as versões das imagens sem precisar configurar um montante de coisas de uma vez.&lt;/p&gt;
&lt;p&gt;Então...&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Antes de começar:&lt;/strong&gt; tenha certeza de que você possui &lt;code&gt;docker&lt;/code&gt; e &lt;code&gt;docker-compose&lt;/code&gt; instalados.&lt;/p&gt;
&lt;h2&gt;O resultado final&lt;/h2&gt;
&lt;p&gt;Se você seguir este tutorial, será capaz de executar diferentes serviços através do comando &lt;code&gt;docker-compose&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Você encontra o resultado final &lt;a href=&quot;https://github.com/nawarian/The-PHP-Website/tree/master/code/7-phpunit-docker-compose&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;no repositório público&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A maior ideia é que cada serviço pode ou não se tornar um comando. E o formato se parece com o seguinte:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ docker-compose run &amp;lt;comando&amp;gt; [--args]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Rodar uma suíte de testes, por exemplo, poderia se parecer com isso:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ docker-compose run tests
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pra tornar a digitação mais simples, podemos também adicionar um alias para o comando &lt;code&gt;docker-compose run&lt;/code&gt;. Vou chamar de &lt;code&gt;dcr&lt;/code&gt; aqui:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ alias dcr=&apos;docker-compose run&apos;
$ dcr lol
ERROR: Can&apos;t find a suitable
configuration file in this
directory or any parent.
Are you in the right directory?

Supported filenames:
docker-compose.yml,
docker-compose.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Alias criado! O programa ainda vai reclamar porque não existe um arquivo docker-compose ainda. Bora criar então!&lt;/p&gt;
&lt;h2&gt;Um docker-compose básico&lt;/h2&gt;
&lt;p&gt;Então a gente vai criar um projeto do zero, huh? Bora lá! Comece &lt;strong&gt;criando a pastsa do projeto&lt;/strong&gt; e mais tarde &lt;strong&gt;criando o arquivo docker-compose.yml&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ mkdir meu-projeto
$ cd meu-projeto
$ touch docker-compose.yml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Eu vou criar as pastas comuns que normalmente minhas aplicações têm. Vai incluir pastas como source, testes e binários.&lt;/p&gt;
&lt;p&gt;Apenas execute o seguinte:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ mkdir -p src/ tests/ bin/ \
  .conf/nginx/ var/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Agora podemos começar a trabalhar com o nosso &lt;code&gt;docker-compose.yml&lt;/code&gt;. Ele deverá conter todas dependências que o nosso projeto teria.&lt;/p&gt;
&lt;p&gt;O conteúdo inicial no nosso docker-compose será bem simples. Apenas escreva o seguinte:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# docker-compose.yml
version: &apos;3&apos;
services:
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A gente vai escrever os serviços já agora! O mais essencial de todos, como deveria ser, é o composer.&lt;/p&gt;
&lt;h2&gt;Adicionando composer no docker-compose&lt;/h2&gt;
&lt;p&gt;Provavelmente usaremos o php de dentro do container. Então &lt;strong&gt;não faz sentido rodar o composer fora de um container&lt;/strong&gt;, já que as versões do php podem divergir.&lt;/p&gt;
&lt;p&gt;Vamos então adicionar um serviço &lt;code&gt;composer&lt;/code&gt; ao nosso arquivo:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# docker-compose.yml
version: &apos;3&apos;
services:
  composer:
    image: composer:1.9.3
    environment:
      - COMPOSER_CACHE_DIR=/app/var/cache/composer
    volumes:
      - .:/app
    restart: &quot;no&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;O snippet acima vai criar um serviço &lt;code&gt;composer&lt;/code&gt;, que mapeia o diretório atual para &lt;code&gt;/app&lt;/code&gt; dentro do container.&lt;/p&gt;
&lt;p&gt;Definir a variável de ambiente COMPOSER_CACHE_DIR com o valor &lt;code&gt;/app/var/cache/composer&lt;/code&gt; fará com que o composer escreva o cache na máquina local em vez de somente dentro do container. Isto irá previnir que o composer baixe todas dependências a cada execução.&lt;/p&gt;
&lt;p&gt;Então é bom tomar conta de que a pasta &lt;code&gt;var/&lt;/code&gt; nunca vá parar no seu GIT, hein!&lt;/p&gt;
&lt;p&gt;Só pra não esquecermos, vamos ignorar os arquivos relacionados ao composer já agora. Apenas rode os seguintes comandos pra evitar commitar esses caras:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ echo &apos;vendor/&apos; &amp;gt;&amp;gt; .gitignore
$ echo &apos;var/&apos; &amp;gt;&amp;gt; .gitignore
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Perfeito! Agora com o composer em mãos nós estamos preparados para instalar a dependência mais importante de todo proejto!&lt;/p&gt;
&lt;h2&gt;Preparando o PHPUnit&lt;/h2&gt;
&lt;p&gt;A dependência mais importante deste skeleton app é o motor de testes, é claro!&lt;/p&gt;
&lt;p&gt;Vamos instalar o phpunit a partir do nosso serviço &lt;code&gt;composer&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ dcr composer require --dev \
  phpunit/phpunit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Não precisa adicionar a barra invertida. Eu só coloquei alí para que fique legível em telas pequenas 😬&lt;/p&gt;
&lt;p&gt;As dependência devem estar sendo baixadas, e os arquivos &lt;code&gt;composer.json&lt;/code&gt; e &lt;code&gt;composer.lock&lt;/code&gt; devem ter aparecido no seu diretório local. Ah, e tem uma pasta &lt;code&gt;vendor/&lt;/code&gt; também.&lt;/p&gt;
&lt;p&gt;Parece que rolou...&lt;/p&gt;
&lt;p&gt;Bora então cirar um serviço php simplão pra rodar coisa de cli. A gente vai usar a imagem oficial do php para cli pra isso. E quanto mais chique melhor, vamo fazer com o php 7.4! 🔥&lt;/p&gt;
&lt;h2&gt;Preparando uma cli PHP&lt;/h2&gt;
&lt;p&gt;Vamos usar a imagem &lt;code&gt;php:7.4-cli&lt;/code&gt; pra isso.&lt;/p&gt;
&lt;p&gt;Vamos também mapear os volumes da mesma forma que fizemos com o composer. Pode ser útil no futuro.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# docker-compose.yml
version: &apos;3&apos;
services:
  composer:
    image: composer:1.9.3
    environment:
      - COMPOSER_CACHE_DIR=/app/.cache/composer
    volumes:
      - .:/app
    restart: &quot;no&quot;
  # NOVO AQUI
  php:
    image: php:7.4-cli
    restart: &quot;no&quot;
    volumes:
      - .:/app
    working_dir: /app
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Aqui a gente também colocou o working dir com o valor &lt;code&gt;/app&lt;/code&gt;. Então sempre que rodarmos &lt;code&gt;dcr php&lt;/code&gt; ele irá executar como se &lt;code&gt;/app&lt;/code&gt; fosse o caminho inicial de execução.&lt;/p&gt;
&lt;p&gt;Tá pensando como vamos rodar os testes, certo?&lt;/p&gt;
&lt;p&gt;Siligaaqui!&lt;/p&gt;
&lt;h2&gt;Rodando PHPUnit dentro do container&lt;/h2&gt;
&lt;p&gt;Rodar PHPUnit deveria ser tão simples quanto rodar um comando de cli. Já que ele é um comando de cli...&lt;/p&gt;
&lt;p&gt;O seguinte, portanto, funciona bem:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ dcr php vendor/bin/phpunit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Você pode usar &amp;lt;TAB&amp;gt; para auto completar normalmente 😉&lt;/p&gt;
&lt;p&gt;Parece bem chatão escrever tudo isso aí cada vez mais. Dá pra simplificar?&lt;/p&gt;
&lt;p&gt;Sim!&lt;/p&gt;
&lt;p&gt;Vamos adicionar um serviço &lt;code&gt;phpunit&lt;/code&gt; para o nosso &lt;code&gt;docker-compose.yml&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# docker-compose.yml
version: &apos;3&apos;
services:
  composer:
    image: composer:1.9.3
    environment:
      - COMPOSER_CACHE_DIR=/app/.cache/composer
    volumes:
      - .:/app
    restart: &quot;no&quot;
  php:
    image: php:7.4-cli
    restart: &quot;no&quot;
    volumes:
      - .:/app
    working_dir: /app
  # NOVO AQUI
  phpunit:
    image: php:7.4-cli
    restart: &quot;no&quot;
    volumes:
      - .:/app
    working_dir: /app
    entrypoint: vendor/bin/phpunit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;O truque aqui tá no &lt;code&gt;entrypoint&lt;/code&gt;! Agora em seu terminal você pode executar o seguinte:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ dcr phpunit --version
PHPUnit 9.0.1 by Sebastian
Bergmann and contributors.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Aooo! Que lindeza!&lt;/p&gt;
&lt;p&gt;A gente, aliás, gerar o nosso &lt;code&gt;phpunit.xml&lt;/code&gt; antes de pular pro próximo passo.&lt;/p&gt;
&lt;p&gt;Assim ó:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ dcr phpunit \
  --generate-configuration
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Esse comando vai te perguntar algumas coisas. Apenas pressione enter pra tudo e tá de boa...&lt;/p&gt;
&lt;h2&gt;Criando um teste simples&lt;/h2&gt;
&lt;p&gt;Só pra ter certeza de que as coisas tão rodando né.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ touch tests/MyTest.php
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;E dentro de &lt;code&gt;tests/MyTest.php&lt;/code&gt; adicione o seguinte:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;# tests/MyTest.php
&amp;lt;?php

declare(strict_types=1);

use PHPUnit\Framework\TestCase;

class MyTest extends TestCase
{
  public function testMyTest(): void
  {
    self::assertTrue(false);
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Funciona perfeitamente! E o teste também está falhando... Tu pode consertar depois, relaxe!&lt;/p&gt;
&lt;p&gt;Agora que conseguimos rodar os nossos testes, podemos pensar em construir a aplicação em si.&lt;/p&gt;
&lt;p&gt;Provavelmente você quer criar uma aplicação web, sim? Então vamos fazer algo com o nginx e php-fpm!!&lt;/p&gt;
&lt;h2&gt;Configurando o Web Server&lt;/h2&gt;
&lt;p&gt;Para configurar o php fpm, precisaremos de dois serviços diferentes. Um será o servidor HTTP e o outro será a instância FPM.&lt;/p&gt;
&lt;p&gt;Como estes são processos de longa execução, a gente não vai usar o &lt;code&gt;docker-compose run&lt;/code&gt; com eles. Em vez disso, usemos o &lt;code&gt;up -d&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;O comando final vai parecer com o seguinte:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ docker-compose up -d fpm nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Vamos adicionar o PHP-FPM na bagaça:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# docker-compose.yml
version: &apos;3&apos;
services:
  composer:
    image: composer:1.9.3
    environment:
      - COMPOSER_CACHE_DIR=/app/.cache/composer
    volumes:
      - .:/app
    restart: &quot;no&quot;
  php:
    image: php:7.4-cli
    restart: &quot;no&quot;
    volumes:
      - .:/app
    working_dir: /app
  phpunit:
    image: php:7.4-cli
    restart: &quot;no&quot;
    volumes:
      - .:/app
    working_dir: /app
    entrypoint: vendor/bin/phpunit
  # NOVO AQUI
  fpm:
    image: php:7.4-fpm
    restart: always
    volumes:
      - .:/app

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Simplasso! Ao rodar &lt;code&gt;docker-compose up -d fpm&lt;/code&gt; ele deveria rodar e ficar no background já.&lt;/p&gt;
&lt;p&gt;Agora vamos configurar a parte do nginx que vai expor a porta &lt;code&gt;8080&lt;/code&gt; e tratar as requests ao php envinando para a porta &lt;code&gt;9000&lt;/code&gt; do fpm.&lt;/p&gt;
&lt;p&gt;O arquivo docker-compose.yml vai ficar assim:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# docker-compose.yml
version: &apos;3&apos;
services:
  composer:
    image: composer:1.9.3
    environment:
      - COMPOSER_CACHE_DIR=/app/.cache/composer
    volumes:
      - .:/app
    restart: &quot;no&quot;
  php:
    image: php:7.4-cli
    restart: &quot;no&quot;
    volumes:
      - .:/app
    working_dir: /app
  phpunit:
    image: php:7.4-cli
    restart: &quot;no&quot;
    volumes:
      - .:/app
    working_dir: /app
    entrypoint: vendor/bin/phpunit
  fpm:
    image: php:7.4-fpm
    restart: always
    volumes:
      - .:/app
  # NOVO AQUI
  nginx:
    image: nginx:1.17.8-alpine
    ports:
      - 8080:80
    volumes:
      - .:/app
      - ./var/log/nginx:/var/log/nginx
      - .conf/nginx/site.conf:/etc/nginx/conf.d/default.conf

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Com isto nós expomos a porta &lt;code&gt;8080&lt;/code&gt; como sendo a porta &lt;code&gt;80&lt;/code&gt; do container (porta padrão do http).&lt;/p&gt;
&lt;p&gt;Também ligamos o nosso diretório atual para &lt;code&gt;/app&lt;/code&gt;. Normalmente as pessoas fazem &lt;code&gt;/var/www&lt;/code&gt;, mas eu gosto de deixar as coisas consistentes em comparação com os outros serviços.&lt;/p&gt;
&lt;p&gt;O diretório local &lt;code&gt;var/log/nginx&lt;/code&gt; foi conectado ao &lt;code&gt;/var/log/nginx&lt;/code&gt; do container. Desta forma a gente não fica cego quando precisar checar os logs de acesso ou erros.&lt;/p&gt;
&lt;p&gt;Por último, mas não menos importante, o &lt;code&gt;site.conf&lt;/code&gt; foi introduzido ao container com o nome &lt;code&gt;default.conf&lt;/code&gt;. Esta é só uma maneira rápida de fazer com que o nginx aceite a nossa configuração.&lt;/p&gt;
&lt;p&gt;A gente precisa criar o nosso arquivo de configuração. Façamos então!&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ touch .conf/nginx/site.conf
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Escreva o seguinte arquivo de configuração no caminho &lt;code&gt;.conf/nginx/site.conf&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-conf&quot;&gt;# .conf/nginx/site.conf
server {
  listen 80;
  listen [::]:80;

  root /app/public;
  index index.php;

  location / {
      try_files $uri $uri/ /index.php$is_args$args;
  }

  location ~ \.php$ {
      try_files $uri =404;
      fastcgi_split_path_info ^(.+.php)(/.+)$;
      fastcgi_pass fpm:9000;
      fastcgi_index index.php;
      include fastcgi_params;
      fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
      fastcgi_param PATH_INFO $fastcgi_path_info;
  }

  access_log /var/log/nginx/myapp_access.log;
  error_log /var/log/nginx/myapp_error.log;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Repare como &lt;code&gt;root&lt;/code&gt; está apontando para &lt;code&gt;/app/public&lt;/code&gt;. Isto fará com que a pasta &lt;code&gt;public/&lt;/code&gt; seja o ponto de início para toda requisição que o nginx gerenciar.&lt;/p&gt;
&lt;p&gt;Repare também no &lt;code&gt;fastcgi_pass&lt;/code&gt; e veja que está apontando para &lt;code&gt;fpm:9000&lt;/code&gt;. &lt;strong&gt;Esta é a nossa imagem fpm. Se você a deu um nome diferente, ajuste essa linha aqui também!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Pra testar isso tudo, vamos criar um simples &lt;code&gt;index.php&lt;/code&gt; dentro da pasta &lt;code&gt;/public&lt;/code&gt;. Este arquivo vai servir como o ponto de partida da nossa aplicação.&lt;/p&gt;
&lt;p&gt;Apenas adicione uma chamada ao phpinfo neste arquivo:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;# public/index.php
&amp;lt;?php

phpinfo();

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Agora vamos levantar o servidor nginx:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ docker-compose up -d nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A partir deste momento você poderá acessar http://localhost:8080/ a partir do seu navegador normalmente.&lt;/p&gt;
&lt;h2&gt;Não esqueça o autoloader&lt;/h2&gt;
&lt;p&gt;Nós instalamos o composer corretamente, mas usar as nossas classes ainda não está perfeito.&lt;/p&gt;
&lt;p&gt;Vamos ajustar o nosso composer.json para que o composer possa saber de onde carregar nossas classes:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;# composer.json
{
  &quot;require-dev&quot;: {
    &quot;phpunit/phpunit&quot;: &quot;^9.0&quot;
  },
  &quot;autoload&quot;: {
    &quot;psr-4&quot;: {
      &quot;ThePHPWebsite\\&quot;: &quot;src/&quot;
    }
  }
}

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Agora rode um composer dump:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ dcr composer -- dump
Generated autoload files
containing 646 classes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Este &lt;code&gt;--&lt;/code&gt; antes do comando apenas faz com que o &lt;code&gt;docker-compose&lt;/code&gt; não pense que &lt;code&gt;dump&lt;/code&gt; é um serviço em vez de parâmetro ao nosso comando do composer.&lt;/p&gt;
&lt;p&gt;Pra testar este pedacinho, criemos um arquivo chamado &lt;code&gt;App.php&lt;/code&gt; dentro de &lt;code&gt;src/&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;# src/App.php
&amp;lt;?php

declare(strict_types=1);

namespace ThePHPWebsite;

class App
{
  public function sayHello(): void
  {
    echo &apos;Hello!&apos;;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;E agora apenas modifique o arquivo &lt;code&gt;public/index.php&lt;/code&gt; para usar a nossa classe:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

require_once __DIR__
  . &apos;/../vendor/autoload.php&apos;;

use ThePHPWebsite\App;

$app = new App();

$app-&amp;gt;sayHello();

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Recarregue a página no navegador e XABLAU! &quot;Hello!&quot; tá lá, chapa!&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Buum! Isso é tudo! Um guia massa de como montar um ambiente local de desenvolvimento pra aplicações php usando docker compose e podendo rodar testes com o phpunit.&lt;/p&gt;
&lt;p&gt;Você provavelmente gostará também de adicionar outros serviços como bancos de dados, servidores de filas, um servidor Solr...&lt;/p&gt;
&lt;p&gt;Vai na fé e adiciona eles aí, agora tu não precisa mais bagunçar seu ambiente todo pra mexer com diferentes serviços.&lt;/p&gt;
&lt;p&gt;Se em algum momento você entender que precisa de alguma coisa MUITO específica, como uma extensão do php ou coisa do gênero, basta criar um Dockerfile customizado e referenciá-lo no docker-compose.yml.&lt;/p&gt;
&lt;p&gt;Não se esqueça de compartilhar com seus(uas) amigos(as) preguiçosos(as) sempre que começarem a reclamar do processo de criar um projeto base com PHP.&lt;/p&gt;
&lt;p&gt;E também sinta-se livre pra me dar um alô se você teve algum problema durante este tutorial.&lt;/p&gt;
&lt;p&gt;Valeus!&lt;/p&gt;</content:encoded><category>php</category></item><item><title>TDL: aprendizado guiado por testes</title><link>https://codamos.com.br/tdl-aprendizado-por-testes/</link><guid isPermaLink="true">https://codamos.com.br/tdl-aprendizado-por-testes/</guid><description>TL;DR TDL = Test-Driven Learning OU Aprendizado Guiado por Testes. Se você pudesse levar uma única coisa deste texto contigo, leva isso aqui: Desenvolvimento guiado por testes pode ser utilizado para </description><pubDate>Sat, 01 Feb 2020 10:39:00 GMT</pubDate><content:encoded>&lt;h2&gt;TL;DR&lt;/h2&gt;
&lt;p&gt;TDL = Test-Driven Learning OU Aprendizado Guiado por Testes.&lt;/p&gt;
&lt;p&gt;Se você pudesse levar uma única coisa deste texto contigo, leva isso aqui: &lt;strong&gt;Desenvolvimento guiado por testes pode ser utilizado para aprender também.&lt;/strong&gt; &lt;a href=&quot;/tdd-php-exemplos/&quot;&gt;Aprenda como fazer TDD de forma eficiente&lt;/a&gt; e você entenderá rapidinho o conceito deste texto inteiro.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Recentemente eu iniciei (novamente) a missão mais divertida que nós programadores(as) enfrentamos de tempos em tempos: &lt;strong&gt;✨ aprender uma nova linguagem de programação ✨.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Desta vez eu decidi aprender &lt;a href=&quot;https://www.rust-lang.org/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Rust&lt;/a&gt;, que pra mim (ainda) é insanamente interessante, já que sou um desenvolvedor web e nunca precisei encostar em nada relacionado a baixo nível que não fosse o código fonte do PHP.&lt;/p&gt;
&lt;p&gt;Depois de passar por este processo várias vezes, eu comecei a ver alguns padrões no meu processo de aprendizado. Foi preciso uma boa mistura de auto conhecimento, habilidades de gerenciamento de projetos (sim) e pesquisa pra compilar estes padrões num modelo que eu poderia facilmente integrar no meu dia a dia.&lt;/p&gt;
&lt;p&gt;Eu acredito que desta vez, aprendendo Rust, eu alcancei uma versão mais ou menos estável deste framework de aprendizado baseado no TDL. Mesmo que otimizar este framework tenha de ser um processo em constante evolução.&lt;/p&gt;
&lt;p&gt;Pra ser muito claro, &lt;strong&gt;eu não quero dizer que esta é a melhor forma de aprender uma nova linguagem de programação ou coisa do tipo.&lt;/strong&gt; Você vai precisar aprender por si mesmo qual formato funciona melhor pra ti.&lt;/p&gt;
&lt;p&gt;Como sempre, vamos parar com a enrolação e começar!&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Cada seção aqui começa com uma lista de tópicos para que você possa saber as principais ideias antes de ler algo. Sinta-se livre pra pular para o próximo subtítulo se os tópicos não chamarem sua atenção.&lt;/p&gt;
&lt;p&gt;Este texto está dividido em três partes e, honestamente, daria pra escrever um livro se eu fosse desenvolver meus pensamentos em cada uma delas. (&lt;a href=&quot;https://twitter.com/intent/tweet?text=Escreve+o+livro,+@nawarian,+macho,+v%C3%A9i!+-+https://thephp.website&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Me dá um alô no twitter se você quiser ver este livro virar realidade xD&lt;/a&gt;)&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&quot;&lt;strong&gt;Iniciando com uma nova linguagem de programação&lt;/strong&gt;&quot; apresenta um modelo mental sobre como descobrir uma nova linguagem de programação e como adquirir a mais fundamental ferramenta de aprendizado com TDL: testes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&quot;&lt;strong&gt;Como funciona o Aprendizado Guiado por Testes?&lt;/strong&gt;&quot; tenta explicar como esse arcabouço funciona, como manter o feedback loop e por aí vai.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Por último, mas não menos importante, vem &quot;&lt;strong&gt;Praxis: a parte mais difícil é a descoberta&lt;/strong&gt;&quot;, que traz algumas dicas de como alimentar o primeiro passo do loop do TDL.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Iniciando com uma nova linguagem de programação&lt;/h2&gt;
&lt;p&gt;Tópicos nesta seção:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;As linguagens de programação são semelhantes&lt;/li&gt;
&lt;li&gt;Toda linguagem tem um propósito&lt;/li&gt;
&lt;li&gt;Encontrando os pontos altos da linguagem&lt;/li&gt;
&lt;li&gt;Como testar nesta linguagem&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Se você já sabe qual linguagem de programação quer aprender, o processo de inicialização é razoavelmente simples. Mas eu tenho um conselho bem estranho pra você:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Não escreva código algum até você ter um modelo mental claro sobre o que esta linguagem é capaz de fazer.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Para construir este modelo mental é sempre bom lembrar que linguagens de programação são muito semelhantes entre si e normalmente conseguem fazer alguma(s) coisa(s) muito bem (são especializadas).&lt;/p&gt;
&lt;h3&gt;As linguagens de programação são semelhantes&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;A maioria das linguagens de programação são semelhantes entre si.&lt;/strong&gt; Elas podem até ter diferentes estruturas, sintaxe, convenções mas no fim das contas a maioria delas vai te prover uma execução baseada em pilha, onde você &lt;strong&gt;guarda variáveis, carrega valores nelas, executa expressões, chama funções e por aí vai.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Imperativa ou declarativa, compilada ou interpretada, &lt;strong&gt;todas elas compartilham características comuns.&lt;/strong&gt; Quanto mais cedo você entender estas características, mais próximo de ser apenas uma questão de sintaxe elas vão te parecer.&lt;/p&gt;
&lt;p&gt;Além da sintaxe você encontrará modelos que são profundamente ligados à linguagem. Normalmente eles começam a aparecer quando você começa a aprender o problema que determinada linguagem resolve.&lt;/p&gt;
&lt;p&gt;Então &lt;strong&gt;não comece a codar ainda!&lt;/strong&gt; Antes de escrever qualquer linha de código, tenha certeza de que você olhou bem para a linguagem, sabe que cara tem e quais coisas tornam esta linguagem única e útil.&lt;/p&gt;
&lt;p&gt;Normalmente &lt;strong&gt;uma linguagem se destaca das outras por ter um propósito.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;Toda linguagem tem um propósito&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;/como-php-funciona/&quot;&gt;PHP era um monte de scripts CGI pra fazer templates&lt;/a&gt;, o JavaScript nasceu para tornar páginas web interativas, ActionScript foi para fazer o mesmo com Flash, C para abstrair com alta performance em desenvolvimento de sistemas, Rust para fazer o mesmo que C com segurança em mente, Ruby para escrever código como escrevemos livros, e a IR da LLVM para tornar mais fácil criar novas linguagens de programação...&lt;/p&gt;
&lt;p&gt;Toda linguagem de programação tem (ou teve) um propósito quando foi escrita pela primeira vez.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Saber o propósito de uma linguagem lhe ajuda a entender como ela funciona.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Quando você entende o propósito da linguagem, as melhores funcionalidades desta linguagem começam a aparecer pra ti naturalmente.&lt;/p&gt;
&lt;h3&gt;Encontrando os pontos altos da linguagem&lt;/h3&gt;
&lt;p&gt;Vamos tomar Rust como exemplo aqui, já que é minha memória mais recente.&lt;/p&gt;
&lt;p&gt;Eu entendi que Rust é uma linguagem de desenvolvimento de sistemas, com alto foco em segurança no gerenciamento de memória sem perder em performance. Mas como isso tudo se traduz na linguagem?&lt;/p&gt;
&lt;p&gt;Aarre! O compilador reclama de tudo, as variáveis têm ciclo de vida e ownership, tem uma parada de emprestar variáveis, tipos de dado que nunca ficam nulos, eu já falei do compilador?&lt;/p&gt;
&lt;p&gt;Saber tais coisas vai te ensinar do que tu pode se orgulhar em saber quando souber, mas também vai te dar uma clara visão de onde você precisa chegar.&lt;/p&gt;
&lt;p&gt;Isso também vai fazer com que outras pessoas acreditem que você está realmente aprendendo esta linguagem. Não tem nada mais frustrante que receber um &quot;por que?&quot; sem conseguir responder de maneira satisfatória.&lt;/p&gt;
&lt;h3&gt;Como testar nesta linguagem&lt;/h3&gt;
&lt;p&gt;Ainda &lt;strong&gt;antes de codar qualquer coisa&lt;/strong&gt; nessa linguagem, o último passo para construir este modelo mental é aprender como escrever testes.&lt;/p&gt;
&lt;p&gt;Sim! Mesmo antes de aprender como declarar uma variável, aprenda como testar. Ou melhor dizendo, &lt;strong&gt;aprenda como fazer asserções&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;PHP e C, por exemplo, possuem a função &lt;code&gt;assert()&lt;/code&gt;. Rust tem as macros &lt;code&gt;assert_*&lt;/code&gt; e uma ferramenta integrada de testes.&lt;/p&gt;
&lt;p&gt;Aprenda o que está disponível para fazer testes: tem alguma forma de escrever testes unitários? De integração? Consigo usar uma linguagem de testes como o Gherkin com ela?&lt;/p&gt;
&lt;p&gt;Eu vou usar um programa em rust como exemplo aqui em como escrever uma asserção essencial para que a gente possa iniciar nosso loop com TDL:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;// src/main.rs

#[test]
fn test_basics() {
  assert_eq!(1, 1); // 1 = 1
  assert!(true); // sucesso
  assert!(false); // falha
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Depois eu só executo &lt;code&gt;$ cargo test&lt;/code&gt; e PRONTINHO! Eu sei o básico em como escrever asserções nessa linguagem nova. Hora de começar a aprender!&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Como funciona o Aprendizado Guiado por Testes?&lt;/h2&gt;
&lt;p&gt;Tópicos nessa seção:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Introdução com exemplos de código&lt;/li&gt;
&lt;li&gt;Descoberta&lt;/li&gt;
&lt;li&gt;Asserção&lt;/li&gt;
&lt;li&gt;Aprendizado&lt;/li&gt;
&lt;li&gt;Repetição&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pode ser que você pense que eu tô tentando criar moda ou algo do gênero. Mas &lt;a href=&quot;https://digitalcommons.calpoly.edu/csse_fac/88/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Aprendizado Guiado por Testes é real total de verdadinha&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;É importante notar que TDL nesta pesquisa acima é apenas uma ferramenta de ensino. O que eu estou apresentando aqui é como eu uso esta ferramenta num framework que eu construí e adoto.&lt;/p&gt;
&lt;p&gt;Eu baseio meu aprendizado com TDL em três passos repetíveis: &lt;strong&gt;descoberta, asserção e aprendizado&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Ferramentas como Khan Academy, Vim Adventures e outros MOOCs também usam métodos semelhantes a este: apresentar algo novo (descoberta), dar feedback em suas falhas (asserção) e premiar seus acertos (aprendizado).&lt;/p&gt;
&lt;p&gt;A ideia é primeiro &lt;strong&gt;descobrir&lt;/strong&gt; algo que você quer ou precisa aprender, realizar &lt;strong&gt;asserções&lt;/strong&gt; para entender quando você terá aprendido. Fazer as asserções funcionarem com o que você &lt;strong&gt;aprendeu&lt;/strong&gt; ou precisa aprender.&lt;/p&gt;
&lt;p&gt;Vamos tomar um exemplo bem tosquinho com rust. Eu descobri que posso definir variáveis. Como isto funciona? Vamos fazer uma asserção de que a variável &lt;code&gt;nawarian&lt;/code&gt; deveria conter o valor 10.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;// src/main.rs

#[test]
fn test_variables() {
  assert_eq!(10, nawarian);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Eu sei agora que eu só vou tentar descobrir novas coisas quando esta asserção passar. Eu vou continuar brigando com meu teclado até que &lt;code&gt;cargo test&lt;/code&gt; fique verde!!&lt;/p&gt;
&lt;p&gt;Um pouco de pesquisa aqui e acolá, e o seguinte parece funcionar:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;// src/main.rs

#[test]
fn test_variables() {
  let nawarian = 10;

  assert_eq!(10, nawarian);
} 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Os testes estão verdes. Eu poderia continuar com coisas novas ou brincar mais um pouco com este aqui. Em vez de definir &lt;code&gt;nawarian = 10&lt;/code&gt; eu poderia fazer isso com um loop e contador, não?&lt;/p&gt;
&lt;p&gt;Então como será que eu posso fazer um loop de 0 a 10 e incrementar &lt;strong&gt;nawarian&lt;/strong&gt; a cada iteração?&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;// src/main.rs

#[test]
fn test_variables() {
  let nawarian = 0;
  for i in 0..10 {
    nawarian += 1;
  }

  assert_eq!(10, nawarian);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Agora o &lt;code&gt;cargo test&lt;/code&gt; ficou loucão e começou a reclamar de uma par de coisas:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;warning:&lt;/strong&gt; unused variable: &lt;code&gt;i&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;help:&lt;/strong&gt; consider prefixing with an underscore: &lt;code&gt;_i&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;error[E0384]:&lt;/strong&gt; cannot assign twice to immutable variable &lt;code&gt;nawarian&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;help:&lt;/strong&gt; make this binding mutable: &lt;code&gt;mut nawarian&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Não tá funcionando... o compilador diz que &lt;code&gt;nawarian&lt;/code&gt; não é mutável e tá implicando até que &lt;code&gt;i&lt;/code&gt; nunca é utilizada, que eu deveria prefixar essa variável com &lt;code&gt;_&lt;/code&gt; pra que ninguém ligue pra ela.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Eu:&lt;/strong&gt; Diabé!? Aparentemente variáveis são imutáveis por padrão em Rust. Interessante... Dá pra fazer ela ficar mutável usando a palavra chave &lt;code&gt;mut&lt;/code&gt;...&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Escreve, roda. FUNCIONOU!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Essa estrutura é difudê porque você entende exatamente onde está pisando.&lt;/strong&gt; E quando não entender, é mais fácil pesquisar um problema pequenino e específico que você esteja enfrentando no momento.&lt;/p&gt;
&lt;p&gt;Este feedback loop vai te forçar a &lt;strong&gt;aprender ativamente&lt;/strong&gt; em vez de passivamente: encontre uma funcionalidade, teste, encontre a resposta até ficar satisfeito(a). Descubra, afirme, aprenda.&lt;/p&gt;
&lt;p&gt;Outra coisa maravilhosa é que testes passando deixam as pessoas felizes. Ver o quanto você consegue &lt;a href=&quot;/livro-refactoring-martin-fowler/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;refatorar um código&lt;/a&gt; sem quebrar traz um sentimento muuuito bom!&lt;/p&gt;
&lt;p&gt;Eu não quero dizer que você deveria, mas com essa asserção simples, você pode aprender desde variáveis até threading. Um passo de cada vez, mantenha os testes passando e alimente seu feedback loop!&lt;/p&gt;
&lt;p&gt;Eu vou tentar te dar um pouco mais de informação em como lidar com cada passo enquanto utiliza o TDL:&lt;/p&gt;
&lt;h3&gt;Descoberta&lt;/h3&gt;
&lt;p&gt;O passo da descoberta é muito bom para aprender sobre sintaxe, funcionalidades da linguagem, frameworks... Basicamente tudo o que possa captar seu interesse se encaixa aqui.&lt;/p&gt;
&lt;p&gt;Mas sempre mantenha suas asserções simples. &lt;strong&gt;É extremamente importante que você entenda seus testes&lt;/strong&gt; muito mais que a implementação em si. Os testes precisam ser claros, o código você pode sempre refatorar.&lt;/p&gt;
&lt;h3&gt;Asserção&lt;/h3&gt;
&lt;p&gt;O passo da asserção pode ser um tanto diferente dependendo do nível que você já tenha alcançado na linguagem.&lt;/p&gt;
&lt;p&gt;Novatos (como eu em Rust) devem escrever teste unitários o máximo possível, usando ferramentas nativas da linguagem como &lt;code&gt;assert&lt;/code&gt;, &lt;code&gt;echo&lt;/code&gt; ou mesmo &lt;code&gt;exit&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Quanto mais você avança, testes grandes e complexos usando &quot;Given, When, Then&quot; podem funcionar melhor. Você precisará aprender como utilizar ferramentas como Gherkin ou algo tão amplo e descritivo quanto em sua linguagem.&lt;/p&gt;
&lt;h3&gt;Aprendizado&lt;/h3&gt;
&lt;p&gt;Faça com que seus testes passem!&lt;/p&gt;
&lt;p&gt;Leia os erros que aparecem pra ti, entenda o problema e assim que o fizer: leia o manual da linguagem, procure em mecanismos diferentes, pergunte a amigos ou quem puder saber mais.&lt;/p&gt;
&lt;h3&gt;Repetição&lt;/h3&gt;
&lt;p&gt;Volte ao passo da descoberta e encontre algo novo para fazer novas asserções e aprender.&lt;/p&gt;
&lt;p&gt;Ou apenas seja criativo(a). Aquele simples &lt;code&gt;nawarian = 10&lt;/code&gt; pode ser transformado em operações de E/S, utilização de structs, chamadas FFI, threads...&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Não existe código que você não possa tornar mais complicado! 😉&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Praxis: a parte mais difícil é a descoberta&lt;/h2&gt;
&lt;p&gt;Tópicos nesta seção:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Introdução sobre comunidade e ferramentas&lt;/li&gt;
&lt;li&gt;Se envolva com a linguagem&lt;/li&gt;
&lt;li&gt;Conecte-se com a comunidade&lt;/li&gt;
&lt;li&gt;Explique algo que você ainda não sabe&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A teoria parece ótima, né? (talvez nem mesmo pareça...)&lt;/p&gt;
&lt;p&gt;Mas eu sei o quão difícil é no começo entender e tomar proveito deste framework. Pra mim a parte mais difícil é alimentar este feedback loop com mais descobertas.&lt;/p&gt;
&lt;p&gt;Felizmente a melhor resposta que eu encontrei até o momento para a maioria das linguagens/frameworks é: Comunidade!&lt;/p&gt;
&lt;p&gt;Rust, por exemplo, tem este projeto maravilhoso chamado &quot;&lt;a href=&quot;https://github.com/rust-lang/rustlings&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;rustlings&lt;/a&gt;&quot;. Ele te guia através de testes escritos pela comunidade e te desafia a fazer com que os códigos compilem (o compilador é realmente chato), que os testes passem...&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.phpschool.io/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;No php tem o PHP School&lt;/a&gt; que é bem semelhante ao rustlings, mas é altamente extensível e tem muitos cursos feitos pela comunidade sobre modulos/funcionalidades específicas.&lt;/p&gt;
&lt;p&gt;Mas depois de aprender a sintaxe você precisará de muito mais. Você precisará ver em quê e como a linguagem está evoluindo.&lt;/p&gt;
&lt;h3&gt;Se envolva com a linguagem&lt;/h3&gt;
&lt;p&gt;Aqui é o momento de assistir palestras, ir a conferências e assistir pessoas codando por horas na frente das câmeras...&lt;/p&gt;
&lt;p&gt;Comece a contribuir com projetos de código aberto também! Esta é uma forma bem simples de ganhar proficiência na linguagem: contribua, falhe nos code reviews e conserte seus erros baseado no feedback de outras pessoas...&lt;/p&gt;
&lt;h3&gt;Conecte-se com a comunidade&lt;/h3&gt;
&lt;p&gt;Escute também podcasts, leia blogs (ou comece um!), entre em reddits. Você aprenderá mais e mais sobre o que pessoas estão fazendo com esta linguagem, o que é considerado normal e o que não é.&lt;/p&gt;
&lt;p&gt;Encontre grupos de encontro locais, ou crie um você mesmo. Converse com pessoas de verdade, sobre problemas de verdade.&lt;/p&gt;
&lt;h3&gt;Explique algo que você ainda não sabe&lt;/h3&gt;
&lt;p&gt;Navegue pelo stackoverflow, github issues ou forums do reddit para encontrar perguntas que você realmente não sabe responder. Encontre-as, pesquise e responda (ou ao menos tente).&lt;/p&gt;
&lt;p&gt;As vezes você será capaz de explicar somente com assertions, as vezes você precisará de uma visão mais ampla das coisas. Tente os dois!&lt;/p&gt;
&lt;p&gt;Em determinado momento você estará navegando por oportunidades de emprego nesta linguagem e os requisitos estão quase todos preenchidos. Os que não estiverem, você pode utilizar para alimentar seu feedback loop e continuar evoluindo.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Fico feliz que tenha chegado até aqui, porque não tô tentando te enrolar. Meu processo de aprendizado até o momento é bem doloroso mas extremamente útil pra mim.&lt;/p&gt;
&lt;p&gt;Também me salva um bom tempo por me guiar através de perguntas pequenas e respostas que eu precise dar, já que eu não tenho tempo para investir em aprendizado de novas linguagens como eu costumava ter há alguns anos atrás ~ suspiros.&lt;/p&gt;
&lt;p&gt;Eu espero que este texto tenha sido útil pra ti.&lt;/p&gt;
&lt;p&gt;Como sempre, sinta-se livre pra me mandar qualquer feedback através do twitter.&lt;/p&gt;</content:encoded><category>php</category></item><item><title>Testes legíveis com PHP e PHPUnit</title><link>https://codamos.com.br/testes-php-phpunit/</link><guid isPermaLink="true">https://codamos.com.br/testes-php-phpunit/</guid><description>Existem várias ferramentas disponíveis no ecossistema PHP que estão preparadas para oferecer uma ótima experiência com testes. PHPUnit é de longe a mais famosa de todas . É quase um sinônimo de teste </description><pubDate>Tue, 07 Jan 2020 10:36:00 GMT</pubDate><content:encoded>&lt;p&gt;Existem várias ferramentas disponíveis no ecossistema PHP que estão preparadas para oferecer uma ótima experiência com testes. &lt;a href=&quot;https://github.com/sebastianbergmann/phpunit&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;PHPUnit é de longe a mais famosa de todas&lt;/a&gt; . É quase um sinônimo de teste nessa linguagem.&lt;/p&gt;
&lt;p&gt;As boas práticas não são bem compartilhadas na comunidade. Existem tantas opções de quando e por quê escrever testes, quais tipos de testes e por aí vai. Mas na verdade &lt;strong&gt;não faz sentido algum escrever qualquer teste se você não for capaz de lê-los mais tarde&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;Testes são uma forma muito especial de documentação&lt;/h2&gt;
&lt;p&gt;Como eu já mencionei no &lt;a href=&quot;/tdd-php-exemplos/&quot;&gt;post sobre TDD com PHP&lt;/a&gt;, um teste sempre vai (ou pelo menos deveria) tornar claro o que um certo pedaço de código deve atingir como objetivo.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Se um teste não consegue expressar uma ideia, é um teste ruim.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Com isso em mente, eu preparei uma lista com boas práticas que podem auxiliar desenvolvedores(as) php a escrever testes bons, legíveis e úteis.&lt;/p&gt;
&lt;h2&gt;Começando pelo básico&lt;/h2&gt;
&lt;p&gt;Existem algumas práticas que muitas pessoas seguem sem sequer questionar o motivo. Eu vou listar algumas delas e tentar explicar pelo menos por cima qual a razão de tais práticas.&lt;/p&gt;
&lt;h3&gt;Testes não deveriam fazer operações E/S&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Motivo&lt;/strong&gt;: E/S é lento e instável.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lento:&lt;/strong&gt; mesmo com o melhor equipamento na face da terra, E/S ainda será mais lento que acesso a memória. &lt;strong&gt;Testes devem sempre rodar rápido&lt;/strong&gt;, do contrário ninguém irá rodá-los suficientemente.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Instável:&lt;/strong&gt; um certo arquivo, binário, socket, pasta ou entrada DNS pode não estar disponível em todas as máquinas em que seu código será executado. &lt;strong&gt;Quanto mais você depende de E/S em seus testes, mais seus testes ficam amarrados e dependentes de infraestrutura&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Operações consideradas E/S: * Ler/escrever arquivos * Chamadas de rede * Chamadas a processos externos (usando exec, proc_open...)&lt;/p&gt;
&lt;p&gt;Existem casos onde ter E/S fará com que o teste seja escrito mais rapidamente. &lt;strong&gt;Mas se liga&lt;/strong&gt;: fazer com que essas operações funcionem da mesma forma nos ambientes de desenvolvimento, build e deployment pode se tornar uma imensa dor de cabeça.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Isolando testes para que não precisam de E/S:&lt;/strong&gt; abaixo eu mostro uma decisão de design que pode ser tomada para evitar que seus testes realizem operações de E/S &lt;strong&gt;segregando responsabilidades para interfaces&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Segue o exemplo:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;public function getPeople(): array
{
  $rawPeople = file_get_contents(
    &apos;people.json&apos;
  ) ?? &apos;[]&apos;;

  return json_decode(
    $rawPeople,
    true
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No momento em que começarmos a testar este método, seremos forçados a criar um arquivo local pra teste e, de tempos em tempos, manter uma snapshot desse arquivo. Como no seguinte:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;public function testGetPeopleReturnsPeopleList(): void
{
  $people = $this-&amp;gt;peopleService
    -&amp;gt;getPeople();

  // assert it contains people
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pra esse tipo, é necessário &lt;strong&gt;definir pré condições&lt;/strong&gt; para que ele possa passar. Mesmo que pareça fazer sentido a primeira vista, isto é na realidade &lt;strong&gt;terrível&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pular um teste por conta de uma pré condição faltante não garante qualidade de software. Apenas esconde bugs!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Corrigindo:&lt;/strong&gt; basta isolar as operações de E/S ao mover a responsabilidade para uma interface.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;// extrai a lógica
// de buscar algo
// p/ uma interface
// especializada
interface PeopleProvider
{
  public function getPeople(): array;
}

// implementação concreta
class JsonFilePeopleProvider
  implements PeopleProvider
{
  private const PEOPLE_JSON =
    &apos;people.json&apos;;

  public function getPeople(): array
  {
    $rawPeople = file_get_contents(
      self::PEOPLE_JSON
    ) ?? &apos;[]&apos;;

    return json_decode(
      $rawPeople,
      true
    );
  }
}

class PeopleService
{
  // injetar via __construct()
  private PeopleProvider $peopleProvider;

  public function getPeople(): array
  {
    return $this-&amp;gt;peopleProvider
      -&amp;gt;getPeople();
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Tô sabendo, agora &lt;code&gt;JsonFilePeopleProvider&lt;/code&gt; usa E/S de toda forma. Verdade.&lt;/p&gt;
&lt;p&gt;Em vez de &lt;code&gt;file_get_contents()&lt;/code&gt; a gente pode usar um layer de abstração como o &lt;a href=&quot;https://flysystem.thephpleague.com/docs/adapter/local/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Filesystem do Flysystem&lt;/a&gt; que pode ser facilmente mockado.&lt;/p&gt;
&lt;p&gt;E pra quê serve o &lt;code&gt;PeopleService&lt;/code&gt; então? Boa pergunta... Isto é uma das coisas que &lt;strong&gt;testes nos traz: questionar o nosso design, remover código inutil.&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Testes devem ser concisos e ter significado&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Motivo:&lt;/strong&gt; testes são uma forma de documentação. Mantenha-os limpos, curtos e legíveis.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Limpos e curtos&lt;/strong&gt;: sem bagunça, sem escrever mil linhas de mock, sem escrever trocentos asserts no mesmo teste.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Legíveis:&lt;/strong&gt; cada teste deve contar uma história. A estrutura &quot;Given, When, Then&quot; é perfeita pra isso.&lt;/p&gt;
&lt;p&gt;Aqui vão algumas características de um teste bem escrito: * Contém apenas asserts necessários (preferivelmente apenas um) * Lhe conta exatamente o que deveria acontecer dada certa condição * Testa apenas um caminho de execução do método por vez * Não mocka o universo inteiro para fazer algum assert&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Importante notar&lt;/strong&gt; que se a sua implementação possui alguns IFs, switch ou iterações, &lt;strong&gt;todos estes caminhos alternativos devem ser explicitamente testados.&lt;/strong&gt; Então early returns, por exemplo, devem sempre conter testes.&lt;/p&gt;
&lt;p&gt;Novamente: &lt;strong&gt;não importa o coverage, o que importa é documentar.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Deixa eu te mostrar como um teste confuso se parece:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;public function testCanFly(): void
{
  $semAsas = new Person(0);
  $this-&amp;gt;assertEquals(
    false,
    $semAsas-&amp;gt;canFly()
  );

  $umaAsa = new Person(1);
  $this-&amp;gt;assertTrue(
    !$umaAsa-&amp;gt;canFly()
  );

  $duasAsas = new Person(2);
  $this-&amp;gt;assertTrue(
    $duasAsas-&amp;gt;canFly()
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Vamos então adotar o &quot;Given, When, Then&quot; e ver como esse teste muda:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;public function testCanFly(): void
{
  // Given
  $person = $this-&amp;gt;givenAPersonHasNoWings();

  // Then
  $this-&amp;gt;assertEquals(
    false,
    $person-&amp;gt;canFly()
  );

  // Outros casos...
}

private function givenAPersonHasNoWings(): Person
{
  return new Person(0);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Assim como as cláusulas &quot;Given&quot;, os &quot;When&quot;s e &quot;Then&quot;s também podem ser extraídos para métodos privados. Qualquer coisa que faça seu teste ficar mais legível.&lt;/p&gt;
&lt;p&gt;Agora, aquele assertEquals tá bem bagunçado e com pouquíssimo significado. Um humano lendo isso precisa interpretar a assertion pra entender o que deveria significar.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Usar assertions específicas tornam seus testes muito mais legíveis.&lt;/strong&gt; &lt;code&gt;assertTrue()&lt;/code&gt; deveria receber uma variável contendo um booleano, nunca uma expressão como &lt;code&gt;canFly() !== true&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Então do exemplo anterior, vamos substituir o &lt;code&gt;assertEquals&lt;/code&gt; entre &lt;code&gt;false&lt;/code&gt; e &lt;code&gt;$person-&amp;gt;canFly()&lt;/code&gt; com um simples &lt;code&gt;assertFalse&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;// ...
$person = $this-&amp;gt;givenAPersonHasNoWings();

$this-&amp;gt;assertFalse(
  $person-&amp;gt;canFly()
);

// Outros casos...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Limpinho! Dado que uma pessoa não tem asas, ela não deveria poder voar! Dá pra ler como se fosse um poema 😍&lt;/p&gt;
&lt;p&gt;Agora, esse &quot;Outros casos&quot; aparecendo duas vezes no nosso texto já é uma boa pista de que este teste está fazendo muitas assertions. Ao mesmo tempo o nome do método &lt;code&gt;testCanFly()&lt;/code&gt; não significa nada muito útil.&lt;/p&gt;
&lt;p&gt;Vamos tornar o nosso test case um tequinho melhor:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;public function testCanFlyIsFalsyWhenPersonHasNoWings(): void
{
  $person = $this-&amp;gt;givenAPersonHasNoWings();
  $this-&amp;gt;assertFalse(
    $person-&amp;gt;canFly()
  );
}

public function testCanFlyIsTruthyWhenPersonHasTwoWings(): void
{
  $person = $this-&amp;gt;givenAPersonHasTwoWings();
  $this-&amp;gt;assertTrue(
    $person-&amp;gt;canFly()
  );
}

// ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A gente poderia inclusive renomear o teste pra bater com um cenário da vida real como &lt;code&gt;testPersonCantFlyWithoutWings&lt;/code&gt;, mas pra mim o nome já parece bom o suficiente.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Um teste não deve depender de outro&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Motivo:&lt;/strong&gt; um teste deveria ser capaz de rodar e passar em qualquer ordem.&lt;/p&gt;
&lt;p&gt;Até o presente momento, eu não consigo encontrar um bom motivo para acoplar testes.&lt;/p&gt;
&lt;p&gt;Recentemente eu fui perguntado sobre como testar uma feature para usuários logados e eu gostaria de utilizar isto como exemplo aqui.&lt;/p&gt;
&lt;p&gt;O teste faria o seguinte: * Gerar um token JWT * Executar uma certa tarefa logado * Fazer os asserts&lt;/p&gt;
&lt;p&gt;A forma como o teste foi feito era a seguinte:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;public function testGenerateJWTToken(): void
{
  // ... $token
  $this-&amp;gt;token = $token;
}

// @depends  testGenerateJWTToken
public function testExecuteAnAmazingFeature(): void
{
  // Execute using $this-&amp;gt;token
}

// @depends  testExecuteAnAmazingFeature
public function testStateIsBlah(): void
{
  // Busca os resultados
  // interface logada
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Este teste é ruim por alguns motivos: * PHPUnit não garantirá a ordem de execução dos testes * Os testes não podem ser executados de forma independente * Testes rodando em paralelo irão falhar aleatoriamente&lt;/p&gt;
&lt;p&gt;A forma mais simples de resolver este problema que eu consigo pensar, novamente, é com &quot;Given, When, Then&quot;. Desta forma a gente torna os testes mais concisos e conta uma história ao mostrar suas dependências de forma clara que explica a feature em si.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;public function testAmazingFeatureChangesState(): void
{
  // Given
  $token = $this-&amp;gt;givenImAuthenticated();

  // When
  $this-&amp;gt;whenIExecuteMyAmazingFeature(
    $token
  );
  $newState = $this-&amp;gt;pollStateFromInterface(
    $token
  );

  // Then
  $this-&amp;gt;assertEquals(
    &apos;my-state&apos;,
    $newState
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A gente precisaria também escrever testes para autenticar e por aí vai. Esta estrutura é tão massa que o &lt;a href=&quot;https://behat.org/en/latest/quick_start.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Behat a utiliza por padrão&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Sempre injete as dependências&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Motivo:&lt;/strong&gt; mockar estado global é terrível, não ser capaz de mockar as dependências torna impossível testar uma funcionalidade.&lt;/p&gt;
&lt;p&gt;Aqui vai uma lição para a vida: &lt;strong&gt;Esqueça sobre classes estáticas que mantém estado e também instâncias singleton.&lt;/strong&gt; Se a sua classe depende de algo, torne-o injetável.&lt;/p&gt;
&lt;p&gt;Aqui vai um exemplo particularmente triste:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;class FeatureToggle
{
  public function isActive(
    Id $feature
  ): bool {
    $cookieName = $feature-&amp;gt;getCookieName();

    // Early return se o
    // cookie está presente
    if (Cookies::exists(
      $cookieName
    )) {
      return Cookies::get(
        $cookieName
      );
    }

    // Calcular feature toggle...
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Agora. Como você poderia testar este early return?&lt;/p&gt;
&lt;p&gt;Não consegue né, Moisés?&lt;/p&gt;
&lt;p&gt;Pra testar este método, nós precisaríamos entender o comportamento desta classe &lt;code&gt;Cookies&lt;/code&gt; e tomar certeza de que conseguiríamos reproduzir todo o ambiente por trás desta classe para forçar alguns retornos.&lt;/p&gt;
&lt;p&gt;Faz isso não.&lt;/p&gt;
&lt;p&gt;A gente pode consertar essa situação injetando uma instância de &lt;code&gt;Cookies&lt;/code&gt; como dependência. O teste ficaria parecido com o seguinte:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;// Test class...
private Cookies $cookieMock;

private FeatureToggle $service;

// Preparing our service and dependencies
public function setUp(): void
{
  $this-&amp;gt;cookieMock = $this-&amp;gt;prophesize(
    Cookies::class
  );

  $this-&amp;gt;service = new FeatureToggle(
    $this-&amp;gt;cookieMock-&amp;gt;reveal()
  );
}

public function testIsActiveIsOverriddenByCookies(): void
{
  // Given
  $feature = $this-&amp;gt;givenFeatureXExists();

  // When
  $this-&amp;gt;whenCookieOverridesFeatureWithTrue(
    $feature
  );

  // Then
  $this-&amp;gt;assertTrue(
    $this-&amp;gt;service-&amp;gt;isActive($feature)
  );
  // poderíamos também testar que
  // nenhum outro método foi chamado
}

private function givenFeatureXExists(): Id
{
  // ...
  return $feature;
}

private function whenCookieOverridesFeatureWithTrue(
  Id $feature
): void {
  $cookieName = $feature-&amp;gt;getCookieName();
  $this-&amp;gt;cookieMock-&amp;gt;exists($cookieName)
    -&amp;gt;shouldBeCalledOnce()
    -&amp;gt;willReturn(true);

  $this-&amp;gt;cookieMock-&amp;gt;get($cookieName)
    -&amp;gt;shouldBeCalledOnce()
    -&amp;gt;willReturn(true);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;O mesmo acontece com singletons.&lt;/strong&gt; Então se você quer &lt;strong&gt;tornar um objeto único&lt;/strong&gt;, é só &lt;strong&gt;configurar o seu injetor de dependências direito&lt;/strong&gt; em vez de utilizar o Singleton (anti) pattern.&lt;/p&gt;
&lt;p&gt;Do contrário você vai acabar escrevendo métodos como &lt;code&gt;reset()&lt;/code&gt; ou &lt;code&gt;setInstance()&lt;/code&gt;, que só são úteis para classes de teste. Me soa no mínimo estranho.&lt;/p&gt;
&lt;p&gt;Mudar o seu desgin para tornar testes mais simples está tudo bem. &lt;strong&gt;Criar métodos para tornar testes mais simples não está ok.&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Nunca teste métodos protected/private&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Motivo:&lt;/strong&gt; a forma como testamos uma funcionalidade é fazendo assertions em como a sua assinatura se comporta: dada uma condição, quando eu faço X, espero que Y aconteça. &lt;strong&gt;Métodos protected/private não são parte da assinatura de uma funcionalidade.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Eu vou inclusive me recusar a te mostrar uma forma de &quot;testar&quot; métodos privados, mas aqui vai uma dica: você fazer isso com a &lt;a href=&quot;https://www.php.net/manual/en/book.reflection.php&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;reflection API&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Por favor, castigue-se de alguma forma sempre que pensar em utilizar reflections pra testar um método privado!&lt;/p&gt;
&lt;p&gt;Por definição, métodos privados vão somente ser chamados de dentro da classe. Então não são publicamente acessíveis. Isto significa que apenas métodos públicos nesta mesma classe consegue invocar tais métodos privados.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Se você testou todos os métodos públicos, você também deve ter testado os protegidos/privados de uma vez só.&lt;/strong&gt; Se não, pode apagar cada um deles, que ninguém tá usando eles mesmo.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Além do básico: as coisas interessantes&lt;/h2&gt;
&lt;p&gt;Espero que você não tenha ficado entediado(a) até aqui. Básico é básico, mas precisa ser escrito.&lt;/p&gt;
&lt;p&gt;Agora, durante as próximas linhas, vou compartilhar contigo algumas opiniões que carrego sobre testes limpos e cada decisão que impacta meu fluxo de desenvolvimento.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Eu diria que os valores mais importantes que levo em consideração enquanto escrevo testes são os seguintes:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Aprendizado&lt;/li&gt;
&lt;li&gt;Receber feedback rápido&lt;/li&gt;
&lt;li&gt;Documentação&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/livro-refactoring-martin-fowler/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Refatoração&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Design enquanto testo&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cada opinião que exponho abaixo segue ao menos um destes valores e cada uma dá suporte à outra.&lt;/p&gt;
&lt;h3&gt;Teste vem primeiro, não depois&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Valores&lt;/strong&gt;: aprendizado, receber feedback rápido, documentação, refatoração, design enquanto testo.&lt;/p&gt;
&lt;p&gt;Esta é a base de tudo. É tão importante que carrega todos os valores de uma vez só.&lt;/p&gt;
&lt;p&gt;Escrever teste primeiro lhe força entender como o seu &quot;given, when, then&quot; deve ser estruturado. &lt;strong&gt;Você documenta primeiro ao escrever assim&lt;/strong&gt; e, mais importante ainda, &lt;strong&gt;aprende e torna explícito seus requisitos&lt;/strong&gt; como coisas mais relevantes no software.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Te parece estranho escrever um teste antes de escrever algo?&lt;/strong&gt; Imagine o quão embaraçoso é implementar algo e, enquanto testa, descobrir que todos os &quot;given, when, then&quot; não têm sentido algum.&lt;/p&gt;
&lt;p&gt;Testar primeiro também te permite rodar os testes contra as expectativas a cada 2 segundos. &lt;strong&gt;Você recebe feedback de suas mudanças da forma mais rápida possível. Não importa o quão grande ou pequena a feature possa parecer.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Testes que estão passando indicam as melhores áreas para refatorar no sistema.&lt;/strong&gt; Em algum momento eu provavelmente escreverei sobre refatoração, mas a coisa é: sem teste, sem refatoração. Porque refatorar sem testes é simplesmente arriscado demais.&lt;/p&gt;
&lt;p&gt;E por último, mas não menos importante, ao definir o seu &quot;given, when, then&quot; fica claro quais interfaces seus métodos devem ter e como elas devem se comportar. &lt;strong&gt;Manter este teste limpo também irá lhe forçar a tomar diferentes decisões de design.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Irá lhe forçar a criar factories, interfaces, quebrar heranças e por aí vai. E, sim, para tornar o teste mais simples!&lt;/p&gt;
&lt;p&gt;Se seus testes são um documento vivo que pretende explicar como o software funciona, &lt;strong&gt;é extremamente importante que eles expliquem de forma clara.&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Não ter testes é melhor que ter testes mal feitos&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Valores&lt;/strong&gt;: aprendizado, documentação, refatoração.&lt;/p&gt;
&lt;p&gt;Muitos(as) desenvolvedores(as) escrevem teste da seguinte forma: escreve a funcionalidade, soca o framework de teste até cobrir um certo tanto de linhas e enviam pra produção.&lt;/p&gt;
&lt;p&gt;O que eu gostaria que fosse levado em consideração com mais frequência, porém, é quando o(a) próximo(a) desenvolvedor(a) visita esta funcionalidade. &lt;strong&gt;O que os testes estão realmente contando a esta pessoa...&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Normalmente testes cujo nome não dizem muita coisa, são testes mal escritos. O que é mais claro pra ti: &lt;code&gt;testCanFly&lt;/code&gt; ou &lt;code&gt;testCanFlyReturnsFalseWhenPersonHasNoWings&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;Sempre que seu teste não representar nada além de bagunça e códigos forçando ao framework aumentar o coverage com exemplos que não parecem fazer qualquer sentido, é hora de parar e pensar se vale a pena escrever este teste.&lt;/p&gt;
&lt;p&gt;Até mesmo coisas bestas como nomear uma variável como &lt;code&gt;$a&lt;/code&gt; e &lt;code&gt;$b&lt;/code&gt;, ou dar nomes que não se relacionam com o caso de uso.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lembre-se:&lt;/strong&gt; testes são um documento vivo, tentando explicar como o software deveria se comportar. &lt;code&gt;assertFalse($a-&amp;gt;canFly())&lt;/code&gt; não documenta muita coisa. Já &lt;code&gt;assertFalse($personWithNoWingos-&amp;gt;canFly())&lt;/code&gt; documenta.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Rode seus testes compulsivamente&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Valores&lt;/strong&gt;: aprendizado, receber feedback rápido, refatoração.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Antes de iniciar qualquer funcionalidade: rode os testes.&lt;/strong&gt; Se os testes estiverem quebrados antes de você tocar qualquer coisa, você saberá &lt;em&gt;antes&lt;/em&gt; de escrever qualquer código e não irá gastar preciosos minutos depurando testes quebrados que você nem tinha conhecimento sobre.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Após salvar um arquivo: rode os testes.&lt;/strong&gt; O quanto antes você souber que quebrou algo, mais cedo saberá como corrigir o problema e continuar. Se interromper seu fluxo de trabalho para corrigir um problema te parece improdutivo, imagina só voltar vários passos atrás pra corrigir um problema que você não fazia ideia ter causado.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Depois de trocar uma ideia com o(a) colega ou verificar suas notificações do github: rode os testes.&lt;/strong&gt; Se o teste estiver vermelho, você sabe onde parou. Se estiverem verdes, você sabe que pode continuar.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Antes de refatorar algo, até mesmo nomes de variáveis: rode os testes.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Sério mesmo, rode os testes. É de graça. Rode os testes com a mesma frequência em que salva seus arquivos.&lt;/p&gt;
&lt;p&gt;Na real, o &lt;a href=&quot;https://github.com/spatie/phpunit-watcher&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;PHPUnit Watcher&lt;/a&gt; resolve exatamente esse problema pra gente e até envia notificação quando os testes rodam.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Grandes testes, grandes responsabilidades&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Valores&lt;/strong&gt;: aprendizado, refatoração, design enquanto testo.&lt;/p&gt;
&lt;p&gt;Seria ideal que cada classe teria ao menos um caso de teste pra si. E também que cada método público fosse coberto com testes. E cada fluxo alternativo (if/switch/try-catch/exception)...&lt;/p&gt;
&lt;p&gt;Contemos mais ou menos assim:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1 classe = 1 caso de teste&lt;/li&gt;
&lt;li&gt;1 método = 1 ou mais testes&lt;/li&gt;
&lt;li&gt;1 fluxo alternativo (if/switch/try-catch/exception) = 1 teste&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Então um código simples como o abaixo deveria ter 4 testes diferentes:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;// class Person
public function eatSlice(Pizza $pizza): void
{
  // testar exception
  if ([] === $pizza-&amp;gt;slices()) {
    throw new LogicException(&apos;...&apos;);
  }

  // testar exception
  if (true === $this-&amp;gt;isFull()) {
    throw new LogicException(&apos;...&apos;);
  }

  // testar caminho padrão (slices = 1)
  $slices = 1;
  // testar caminho alternativo (slices = 2)
  if (true === $this-&amp;gt;isVeryHungry()) {
    $slices = 2;
  }

  $pizza-&amp;gt;removeSlices($slices);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Quanto mais métodos públicos, mais testes.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;E ninguém gosta de ler documentos longos. Como seu caso de teste também é um documento, deixá-lo pequeno e conciso irá aumentar a sua qualidade e utilidade.&lt;/p&gt;
&lt;p&gt;Isto também é um grande sinal de que sua classe está acumulando responsabilidades e pode ser hora de botar o chapéu de refatoração pra remover funcionalidades, mover para classes diferentes ou repensar parte do seu design.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Mantenha uma suite de regressão&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Valores&lt;/strong&gt;: aprendizado, documentação, receber feedback rápido.&lt;/p&gt;
&lt;p&gt;Se liga nessa função:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;function findById(string $id): object
{
  return fromDb((int) $id);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Você esperou alguém passar &lt;code&gt;&quot;10&quot;&lt;/code&gt; mas, em vez disso, foi passado &lt;code&gt;&quot;10 bananas&quot;&lt;/code&gt;. Ambas formas acham o valor, mas uma não deveria. Você tem um bug.&lt;/p&gt;
&lt;p&gt;A primeira coisa a fazer? Escrever um teste que descreva que este comportamento está errado!!&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;public function testFindByIdAcceptsOnlyNumericIds(): void
{
  $this-&amp;gt;expectException(InvalidArgumentException::class);
  $this-&amp;gt;expectExceptionMessage(
    &apos;Only numeric IDs are allowed.&apos;
  );

  findById(&quot;10 bananas&quot;);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Testes não estão passando, é claro. Mas agora você sabe o que fazer para fazê-los passar. Remova o bug, faça o teste passar, joga no master, dá aquele deploy e vai ser feliz!&lt;/p&gt;
&lt;p&gt;Mantenha este teste ali, pra sempre. Se possível, numa suite de testes especializada em regressão e conecte este teste com uma issue.&lt;/p&gt;
&lt;p&gt;E prontinho! Feedback rápido enquanto corrige bugs, documentação feita, código a prova de regressões e felicidade.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Notas finais e bora trocar ideia&lt;/h2&gt;
&lt;p&gt;Ufa, falei um monte ein... E é claro que a maioria das coisas aqui são opiniões minhas que desenvolvi conforme fui evoluindo na carreira. Não estão certas ou erradas, são apenas opiniões.&lt;/p&gt;
&lt;p&gt;Este post continuará crescendo conforme eu veja que alguns tópicos importantes ficaram de fora.&lt;/p&gt;
&lt;p&gt;Sinta-se sempre livre pra comentar e enviar dúvidas direto no meu twitter ou pelo repositório do projeto no Github.&lt;/p&gt;</content:encoded><category>php</category></item><item><title>Generators além do xrange</title><link>https://codamos.com.br/generators-php/</link><guid isPermaLink="true">https://codamos.com.br/generators-php/</guid><description>TL;DR Generators são muito mais do que apenas usar yield em variáveis pra evitar a utilização de arrays (como na função xrange). Eles nos proveem com o poder do async, coroutines e várias magias 🧙! S</description><pubDate>Wed, 11 Dec 2019 10:34:00 GMT</pubDate><content:encoded>&lt;h2&gt;TL;DR&lt;/h2&gt;
&lt;p&gt;Generators são muito mais do que apenas usar yield em variáveis pra evitar a utilização de arrays (como na função xrange). Eles nos proveem com o poder do async, coroutines e várias magias 🧙!&lt;/p&gt;
&lt;p&gt;Se você busca uma explicação mais exaustiva, dá uma sacada &lt;a href=&quot;https://nikic.github.io/2012/12/22/Cooperative-multitasking-using-coroutines-in-PHP.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;nesse artigo de 2012 do nikic&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;O que são Generators e o que eles fazem?&lt;/h2&gt;
&lt;p&gt;Comecemos pela &lt;a href=&quot;https://www.php.net/manual/en/language.generators.overview.php&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;documentação oficial&lt;/a&gt;. Encontraremos várias pistas a partir dela!&lt;/p&gt;
&lt;p&gt;Generators são uma feature do php desde a versão 5.5 da linguagem, como você pode ver na &lt;a href=&quot;https://wiki.php.net/rfc/generators&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;RFC sobre generators&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A principal ideia dos Generators é prover uma forma &lt;strong&gt;simplificada de escrever iterators&lt;/strong&gt; sem ter de implementar a interface Iterator. Generators também nos permite &lt;strong&gt;interromper o fluxo de execução do código&lt;/strong&gt;, o que é bem massa!&lt;/p&gt;
&lt;p&gt;A forma como ele funciona é utilizando a palavra-chave &lt;code&gt;yield&lt;/code&gt; dentro de uma função. Ao fazer isso, o &lt;strong&gt;tipo de retorno&lt;/strong&gt; da sua função &lt;strong&gt;automaticamente se transformará em &lt;a href=&quot;https://www.php.net/manual/en/class.generator.php&quot;&gt;&lt;code&gt;\Generator&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Então se liga!&lt;/strong&gt; O código abaixo &lt;em&gt;quebra&lt;/em&gt; porque força um tipo de retorno, mas a utilização de Generators retorna algo diferente:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;// String como tipo de retorno, quebrará
function myGeneratorFunction(): string
{
  yield &apos;Generators&apos;; // Transforma o tipo de retorno em \Generator

  // Fatal Error: tipo de retorno é \Generator, estamos retornando string
  return &apos;The PHP Website&apos;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Por nos permitir interromper a execução do código, isto naturalmente nos permite gerenciar melhor a memória em nossos programas php. Tem um script famoso que ilustra este caso:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;// range comum
foreach (range(1, 10000) as $n) {
  echo $n . PHP_EOL;
}

// range baseado em Generators
function xrange(int $from, int $to) {
  for ($i = $from; $i &amp;lt;= $to; $i++) {
    yield $i;
  }
}

foreach (xrange(1, 10000) as $n) {
  echo $n . PHP_EOL;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A diferença? Alerta de super simplificação: &lt;code&gt;range()&lt;/code&gt; alocou memória para 10.000 integers, enquanto &lt;code&gt;xrange()&lt;/code&gt; alocou memória para apenas um.&lt;/p&gt;
&lt;p&gt;Você provavelmente já sabia isso desde 2012, claro. Mas vamos resumir aqui rapidex e partir pra parte divertida do texto!&lt;/p&gt;
&lt;h3&gt;O que PHP Generators fazem?&lt;/h3&gt;
&lt;p&gt;Generators nos permitem &lt;strong&gt;criar iterators facilmente&lt;/strong&gt; sem precisar implementar a interface Iterator e permitem &lt;strong&gt;interrupção de código&lt;/strong&gt; para melhor gerenciamento de memória ou qualquer tipo de maluquice que você queira construir.&lt;/p&gt;
&lt;p&gt;Abaixo eu mostro um exemplo simples de generator e comento alguns termos. Se você em algum momento ler alguma palavra-chave que não faça muito sentido, volta aqui e lê esse exemplo.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;// Generator function
function xrange(): \Generator {
  // Contexto/corpo/escopo do Generator
  while (true) {
    yield 1;
  }
}

$xrange = xrange();
$xrange-&amp;gt;next(); // Puxa o próximo yield
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;O que você possivelmente não sabe sobre Generators...&lt;/h2&gt;
&lt;p&gt;Uma feature maravilhosa dos Generators que normalmente deixam passar batido é a capacidade de &lt;strong&gt;enviar valores de volta para a Generator function&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Basicamente quando você dá um &lt;code&gt;yield&lt;/code&gt; dentro da generator function, o código pára de executar lá e volta para o contexto de quem invocou o generator. De lá é possível enviar valores de volta para dentro da generator function.&lt;/p&gt;
&lt;p&gt;Isso cria uma série de oportunidades para criar ferramentas incríveis que negociam o flow de processamento para você. Incluindo &lt;strong&gt;coroutines&lt;/strong&gt;, &lt;strong&gt;programação assíncrona&lt;/strong&gt; e &lt;strong&gt;otimização de coleta de dados&lt;/strong&gt;. Tu vai curtir essa ultima, segue a linha!&lt;/p&gt;
&lt;h3&gt;Como enviar valores de volta para a generator function?&lt;/h3&gt;
&lt;p&gt;Na verdade é bem simples. Um objeto do tipo Generator implementa todos os métodos de Iterator e alguns a mais. Um deles é o método &lt;a href=&quot;https://www.php.net/manual/en/generator.send.php&quot;&gt;&lt;code&gt;Generator::send()&lt;/code&gt;&lt;/a&gt;, que é utilizado para enviar valores para dentro da generator function.&lt;/p&gt;
&lt;p&gt;Funciona da seguinte maneira: 1. Alguém invoca a generator function 1. A generator function dá yield em algo, interrompendo a execução e voltando para quem a invocou 1. O método &lt;code&gt;send()&lt;/code&gt; do objeto generator é invocado, que passa um valor como resultado do &lt;code&gt;yield&lt;/code&gt; dentro da generator function 1. A generator function continua executando com o valor passado&lt;/p&gt;
&lt;p&gt;Tá confuso né? Olha esse código:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;function meuGenerator(): Generator
{
  // 2. joga o valor 10 para quem chama a função
  $vinte = yield 10;

  // 4. Continua a execução com o novo valor
  var_dump($vinte);
}

$gen = meuGenerator();
// 1. Inicia a execução
$dez = $gen-&amp;gt;current();

// 3. Joga de volta o valor para o generator function
$gen-&amp;gt;send($dez * 2);

// Saída: int(20)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Isso é meio que tudo o que tu precisaria saber sobre Generators.&lt;/strong&gt; Quer dizer, você também pode lançar exceptions de fora da generator function usando o método &lt;code&gt;Generator::throw()&lt;/code&gt;. Mas isso é meio que tudo mesmo...&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mas é claro que tem mais coisa pra ver!&lt;/strong&gt; Você não esperava vir aqui com conteúdo que encontraria facilmente noutro canto, né?&lt;/p&gt;
&lt;p&gt;Lendo o post do nikic (o de 2012 que eu citei acima) você pode extrair informações muito mais profundas sobre o que pode ser feito com Generators no php. Vai lá, leia quantas vezes julgar necessário até absorver a ideia.&lt;/p&gt;
&lt;p&gt;Isso tudo é teoria e é bem massa. Mas tem algumas &lt;strong&gt;implementações reais de Generators que podem mudar a sua vida&lt;/strong&gt; ou pelo menos te fazer considerar um paradigma diferente.&lt;/p&gt;
&lt;h2&gt;Para que são utilizados Generators?&lt;/h2&gt;
&lt;p&gt;Eu gostaria de lhe apresentar &lt;strong&gt;duas aplicações maneiras de Generators com PHP&lt;/strong&gt;. Uma é open source e tu pode começar a utilizar desde já. A outra é mais um conceito e tu precisaria desenvolver algo pra si.&lt;/p&gt;
&lt;h3&gt;Desenvolvimento assíncrono: como o framework Amp funciona&lt;/h3&gt;
&lt;p&gt;Eu sei, você provavelmente já ouviu falar do framework Amp e como ele pode te ajudar a desenvolver código assíncrono no PHP.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mas eu tô aqui pra te tirar da camada de usuário.&lt;/strong&gt; Eu quero que tu pense sobre como esse treco foi implementado e tenha ao menos uma visão superficial em como ele funciona e o quão dependente de Generators este framework é.&lt;/p&gt;
&lt;p&gt;Considere o seguinte exemplo incompleto:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;Amp\Loop::run(function () {
  $socket = yield connect(
    &apos;localhost:443&apos;
  );

  // object(EncryptableSocket)
  var_dump($socket);
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Sééé loco, tanta coisa rolando aqui...&lt;/p&gt;
&lt;p&gt;Comecemos com a ideia de que &lt;code&gt;Amp\Loop::run()&lt;/code&gt; cria um Event Loop. Se você não sabe o que um event loop faz, dá uma paradinha aqui e vai buscar ler um pouco sobre isso. Tu vai encontrar coisas sobre React PHP e Node.JS.&lt;/p&gt;
&lt;p&gt;Na verdade, tenta aprender um teco como o React PHP funciona e como ele enfileira tarefas e faz polling para operações de E/S (I/O), lhe permitindo fazer programação assíncrona com PHP.&lt;/p&gt;
&lt;p&gt;A coisa é que esse Event Loop do Amp é muito especial porque &lt;strong&gt;ele não é só um event loop&lt;/strong&gt;. Ele também monitora &lt;code&gt;yield&lt;/code&gt;, portanto ele &lt;strong&gt;espera que a sua função de callback seja uma generator function&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;Daí além de fazer o enfileiramento e monitorar E/S pra manter a thread desocupada, ele também trata valores que você der yield.&lt;/p&gt;
&lt;p&gt;Ao equipar-se com &lt;a href=&quot;https://github.com/reactphp/promise&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;React Promises&lt;/a&gt; &lt;strong&gt;ele te permite emular a funcionalidade async/await no PHP&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Mas como?&lt;/p&gt;
&lt;p&gt;Se você der uma olhadinha mais de perto na &lt;a href=&quot;https://github.com/amphp/socket/blob/d49dc0d7936f65fd41068482da801768266d0c1a/src/functions.php#L63&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;implementação da função connect&lt;/a&gt; notará que ela retorna uma Promise que quando resolvida irá retornar um objeto &lt;code&gt;EncryptableSocket&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Então &lt;code&gt;connect(&apos;localhost:443&apos;);&lt;/code&gt; na verdade retorna uma Promise. Como pode &lt;code&gt;$socket&lt;/code&gt; conter &lt;code&gt;EncryptableSocket&lt;/code&gt; então?&lt;/p&gt;
&lt;p&gt;No momento em que nós fazemos &lt;code&gt;yield&lt;/code&gt; em uma Promise dentro deste Event Loop, Amp irá aguardar esta promise resolver para então devolver o valor (em caso de fulfil) ou lançar exceção (em caso de reject).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Namoral, num é massa isso não!? Digaí!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Significa que você deveria escrever suas aplicações dessa maneira de agora em diante? Talvez, talvez não...&lt;/p&gt;
&lt;p&gt;Apesar de ser tão massa que não precisemos esperar o async/await chegar no core da linguagem, esse modelo parece um tanto invasivo pra quem gosta de tipificar tudo.&lt;/p&gt;
&lt;p&gt;Primeiro de tudo, isso te força a sempre retornar um Generator no seu callback. O que é até ok. Mas daí tu precisaria &lt;strong&gt;retornar Promise em todo canto&lt;/strong&gt; pra tirar proveito dessa biblioteca.&lt;/p&gt;
&lt;p&gt;O que também pode ser ok, a galera do JavaScript faz isso direto e não fica chateada com isso. Mas sem Type Generics é difícil forçar os tipos de retorno das Promises.&lt;/p&gt;
&lt;p&gt;Se você está ok com essa ideia, vá em frente. Tem todo um mundo a ser explorado! Dá uma olhada nos &lt;a href=&quot;https://amphp.org/packages&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;pacotes disponíveis no Framework Amp&lt;/a&gt; só pra ter certeza de que você não vá reinventar a roda.&lt;/p&gt;
&lt;h3&gt;Otimização de coleta de dados com Generators&lt;/h3&gt;
&lt;p&gt;A gente tá nessa era de web apis, o que é bem maneiro. Existem vários padrões a se seguir enquando provedor de API: SOAP, REST, GraphQL... O que acaba deixando pouco espaço para aplicações MVC tradicionais que estávamos acostumados a ver há alguns anos.&lt;/p&gt;
&lt;p&gt;Coisas como REST tendem a diminuir a árvore de dependências da request: nós especializamos um recurso por URL, que pode, por exemplo, ser pré computado e armazenado num repositório de dados mega rápido.&lt;/p&gt;
&lt;p&gt;Mas sempre que você pensar em múltiplos repositórios de dados para compor uma resposta, Generator pode ser uma incrível ferramenta para otimizar a utilização de recursos e tempos de resposta.&lt;/p&gt;
&lt;p&gt;Talvez não para apis REST, mas pensando em GraphQL é natural que o gerenciamento da coleta de dados é importante. A performance fala alto e nós temos as ferramentas pra fazer isso da forma correta.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=YYt9u4uUetU&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Nessa incrível apresentação do Bastian Hoffmann&lt;/a&gt; a gente consegue tomar alguma inspiração a partir do momento em que ele começa a falar sobre widgets. A ideia de ter um request handler para determinado tipo graphql que é composto de outros recursos mais granulares e ter essa árvore de dependências organizada pode trazer benefícios maravilhosos.&lt;/p&gt;
&lt;p&gt;Imagine a seguinte requisição GraphQL (sintaxe simplificada):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gql&quot;&gt;{
  person {
    name
  }
  team {
    people {
      name
      age
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;O array de &lt;code&gt;people&lt;/code&gt; pode conter o mesmo objeto &lt;code&gt;person&lt;/code&gt; entre seus elementos. Então por quê solicitar &lt;code&gt;person&lt;/code&gt; duas vezes? Isto poderia ser otimizado numa única chamada.&lt;/p&gt;
&lt;p&gt;Então por quê não algo parecido com o seguinte?&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;// PersonType.php
yield DataRequirement::craft(
  Person::class,
  [&apos;name&apos;],
  $whereClause
);

// PeopleType.php
yield DataRequirement::craft(
  Person::class,
  [&apos;name&apos;, &apos;age&apos;],
  $whereClause
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Parece um tanto estranho, né? E é mesmo, dado que engenheiros(as) php normalmente têm um ciclo de vida bem direto em suas aplicações.&lt;/p&gt;
&lt;p&gt;Apenas imagine o quão bacana seria se o handler chamando &lt;code&gt;PersonType.php&lt;/code&gt; fosse o mesmo chamando &lt;code&gt;PeopleType.php&lt;/code&gt; e ao dar yield nesses dois requisitos, um &lt;code&gt;Resolver&lt;/code&gt; entenderia que eles usam exatamente a mesma entidade e otimizaria a chamada REST/SOAP/MongoDB para solicitar somente os campos necessários apenas uma vez.&lt;/p&gt;
&lt;p&gt;Eu recentemente iniciei um POC em como desenvolver essa parada. Parece com o snippet a seguir (que tu também pode &lt;a href=&quot;https://github.com/nawarian/resolver/blob/master/tests/integration/FetchThePhpWebsiteSitemapsTest.php#L43-L68i&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;encontrar aqui&lt;/a&gt;).&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;public function fetchSitemaps(): Generator
{
  // Envolve o service para sempre retornar Promise.
  // Talvez pudesse ser feito com Annotations
  $sitemapProvider = wrap($this-&amp;gt;sitemapService);

  list($this-&amp;gt;en, $this-&amp;gt;br) = yield [
    $sitemapProvider-&amp;gt;getSitemap(&apos;en&apos;),
    $sitemapProvider-&amp;gt;getSitemap(&apos;br&apos;),
  ];

  // Aqui $this-&amp;gt;en e $this-&amp;gt;br são
  // populados com resultados do
  // getSitemap()
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;O quão mais eu desenvolvi essa POC, mais eu percebi que se parecia com o Amp framework. Então acho que esse seria &lt;a href=&quot;https://amphp.org/amp/coroutines/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;um bom ponto de partida.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Em geral, eu vejo grande potencial em Coroutines no PHP e adoraria ver este lado da linguagem ser melhor desenvolvido.&lt;/p&gt;
&lt;p&gt;Diz aí o que tu acha! Me dá um ping no Twitter e bora desenvolver essa ideia juntos 😉&lt;/p&gt;</content:encoded><category>php</category></item><item><title>Como o PHP funciona internamente</title><link>https://codamos.com.br/como-php-funciona/</link><guid isPermaLink="true">https://codamos.com.br/como-php-funciona/</guid><description>TL;DR A linguagem PHP traduz arquivos em tokens, cria uma Árvore Sintática Abstrata (Abstract Syntax Tree, AST) e transforma esta em Opcodes. Estes Opcodes podem ser postos no cache para ganho de perf</description><pubDate>Sat, 09 Nov 2019 10:32:00 GMT</pubDate><content:encoded>&lt;h2&gt;TL;DR&lt;/h2&gt;
&lt;p&gt;A linguagem PHP traduz arquivos em tokens, cria uma Árvore Sintática Abstrata (Abstract Syntax Tree, AST) e transforma esta em Opcodes. Estes Opcodes podem ser postos no cache para ganho de performance.&lt;/p&gt;
&lt;p&gt;Em servidores web, PHP normalmente é utilizado com PHP-FPM, que traz consigo uma capacidade incrível de escalabilidade. Além disso o PHP 7.4 trouxe a funcionalidade de pré carregamento dos Opcodes (preloading), que é capaz de traduzir os arquivos php em Opcodes no momento em que o serviço FPM está sendo levantado.&lt;/p&gt;
&lt;p&gt;Se você quiser uma explicação aprofundada sobre como a Zend VM se comporta, leia &lt;a href=&quot;/php-8-jit/&quot;&gt;este post sobre o JIT compiler do PHP 8&lt;/a&gt;. Este post mostra em detalhes como o PHP funciona internamente com e sem o Just In Time compiler.&lt;/p&gt;
&lt;h2&gt;Então... o que é PHP?&lt;/h2&gt;
&lt;p&gt;Eu fico muito feliz em ver como o desenvolvimento moderno com PHP requer cada vez menos conhecimento para construir produtos incríveis. &lt;strong&gt;Isso é muito massa!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Numa pesquisa rapidinha a gente encontra a informação de que PHP tornou-se público cerca de &lt;a href=&quot;https://groups.google.com/forum/#!msg/comp.infosystems.www.authoring.cgi/PyJ25gZ6z7A/M9FkTUVDfcwJ&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;26 anos atrás&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A forma como PHP começou é extremamente importante pra entender como e por quê ele se tornou tão popular. Também torna muito mais fácil entender a maior parte de suas características e decisões arquiteturais.&lt;/p&gt;
&lt;p&gt;PHP nasceu como uma template engine. Era uma série de programas CGI que permitia o desenvolvimento de páginas web como valores dinâmicos.&lt;/p&gt;
&lt;p&gt;Sim, a ideia era justamente misturar HTML e PHP. Só que em 1995 isso era revolucionário!&lt;/p&gt;
&lt;p&gt;Como linguagem de script, PHP executa seus códigos sequencialmente do início ao fim do arquivo e toda execução é 100% nova. Sem compartilhamento de memória ou contexto.&lt;/p&gt;
&lt;p&gt;Quando falamos de desenvolvimento web, isso pode mudar um pouco. Dado que o PHP pode rodar como CGI ou módulo no servidor http. Vamos dar uma olhada.&lt;/p&gt;
&lt;h3&gt;Como o PHP funciona com servidores HTTP?&lt;/h3&gt;
&lt;p&gt;Em geral, servidores HTTP têm uma responsabilidade bem clara: prover conteúdo de hipermídia usando o &lt;a href=&quot;https://tools.ietf.org/html/rfc2616#page-7&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Protocolo HTTP&lt;/a&gt;. Isto significa que &lt;strong&gt;servidores http recebem uma request, buscam um conteúdo do tipo string de algum lugar, e respondem com esta string&lt;/strong&gt; baseando-se no Protocolo HTTP.&lt;/p&gt;
&lt;p&gt;PHP veio para tornar este conteúdo de hipermídia dinâmico, permitindo que desenvolvedores possam prover mais que arquivos &lt;code&gt;.html&lt;/code&gt; simples e estáticos.&lt;/p&gt;
&lt;p&gt;Enquanto linguagem de script, num contexto de scripting, o PHP isola toda execução. Portanto não compartilha memória ou outros recursos entre execuções.&lt;/p&gt;
&lt;p&gt;Já enquanto no contexto web, temos duas formas diferentes de executar código PHP e cada uma possui seus prós e contras.&lt;/p&gt;
&lt;p&gt;É possível conectar o PHP a servidores http utilizando uma conexão do tipo CGI ou como um módulo. A maior diferença entre os dois modos é que &lt;strong&gt;módulos http compartilham recursos com o servidor HTTP&lt;/strong&gt; enquanto no modelo &lt;strong&gt;CGI, php faz uma execução nova a cada request&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Utilizar o PHP como módulo costumava ser bem popular, por sua comunicação com o servidor http ter menores barreiras. Ao passo que um script CGI dependeria, por exemplo, de comunicação em rede entre o servidor http e a execução do código.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Isso costumava ser o gargalo em set ups PHP. Hoje em dia, é justamente onde o PHP brilha!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Com o &lt;a href=&quot;https://www.php.net/manual/en/install.fpm.php&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;PHP-FPM&lt;/a&gt; um servidor como nginx ou Apache podem facilmente executar código php como se fosse um script CLI. Onde cada request é 100% isolada das outras.&lt;/p&gt;
&lt;p&gt;Isto também significa que o servidor HTTP pode escalar independentemente do executor de códigos PHP. Com as nossas tecnologias atuais, isso &lt;strong&gt;é incrível para nos permitir escalar verticalmente&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Utilizar o PHP com CGI lhe permite atualizar sua aplicação rapidamente sem precisar reiniciar o servidor HTTP a cada deployment. Com a moda de utilizar load balancers isso não é tão crítico, mas vale mencionar.&lt;/p&gt;
&lt;p&gt;Outro grande benefício de utilizar PHP-FPM é que sempre que um script php quebrar, apenas aquela request está comprometida. O restante da aplicação pode continuar executando normalmente, já que os recursos não são compartilhados.&lt;/p&gt;
&lt;p&gt;Então se a gente ignorar a utilização do PHP como módulo, a forma como ele funciona na web é basicamente: &lt;strong&gt;HTTP Server ⇨ PHP-FPM (Server) ⇨ PHP&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;E é por isso que nós dizemos normalmente que o PHP é extremamente escalável por natureza.&lt;/p&gt;
&lt;p&gt;Mas o PHP ainda é uma linguagem de script. E como no contexto CGI ele possui uma execução isolada a cada request, isso também significa que a sua característica mais escalável também é um dos seus mais relevantes gargalos de performance.&lt;/p&gt;
&lt;h3&gt;Como o scripting com PHP funciona?&lt;/h3&gt;
&lt;p&gt;A linguagem PHP é escrita em C e a forma como funciona é na real bem massa.&lt;/p&gt;
&lt;p&gt;O interpretador php lê arquivos contendo código php, analiza sua sintaxe, transforma tudo que entende como código php em opcodes e mais tarde executa esta lista de opcodes.&lt;/p&gt;
&lt;p&gt;Em termos simplificados, o php: &lt;strong&gt;interpreta, compila e executa&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Toda as vezes novamente (a gente volta nesse ponto já já).&lt;/p&gt;
&lt;p&gt;Então a cada vez que você tenta executar um script php, você encontrará diferentes coisas em diferentes momentos:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Erros sintáticos e verificações de linguagem acontecem durante a fase de interpretação e compilação. Erros lógicos (como exceções) ocorrem apenas durante a fase de execução.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A forma como o PHP faz isso é através de uma &lt;a href=&quot;https://wiki.php.net/rfc/abstract_syntax_tree&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Árvore Sintática Abstrata (Abstract Syntatic Tree - AST)&lt;/a&gt; para entender o que as coisas dentro do arquivo php significam.&lt;/p&gt;
&lt;p&gt;Esta árvore sintática mapeia estruturas de linguagem em instruções de compilação, que quando compiladas se transformam em opcodes da Zend VM. Tais opcodes então podem ser &lt;a href=&quot;https://github.com/php/php-src/blob/master/Zend/zend_vm_def.h&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;interpretados pela Zend VM&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Então se você parar pra pensar, &lt;strong&gt;a parte mais relevante na execução do código PHP ocorre quando a Zend VM executa opcodes&lt;/strong&gt;. Isto é o que realmente produz o resultado que esperamos.&lt;/p&gt;
&lt;p&gt;Ao fim do dia, &lt;strong&gt;ter uma execução isolada a cada request não parece tão inteligente se precisarmos compilar a sintaxe php em opcode a cada nova request&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Por isso o &lt;a href=&quot;https://www.php.net/manual/en/intro.opcache.php&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;OPcache&lt;/a&gt; existe. Não existem soluções sem problemas.&lt;/p&gt;
&lt;p&gt;Com OPcache o PHP pode tomar vantagem de um espaço de memória compartilhado: ler/gravar scripts já interpretados e otimizar execuções futuras.&lt;/p&gt;
&lt;p&gt;Na primeira vez que uma request toca &lt;code&gt;index.php&lt;/code&gt;, por exemplo, o php interpreta, compila e executa. Da segunda vez que a request toca &lt;code&gt;index.php&lt;/code&gt;, o php simplesmente busca o compilado do OPcache e o executa.&lt;/p&gt;
&lt;p&gt;Isto está para mudar, porém. Desde o PHP 7.4 um &lt;a href=&quot;https://wiki.php.net/rfc/preload&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;preloader de opcache foi adicionado ao PHP&lt;/a&gt;. Esta funcionalidade permite uma série de arquivos php serem pré-carregados ao subir o servidor. Desta forma, da primeira vez que uma request tocar &lt;code&gt;index.php&lt;/code&gt;, o php irá buscar o compilado diretamente no opcache. &lt;strong&gt;Sem precisar interpretar o arquivo durante a request&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;E pra quê tu tá me dizendo tudo isso?&lt;/h3&gt;
&lt;p&gt;Eu sinto que engenheiros(as) PHP (assim como python) normalmente possuem grande conhecimento sobre como os componentes se conectam no back-end, dado que nossas linguagens normalmente não provém muita mágica ou software caixa preta de terceiros.&lt;/p&gt;
&lt;p&gt;Eu também sinto que isto vem mudando com o tempo, dado que o software Open Source se mostrou mais que somente um Hype, mas um ótimo modelo econômico. Mais linguagens precisam que seus(uas) engenheiros(as) entendam como as coisas se encaixam e estão se tornando cada vez mais vendor agnostic.&lt;/p&gt;
&lt;p&gt;Mas ainda não estamos lá, e dominar o ecossistema PHP é necessário para investir esforços em performance e segurança corretamente. Saber quando e onde as coisas acontecem irá lhe dar suporte em otimizar como elas devem acontecer.&lt;/p&gt;
&lt;p&gt;Eu espero que este texto tenha lhe ajudado a entender melhor como a engine PHP funciona por baixo dos panos, o ferramentário que utiliza e palavras chave importantes que você provavelmente irá encarar em algum momento.&lt;/p&gt;
&lt;p&gt;Se você tiver alguma pergunta que eu não tenha respondido aqui ou crê que cometi algum erro neste texto, sinta-se livre para entrar em contato e, se eu entender que se encaixa aqui, vou manter este post atualizado para que possamos aprender juntos.&lt;/p&gt;</content:encoded><category>php</category></item><item><title>Desenvolvimento Guiado a Testes no PHP com exemplos</title><link>https://codamos.com.br/tdd-php-exemplos/</link><guid isPermaLink="true">https://codamos.com.br/tdd-php-exemplos/</guid><description>TDD têm várias técnicas a serem utilizadas, este post apresenta algumas delas. Se você está procurando se aprofundar mais no assunto, tem um livro bom pra ti: &quot;Test Driven Development: By Example&quot; , p</description><pubDate>Sun, 03 Nov 2019 02:10:00 GMT</pubDate><content:encoded>&lt;p&gt;TDD têm várias técnicas a serem utilizadas, este post apresenta algumas delas. Se você está procurando se aprofundar mais no assunto, tem um livro bom pra ti: &lt;strong&gt;&lt;em&gt;&quot;Test Driven Development: By Example&quot;&lt;/em&gt;, por Kent Beck&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Todo código escrito aqui está disponível no &lt;a href=&quot;https://github.com/nawarian/The-PHP-Website/tree/master/code/1-real-life-tdd-with-php/archive-org-client&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;repositório do github thephp.website&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Modo enrolação: desligado&lt;/strong&gt; (bora codar!)&lt;/p&gt;
&lt;p&gt;Test Driven Development não é sobre escrever testes unitários, mas sim sobre &lt;strong&gt;escrever teste primeiro&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Testes não são a coisa mais importante, &lt;strong&gt;a gente escreve eles pra ter um ciclo constante de feedback&lt;/strong&gt; durante o desenvolvimento.&lt;/p&gt;
&lt;p&gt;Com isso em mente, o nosso ciclo de desenvolvimento é o seguinte:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;#1-escreva-um-teste-superficial&quot;&gt;Escreva um teste superficial, rode e veja-o falhar&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#2-faca-este-teste-passar-da-forma-mais-burra-possivel&quot;&gt;Faça este teste passar da forma mais burra possível&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#3-refatore-ate-que-nao-pareca-tao-burra&quot;&gt;Refatore a implementação até que não pareça mais tão burra assim&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Antes do &quot;como&quot;, vem o &quot;porquê&quot;&lt;/h2&gt;
&lt;p&gt;Existem algumas ótimas razões pra escrever testes primeiro. Vamos alinhar em algumas pra que tu possa ter uma ideia de por quê manter essa prática.&lt;/p&gt;
&lt;p&gt;Escrever testes primeiro: * te força a saber o que você quer alcançar antes de começar a escrever código * te mantém focado(a) em seu objetivo * te provê uma estrutura com ciclo de feedback constante: alterar, salvar, verificar&lt;/p&gt;
&lt;h2&gt;Construindo um adapter para buscar metadados no Archive.org com TDD&lt;/h2&gt;
&lt;p&gt;Como um exemplo razoável, vamos construir um client que busca metadados sobre itens disponíveis no site Archive.org.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;O que sabemos:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Archive.org nos permite fazer o upload de arquivos e os chama de &quot;Item&quot;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://archive.org/details/nawarian-test&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Aqui há um exemplo de item identificado por &quot;nawarian-test&quot;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Um item contém múltiplos arquivos, representando o arquivo em várias formas e seus metadados&lt;/li&gt;
&lt;li&gt;Todo item contém metadados como data de criação, nome, arquivos...&lt;/li&gt;
&lt;li&gt;Archive.org provê uma API para buscar metadados usando o seguinte URL: &lt;code&gt;https://archive.org/metadata/&amp;lt;nome-do-item&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;O que a gente quer:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Uma classe para buscar os metadados de um item no Archive.org e que nos retorne uma entidade chamada &lt;code&gt;Nawarian\ArchiveOrg\Item\Metadata&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Vamos construir um setup básico pra escrever nosso teste que garanta o que a gente quer!&lt;/p&gt;
&lt;h2&gt;Configuração do ambiente de teste&lt;/h2&gt;
&lt;p&gt;Rapidex: vamos criar uma pasta para o nosso projeto, instalar os pacotes necessários e botar os testes pra rodar. O meu setup normalmente vem com PHPUnit e Mockery:&lt;/p&gt;
&lt;pre&gt;$ mkdir archive-org-client/ &amp;amp;&amp;amp; cd archive-org-client&lt;br&gt;$ composer require phpunit/phpunit mockery/mockery&lt;br&gt;$ ./vendor/bin/phpunit --generate-configuration&lt;code class=&quot;language-shell&quot;&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ao gerar as configurações do phpunit, a ferramenta vai lhe perguntar sobre diretório de testes e outras coisas. Vamos pegar as opções padrão pra tudo aqui (só aperta &quot;enter&quot;).&lt;/p&gt;
&lt;p&gt;A configuração padrão diz que os nossos testes ficam dentro da pasta &lt;code&gt;tests&lt;/code&gt;, e o nosso código fica dentro da pasta &lt;code&gt;src&lt;/code&gt;. Vamos criá-las:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ mkdir tests src
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A gente também precisa configurar o &lt;strong&gt;autoloader&lt;/strong&gt; do composer. Vamos atualizar o arquivo &lt;code&gt;composer.json&lt;/code&gt;, vai ficar assim:&lt;/p&gt;
&lt;p&gt;Arquivo: &lt;strong&gt;composer.json&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
    &quot;require&quot;: {
        &quot;phpunit/phpunit&quot;: &quot;^8.4&quot;,
        &quot;mockery/mockery&quot;: &quot;^1.2&quot;
    },
    &quot;autoload&quot;: {
        &quot;psr-4&quot;: {
            &quot;Nawarian\\ArchiveOrg\\&quot;: &quot;src/&quot;
        }
    },
    &quot;autoload-dev&quot;: {
        &quot;psr-4&quot;: {
            &quot;Nawarian\\ArchiveOrg\\Test\\&quot;: &quot;tests/&quot;
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Atualizado o &lt;code&gt;composer.json&lt;/code&gt;, vamos gerar o autoloader novamente:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ composer dump-autoload
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Agora a gente pode criar a nossa classe de testes e começar a brincadeira!&lt;/p&gt;
&lt;p&gt;Arquivo: &lt;strong&gt;tests/ClientTest.php&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

namespace Nawarian\ArchiveOrg\Test;

use PHPUnit\Framework\TestCase;

class ClientTest extends TestCase
{
    public function testMyTest(): void
    {
        $this-&amp;gt;assertTrue(true);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;E podemos rodar o phpunit normalmente:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ ./vendor/bin/phpunit -c phpunit.xml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Muintcho beeim! Com o teste configurado e rodando, vamos começar com o TDD.&lt;/p&gt;
&lt;h3 id=&quot;1-escreva-um-teste-superficial&quot;&gt;1. Escreva um teste superficial, rode e veja-o falhar&lt;/h3&gt;
&lt;p&gt;Novamente, nosso objetivo é: uma classe para buscar os metadados de um item no Archive.org e que nos retorne uma entidade chamada &lt;code&gt;Nawarian\ArchiveOrg\Item\Metadata&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Nosso teste vai então se parecer com o seguinte:&lt;/p&gt;
&lt;p&gt;Arquivo: &lt;strong&gt;tests/ClientTest.php&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

namespace Nawarian\ArchiveOrg\Test;

use PHPUnit\Framework\TestCase;

class ClientTest extends TestCase
{
    public function testClientFetchesMetadata(): void
    {
        $client = new \Nawarian\ArchiveOrg\Client();

        $metadata = $client-&amp;gt;fetchMetadata(&apos;nawarian-test&apos;);

        $this-&amp;gt;assertSame(&apos;nawarian-test&apos;, $metadata-&amp;gt;identifier());
        $this-&amp;gt;assertSame(&apos;2019-02-19 20:00:38&apos;, $metadata-&amp;gt;publicDate());
        $this-&amp;gt;assertSame(&apos;opensource&apos;, $metadata-&amp;gt;collection());
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pronto! A gente precisa de um &lt;code&gt;Client&lt;/code&gt; que contém um método &lt;code&gt;fetchMetadata()&lt;/code&gt;, que receba uma string &lt;code&gt;identifier&lt;/code&gt; (nawarian-test neste caso).&lt;/p&gt;
&lt;p&gt;A gente também quer que o retorno seja um objeto com os métodos &lt;code&gt;identifier()&lt;/code&gt;, &lt;code&gt;publicDate()&lt;/code&gt; e &lt;code&gt;collection()&lt;/code&gt;, retornando cada um os valores disponíveis na API.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Salve o arquivo, rode o phpunit e veja o teste falhar.&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;2-faca-este-teste-passar-da-forma-mais-burra-possivel&quot;&gt;2. Faça este teste passar da forma mais burra possível&lt;/h3&gt;
&lt;p&gt;O primeiro erro que vemos diz que a classe Client não foi encontrada: &lt;code&gt;Class &apos;Nawarian\ArchiveOrg\Client&apos; not found&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Corrigir este é bem simples, criamos uma classe com o mesmo FQN. Dentro da pasta &lt;code&gt;src/&lt;/code&gt;, claro.&lt;/p&gt;
&lt;p&gt;Arquivo: &lt;strong&gt;src/Client.php&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

namespace Nawarian\ArchiveOrg;

class Client
{
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Salve, rode o phpunit. O próximo erro diz &lt;code&gt;Call to undefined method Nawarian\ArchiveOrg\Client::fetchMetadata()&lt;/code&gt;. Ainda mais fácil, basta escrever o método na classe &lt;code&gt;Client&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;public function fetchMetadata(string $identifier): object
{
    return new \stdClass();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Salve, rode o phpunit. O próximo erro diz &lt;code&gt;Call to undefined method stdClass::identifier()&lt;/code&gt;. Vamos então usar uma classe anônima pra acabar com esses erros e seguir em frente!&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;public function fetchMetadata(string $identifier): object
{
    return new class {
        public function identifier(): string
        {
            return &apos;&apos;;
        }

        public function publicDate(): string
        {
            return &apos;&apos;;
        }

        public function collection(): string
        {
            return &apos;&apos;;
        }
    };
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;O que falta agora é fazer o teste passar &lt;strong&gt;da forma mais burra possível&lt;/strong&gt;. Eu consigo somente pensar em retornar direto os valores que passa no teste:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;public function fetchMetadata(string $identifier): object
{
    return new class {
        public function identifier(): string
        {
            return &apos;nawarian-test&apos;;
        }

        public function publicDate(): string
        {
            return &apos;2019-02-19 20:00:38&apos;;
        }

        public function collection(): string
        {
            return &apos;opensource&apos;;
        }
    };
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Massa! Os testes passaram! É hora de fazer uma implementação de verdade, pra poder buscar os metadados da API em si. &lt;strong&gt;A partir deste momento a gente inicia o ciclo constante de feedback durante o desenvolvimento.&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;3-refatore-ate-que-nao-pareca-tao-burra&quot;&gt;3. Refatore a implementação até que não pareça mais tão burra assim&lt;/h3&gt;
&lt;p&gt;O termo &lt;strong&gt;até que&lt;/strong&gt; é extremamente importante aqui. Nós estamos no último passo, mas também o passo que mais se repete.&lt;/p&gt;
&lt;p&gt;Isto significa que nós vamos continuar retornando a este passo até que estejamos contentes com a implementação.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3.1 Introduzindo a classe &lt;code&gt;Item\Metadata&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A primeira coisa que eu sinto ser necessária é escrever a entidade &lt;code&gt;Metadata&lt;/code&gt;, desta forma a gente pode remover a classe anônima. Vamos lá:&lt;/p&gt;
&lt;p&gt;Arquivo: &lt;strong&gt;src/Item/Metadata.php&lt;/strong&gt; (métodos copiados da classe anônima em Client)&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

namespace Nawarian\ArchiveOrg\Item;

class Metadata
{
    public function identifier(): string
    {
        return &apos;nawarian-test&apos;;
    }

    public function publicDate(): string
    {
        return &apos;2019-02-19 20:00:38&apos;;
    }

    public function collection(): string
    {
        return &apos;opensource&apos;;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Vamos atualizar a implementação em &lt;code&gt;Client::fetchMetadata()&lt;/code&gt;. Observe como o retorno do método mudou para &lt;code&gt;Metadata&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Arquivo: &lt;strong&gt;src/Client.php&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;// ...

use Nawarian\ArchiveOrg\Item\Metadata;

// class Client...

public function fetchMetadata(string $identifier): Metadata
{
    return new Metadata();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Salve, rode o phpunit. Os testes ainda estão passando. Estamos indo bem!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3.2 Receber os dados no construtor da entidade &lt;code&gt;Metadata&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Em vez de escrever os resultados direto no arquivo da classe &lt;code&gt;Metadata&lt;/code&gt;, vamos delegar a responsabilidade de montar os dados para a classe &lt;code&gt;Client&lt;/code&gt; e recebê-los no construtor de &lt;code&gt;Metadata&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Arquivo: &lt;strong&gt;src/Item/Metadata.php&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;class Metadata
{
    private $identifier;

    private $publicDate;

    private $collection;

    public function __construct(string $identifier, string $publicDate, string $collection)
    {
        $this-&amp;gt;identifier = $identifier;
        $this-&amp;gt;publicDate = $publicDate;
        $this-&amp;gt;collection = $collection;
    }

    public function identifier(): string
    {
        return $this-&amp;gt;identifier;
    }

    public function publicDate(): string
    {
        return $this-&amp;gt;publicDate;
    }

    public function collection(): string
    {
        return $this-&amp;gt;collection;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;E agora vamos delegar a responsabilidade de montar os dados para a classe &lt;code&gt;Client&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Arquivo: &lt;strong&gt;src/Client.php&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;public function fetchMetadata(string $identifier): Metadata
{
    return new Metadata(&apos;nawarian-test&apos;, &apos;2019-02-19 20:00:38&apos;, &apos;opensource&apos;);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Salve, rode o phpunit. Ainda está verde. Continuemos.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3.3 Chamando a API para buscar dados de verdade&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Client&lt;/code&gt; ainda está produzindo dados falsos, o que não é bem útil. Vamos usar a API do archive.org pra buscar os dados que precisamos.&lt;/p&gt;
&lt;p&gt;Lembrando que o endpoint é &lt;code&gt;https://archive.org/metadata/&amp;lt;identificador&amp;gt;&lt;/code&gt;. Então invocar o método &lt;code&gt;Client::fetchMetadata()&lt;/code&gt; passando &lt;code&gt;nawarian-test&lt;/code&gt; como identificador (os teste que escrevemos já faz isso), nós deveríamos chamar &lt;code&gt;https://archive.org/metadata/nawarian-test&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Eu vou implementar isto rapidinho usando &lt;code&gt;file_get_contents()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Arquivo: &lt;strong&gt;src/Client.php&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;public function fetchMetadata(string $identifier): object
{
    $jsonData = file_get_contents(&quot;https://archive.org/metadata/{$identifier}&quot;);
    $decoded = json_decode($jsonData, true);
    $metadata = $decoded[&apos;metadata&apos;];

    return new Metadata(
        $metadata[&apos;identifier&apos;],
        $metadata[&apos;publicdate&apos;],
        $metadata[&apos;collection&apos;]
    );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Salve, rode o phpunit. Testes estão passando e... nós atingimos nosso objetivo!&lt;/p&gt;
&lt;h2&gt;Continue refatorando ou pare por aqui&lt;/h2&gt;
&lt;p&gt;A ideia do ciclo de feedback descrito no passo 3.3 é implementar nosso código com base num objetivo bem definido.&lt;/p&gt;
&lt;p&gt;Você encontrá vários momentos de &quot;aaah&quot;, e vai querer implementar da melhor forma possível desde o incício. &lt;strong&gt;Não caia nessa armadilha!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Quanto maior o tempo você passa sem feedback (sem ver os resultados dos testes), maiores são as chances de quebrar o seu código sem entender onde ocorreu o problema.&lt;/p&gt;
&lt;p&gt;Sempre que você encontrar algo que sinta ser muito importante, anote e continue indo em frente! Bote esta anotação como a próxima coisa a resolver no seu ciclo, mas não interrompa a iteração atual.&lt;/p&gt;
&lt;p&gt;Eu posso exemplificar algumas coisas que eu gostaria de ter feito nessa implementação:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;usar um client http compatível com a PSR-18 e remover a chamada à função &lt;code&gt;file_get_contents()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;quebrar este teste em unitário e de integração&lt;/li&gt;
&lt;li&gt;um mecanismo de hydration melhor para a classe &lt;code&gt;Metadata&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Também importante notar que nós não testamos nenhum caso de exceção. Estes testes devem ser criados também! Como deveria a nossa classe se comportar quando &lt;code&gt;identificador&lt;/code&gt; não existe no archive.org?&lt;/p&gt;
&lt;p&gt;Quanto mais você escreve código, mais você irá querer escrever código. Seu trabalho aqui é entender quando parar e iniciar o próximo tópico.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nunca se esqueça de manter o ciclo de feedback em andamento: &lt;a href=&quot;/livro-refactoring-martin-fowler/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;refatore&lt;/a&gt;, salve, rode o phpunit.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;É isso. Não tem mais motivo pra esperar pra implementar TDD.&lt;/p&gt;
&lt;p&gt;Bora codar, leia o livro do Kent Beck e sinta-se convidado(a) a me dar um toque pra discutir ou perguntar coisas.&lt;/p&gt;</content:encoded><category>php</category></item></channel></rss>